大整数除法

基本思想:
反复做减法,看看从被除数里最多能减去多少个除 数,商就是多少。
一个一个减显然太慢,如何减得更快一些呢?以 7546除以23为例来看一下:开始商为0。先减去23的100倍,就是2300,发现够减3次,余下646。于是商的值就增加300。然后用646减去230,发现够减2 次,余下186,于是商的值增加20。最后用186减去23,够减8次,因此最终商就是328。
所以本题的核心是要写一个大整数的减法函数,然后反复调用该函数进行减法操作

 

算法逻辑:
int main()
{
    读入输入数据组数;
    while(输入未结束)
    {
    读入一组输入到szLine1/2 ,初始化减数an1、被减数数组an2;将szLine1/2中存储的字符串形式的整数转换 到 an1/2中去;
    初始化结果数组anResult;
    (1) 计算商的最高位位数, 用nShiftLen保存;
    (2)while (余数>减数)
       {
         (3) 算出an1的10的nShiftLen次方倍;
         (4) 重复减去an1的10的nShiftLen次方倍,看能减几次;
         (5) 记录结果最高位的位置;
         商的最高位位数nShiftLen减一;
       }
       输出结果;
    }
}

 

问题:

(1)计算商的最高位位数, 用nShiftLen保存
nShiftLen = Length(MAX_LEN,an1) - Length(MAX_LEN,an2);定义函数Length求大整数的位数(从高位起找到第一个不为0 的位)。0 算0 位
int Length( int nMaxLen,int * an)
(2)余数>减数
Max(MAX_LEN,an1,an2) == an1
定义函数Max求大整数an1和an2里面大的那个,如果都是0, 则返回NULL(从高位起,若相等则依次比较,若不相等则返回)
int * Max(int nMaxLen, int * an1, int * an2)

(3)算出an1的10的nShiftLen次方倍
ShiftLeft(MAX_LEN, an2, tmpAn2,nShiftLen);
定义函数ShiftLeft将大整数an1左移n位,即乘以10的n次方,结果放到an2里(从高位起依次将i-n放入结果的i位,注意判断i - n 是否>=0)
void ShiftLeft( int nMaxLen, int * an1, int * an2, int n)

(4)重复减去an1的10的nShiftLen次方倍,看能减几次
while( Max(MAX_LEN,an1,tmpAn2) == an1)

 {
   Substract(MAX_LEN, an1,tmpAn2);
   anResult[nShiftLen] ++;
}
定义减法函数Substract,参照前面大整数减法

(5)记录结果最高位的位置
if( nHighestPos == 0 && anResult[nShiftLen])
nHighestPos = nShiftLen;

#include <iostream>
#include <cstring>
#define MAX 100
using namespace std;
//求两个整数中的较大值
int Max(int x, int y)
{
    return (x > y) ? x : y;
}
//两个大整数相减
int Substract(int nMaxLen, int *a1, int *a2)
{
    int nStartPos = 0;
    for(int i = 0; i < nMaxLen; ++i)
    {
        a1[i] -= a2[i];
        if(a1[i] < 0)
        {
            a1[i + 1] --;
            a1[i] += 10;
        }
        if(a1[i])
        {
            nStartPos = i;
        }
    }
    return nStartPos;
}
//求大整数的长度,若为0位则返回0
int nLen(int nMaxLen, int *a)
{
    for(int i = nMaxLen - 1; 0 <= i; --i)
    if(a[i])
    return i + 1;

    return 0;
}
//求两个大整数中较大的那一个,如果都是0则返回NULL
int *MaxNum(int nMaxLen, int *a1, int *a2)
{
    bool bBothZero = true;
    for(int i = nMaxLen; 0 <= i; --i)
    {
        if(a1[i] > a2[i])
        return a1;
        else if(a2[i] > a1[i])
        return a2;
        else if(a1[i])
        bBothZero = false;

    }
    if(bBothZero)
    return NULL;

    return a1;
}
//将大整数a左移n位,即乘以10的n次方,结果放在b中
void ShiftLeft(int nMaxLen, int *a, int *b, int n)
{
    //将a复制到b
    memcpy(b, a, nMaxLen * sizeof(int));
    if(n <= 0)
    return;
   for(int i = nMaxLen - 1; 0 <= i; --i)
   {
       if(i >= n)
       b[i] = a[i - n];
       else
       b[i] = 0;
   }
}

int main()
{
    int n;
    cin >> n;
    while(n--)
    {
        char *s1 = new char[MAX + 10]();
        char *s2 = new char[MAX + 10]();
        int *a1 = new int[MAX + 10]();
        int *a2 = new int[MAX + 10]();
        int *result = new int[MAX + 10]();
        int *tmp = new int [MAX + 10]();
        cin >> s1;
        cin >> s2;
        //将字符串转换为整型数组
        int nLen1 = strlen(s1);
        for(int i = nLen1 - 1, j = 0;0 <= i; --i)
        {
            a1[j++] = s1[i] - '0';
        }
        int nLen2 = strlen(s2);
        for(int i = nLen2 - 1, j = 0; 0 <= i; --i)
        {
            a2[j++] = s2[i] - '0';
        }
        int nMaxLen = Max(nLen1, nLen2);
        //输出
        int nHighestPos = 0;
        //计算商的最高位数
        int nShiftLeft = nLen(nMaxLen, a1) - nLen(nMaxLen, a2);
        while(MaxNum(nMaxLen, a1, a2) == a1)//余数 > 除数,继续循环
        {
            ShiftLeft(nMaxLen, a2, tmp, nShiftLeft);//计算a2的10的nShiftLeft倍
            while(MaxNum(nMaxLen, a1, tmp) == a1)//循环减去a2的10的nShiftLeft倍
            {
                Substract(nMaxLen, a1, tmp);
                result[nShiftLeft]++;//记录能减去的次数,即为商的位
            }
            if(nHighestPos == 0 && result[nShiftLeft])//记录商的最高位
            nHighestPos = nShiftLeft;
            nShiftLeft--;
        }
        for(int i = nHighestPos; 0 <= i; --i)
        {
            cout << result[i];
        }
        cout << endl;
        delete [] s1;
        delete [] s2;
        delete [] a1;
        delete [] a2;
        delete [] result;
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值