高精度正整数除法 大整数除法

高精度正整数除法 大整数除法

标签(空格分隔): 算法竞赛 算法 编程错题 高精度


单词:
    divident:被除数
    divisor:除数
    quotient:商

大整数除法 OpenJ_Bailian - 2737

    题目要求:求两个大的正整数相除的商。

    input:第1行是被除数,第2行是除数。每个数均不超过100位。

    output:一行,相应的商的整数部分

    Sample Input:
    2376
    24

    Sample Output:
    99

算法是这样的,我们以减法代替除法,计算能够减多少次。既然这样,第一个思路就是模拟减法了。但是做的时候发现,模拟减法慢的出奇,需要调用数组很多次,七位数除以一位数时时间就到1秒了。所以必须换思路。
第二种思路的时间复杂度是小的多的,但是思考起来很难,实现起来更加的难。
除法的模拟法是这样的:

  1. 计算被除数与除数相差的位数t
  2. 计算dividend-divisor*10^t
  3. 重复计算2,直到结果小于0时,记录计算次数j,j*10^t作为商的一部分,计算j=j+j*10^t(初始j为0)。将t-1,继续计算2
  4. 不断重复上述过程,每次的j[k++]循环相加,直到t=0,此时的j即为商。

实现起来很麻烦的。代码如下

#include <stdio.h>
#include <string.h>
#define N 101
int dd[N],ds[N],qu[N];
char str1[N],str2[N];

int sub(int* dd,int* ds,int len1,int len2)  //这个函数是重点难点 
{
    int i;
    if (len1<len2)  return -1;
    else if (len1==len2)
        for (i=len1-1;i>=0;i--)
        {
            if (dd[i]<ds[i])
                    return -1;
            else if (dd[i]>ds[i])
                break;
        }
    for (i=0;i<len1;i++)
    {
        dd[i]-=ds[i];
        if (dd[i]<0)
        {
            dd[i]+=10;
            dd[i+1]--;
        }
    }
    for (i=len1-1;i>=0;i--)
        if (dd[i])  break;
    return i+1;
}

int main()
{
    int i,j,k;
    gets(str1);
    gets(str2);
    int len1=strlen(str1),len2=strlen(str2);
    for (k=0,i=len1-1;i>=0;i--)
        dd[k++]=str1[i]-'0';
    for (k=0,i=len2-1;i>=0;i--)
        ds[k++]=str2[i]-'0';
    len1=sub(dd,ds,len1,len2);
    if (len1==-1)
    {
        printf("0\n");
        return 0;
    }
    else if (len1==0)
    {
        printf("1\n");
        return 0;
    }
    qu[0]=1;
    int times=len1-len2;
    for (i=len1-1;i>=0;i--)             //从这一行到72行是重点难点! 
    {
        if (i>=times)
            ds[i]=ds[i-times];
        else
            ds[i]=0;
    }
    len2=len1;
    for (j=0;j<=times;j++)
    {
        int tmp;
        while ((tmp=sub(dd,ds+j,len1,len2-j))>=0)
        {
            len1=tmp;
            qu[times-j]++;
        }
    }
    for (i=0;i<N;i++)
    {
        if (qu[i]>9)
        {
            qu[i+1]+=qu[i]/10; 
            qu[i]%=10;
        }       
    }
    for (i=N-1;qu[i]==0&&i>=0;i--);
    while (i>=0)
        printf("%d",qu[i--]);
    printf("\n");
    return 0;
}

先定义了sub函数,判断输入的高精度被除数和除数的大小关系,被除数小与除数,则返回-1,否则,计算被除数减除数,将结果赋给被除数,再计算被除数此时的位数,返回位数。
对于main函数,先是老套路,用字符串数组保存输入的高精度数,计算位数,之后用整型数组逆序存放每一位,之后执行一次sub,判断、排除被除数小于等于除数的情况。
由于已进行了一次减法,所以商(同样按位数逆序存储)要先+1。
之后line56~line72,就是重点和难点了。
先是line56~line62,是在模拟乘10的幂次运算。由于数据保存在数组中,所以直接向后移位即可。注意他的移位方法,这是最省时间的移位方法,比我原先的移位方法快的多
然后是更难的line63~line72。这一部分是同时在做减法和累加商。循环的计数器j,还是模拟10的幂次相乘的控制器和对商加和的控制器,ds+j控制除数数组的位数,也就相当于控制了乘10的次数;len-j控制了除数数组的长度,和ds-j结合起来,被sub()调用,就控制了算法中的2。之后,首先定义了tmp中间变量,判断每次运算之后被除数是否还大于等于除数,如果小于,就结束循环。每次计算后,将tmp赋值给len1,实现循环调用,并且将对应的商的位数(由高位加到低位,符合我们设置的规律)+1。这里尤其要注意思考,qu[times-j]++,这一步是如何通过循环来计算商的。
剩下的代码还是老套路,就不解释了。

  • 4
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 精度除法的实现方法有很多,下面是一种使用数组实现的示例代码: ``` #include <iostream> using namespace std; const int N = 1005; int a[N], b[N], c[N]; void div(int *a, int *b, int *c, int &lenc) { int len_a = a[0], len_b = b[0]; for (int i = 1; i <= len_a; i++) c[i] = a[i]; c[0] = len_a - len_b + 1; for (int i = c[0]; i >= 1; i--) { c[i] = 0; while (c[i] * (b[1] * 10 + b[2]) <= (c[i + 1] * 10 + c[i + 2])) { c[i]++; } for (int j = 1; j <= len_b; j++) { c[i + j - 1] -= c[i] * b[j]; } for (int j = i + len_b - 1; j >= i; j--) { if (c[j] < 0) { c[j] += 10; c[j - 1]--; } } } while (c[0] > 1 && !c[c[0]]) c[0]--; lenc = c[0]; } int main() { int len_a, len_b, len_c; cin >> len_a; for (int i = 1; i <= len_a; i++) cin >> a[i]; cin >> len_b; for (int i = 1; i <= len_b; i++) cin >> b[i]; div(a, b, c, len_c); for (int i = len_c; i >= 1; i--) cout << c[i]; return 0; } ``` 这里用数组模拟精度除法的过程,需要注意的是,除数和被除数需要从位到低位存储,且需要判断余数是否为0。 希望这个示例代码能帮到你。 ### 回答2: 要用C++编写一个精度除法的项目,不使用vector,可以使用字符串和数组来处理精度数的运算。以下是一个简单的实现示例: 首先,我们需要实现一个函数将字符串转换为数组,并且反转数组的顺序: ```cpp void strToArr(string num, int* arr) { int len = num.length(); for (int i = 0; i < len; i++) { arr[i] = num[len-i-1] - '0'; } } ``` 接下来,我们可以实现一个除法函数: ```cpp string divide(string dividend, string divisor, int precision) { int a[precision+1] = {0}; // 定义一个数组用于保存结果 int dividendArr[dividend.length()]; int divisorArr[divisor.length()]; strToArr(dividend, dividendArr); strToArr(divisor, divisorArr); int dividendLen = dividend.length(); int divisorLen = divisor.length(); int remainder = 0; // 余数 int idx = 0; // 商数数组的下标 for (int i = dividendLen-1; i >= 0; i--) { int curr = dividendArr[i] + remainder * 10; a[idx++] = curr / divisorArr[0]; // 取商 remainder = curr % divisorArr[0]; // 更新余数 // 长除法 for (int j = divisorLen-1; j >= 0; j--) { curr = curr % 10; // 当前的除数 curr = curr * 10 + dividendArr[i-j-1]; // 添加下一位被除数 if (curr / divisorArr[j] >= 1) { // 如果可以整除 curr %= divisorArr[j]; a[idx-1] += 1; // 对应位的商数加1 } } } string result = ""; bool leadingZero = true; // 将除法结果转为字符串 for (int i = precision-1; i >= 0; i--) { if (leadingZero && a[i] == 0) continue; leadingZero = false; result += to_string(a[i]); } return result; } ``` 这是一个简单的精度除法函数的实现,可以通过传入被除数、除数和所需的精度来得到除法结果。 注意,这个实现示例仅适用于除数和被除数都是整数的情况,且结果仅包含整数部分(不包含小数部分)。对于更复杂的情况(例如带有小数的除法),需要额外的处理。 ### 回答3: 要实现精度除法的功能,可以使用C++语言编写一个项目。以下是示例代码: ```cpp #include <iostream> #include <cstring> using namespace std; const int MAXN = 1000; //定义最大位数 int a[MAXN], b[MAXN], c[MAXN]; void divide(int a[], int b[], int c[]) { int len_a = strlen(a); int len_b = strlen(b); memset(c,0,sizeof(c)); //初始化结果数组c int j=0, tmp; for (int i = 0; i < len_a; i++) { tmp = j * 10 + a[i] - '0'; //当前余数乘以10加上下一位被除数 j = tmp % b; c[i] = tmp / b; } } int main() { char str_a[MAXN]; char str_b[MAXN]; cin >> str_a >> str_b; for (int i = 0; i < strlen(str_a); i++) a[i] = str_a[i] - '0'; for (int i = 0; i < strlen(str_b); i++) b[i] = str_b[i] - '0'; divide(a, b, c); //输出结果 bool left_zero = true; for (int i = MAXN - 1; i >= 0; i--) { if (left_zero && c[i] == 0) continue; else left_zero = false; cout << c[i]; } return 0; } ``` 这是一个简单的精度除法实现。我们首先将两个被除数和除数的字符串形式转换成整数数组,然后通过除法计算生成商的整数数组。最后,我们遍历商的数组,从最位开始输出结果。 这个示例项目没有使用`vector`,而是使用了定长的整数数组进行运算。你可以根据自己的需求和对C++语言的熟悉程度进行相应的修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值