高精度数(大整数)除法

题目描述

高精除以高精,求它们的商和余数。

输入

输入两个低于300位的正整数。

输出

输出商和余数。

算法基本原理

算法基本原理:就是被除数能减去除数多少次,减的次数就是商,减完剩下的部分就是余数。

忘了大整数减法?点我

代码

#include<iostream>
#include<string>
using namespace std;

// 计算数a是否比数b大(或相等)
bool bigger(int a[], int b[], int aLen, int bLen){ 
    if(aLen < bLen){
        return 0;
    }else if(aLen > bLen){
        return 1;
    }else{
        for(int i=aLen-1, j=bLen-1; i>=0 && j>=0; i--,j--){
            if(a[i]<b[j]){
                return 0;
            }else if(a[i]>b[j]){
                return 1;
            }
        }
        return 1;
    }
}

//大整数减法,相当于a-=b。 
int sub(int a[], int b[], int aLen, int bLen){
    int ans[100]={0},maxLen=max(aLen,bLen);
    
    for(int i=0; i<maxLen; i++){
        if(a[i]<b[i]){
            a[i] += 10;
            a[i+1]--;
        }
        ans[i] = a[i] - b[i];
    }
    
    while(ans[maxLen-1] == 0 && maxLen > 1){
        maxLen--;
    }
    
    for(int i=0; i<maxLen; i++){
        a[i] = ans[i];
    }
    return maxLen;
}

int main(){
    string as, bs;
    int a[100]={0}, b[100]={0}, aLen, bLen, sum=0;
    
    //输入 
    cin>> as >> bs;
    
    aLen = as.length();
    bLen = bs.length();
        
    //倒序转int 
    for(int i=0; i<aLen; i++){
        a[aLen-i-1] = as[i] - '0';
    }
    
    for(int i=0; i<bLen; i++){
        b[bLen-i-1] = bs[i] - '0';
    }

    //去除前导0 
    while(a[aLen-1] == 0 && aLen > 1){
        aLen--;
    }
    
    while(b[bLen-1] == 0 && bLen > 1){
        bLen--;
    }
    
    //执行多次减法运算,每次a=a-b,直至a<b 
    while(bigger(a, b, aLen, bLen)){ 
        aLen = sub(a, b, aLen, bLen);
        sum++;
    }
    
    //输出
    cout << sum << endl; 
    for(int i=aLen-1; i>=0; i--){
        cout << a[i];
    }
    cout << endl;
    
    return 0;
}

不过,它存在两个问题:

问题1:慢

问题2:当商大于21.5亿时,结果会溢出

优化

优化思想例图

这种方法是可以将商10个10个,100个100个甚至100000000个100000000个运算,大大提高了效率。

#include <iostream>
#include <cstring>
using namespace std;

//去除前导0
int delPreZero(int x[], int xLen){
    int i=xLen;
    
    while(x[i-1]==0 && i>1){
        i--;
    }
    
    return i;
} 

//逆序输出数组值 
void printArr(int x[], int xLen){
    for(int i=xLen-1; i>=0; i--){
        cout << x[i];
    }
    cout << endl;
}

//若x>=y返回true,否则返回false 
bool compare(int x[], int y[], int xLen, int yLen){
    if(xLen < yLen){
        return false;
    }
        

    if(xLen == yLen){
        for(int i=xLen-1; i>=0; i--){
            if(x[i] > y[i]){
                return true;
            }
            if(x[i] < y[i]){
                return false;
            }
        }
        return true;
    }
    return true;
}

//若x>=y,则x的高位减去y(只减一次),返回值为x的新长度
int sub(int x[], int y[], int z[], int xLen, int yLen){
    int zLoc = xLen - yLen ;    //商的位置 
    
    //若不够减,则商的位置后移一位 
    for(int i=1; i<=yLen; i++){
        if(x[xLen-i] > y[yLen-i])
            break;
        
        if(x[xLen-i] < y[yLen-i]){
            zLoc--;
            break;
        }           
    }
    
    if(zLoc<0) 
        return xLen;
        
    //当前被除数x的高位与除数y做一次减法运算 
    for(int i=zLoc,j=0; i<xLen && j<yLen; i++,j++){
        while(x[i] < y[j]){
            x[i+1]--;
            x[i] += 10;
        }
        
        x[i] -= y[j];
    }
    
    //商的相应位置加一 
    z[zLoc]++;
    
    //计算当前被除数x的真实长度 
    while(x[xLen-1]==0)
        xLen--;
    
    if(xLen <= 0)
        xLen = 1;
        
    return xLen;
} 

int main(){
    char as[301], bs[301];
    
    int a[301]={0}, b[301]={0}, c[301]={0};
    int aLen = 0, bLen = 0, cLen = 1, maxLen = 0;
    int i;
    
    //输入 
    cin >> as >> bs;
    aLen = strlen(as);
    bLen = strlen(bs);

    //被除数和除数分别逆序存放 
    for(i=0; i<aLen; i++){
        a[i] = as[aLen-1-i] - '0';
    }

    for(i=0; i<bLen; i++){
        b[i] = bs[bLen-1-i] - '0';
    }
    
    //去除前导0
    aLen = delPreZero(a, aLen);
    bLen = delPreZero(b, bLen);
    
    //通过从高位开始连续减去除数,计算商和余数 
    cLen = aLen - bLen + 1;
    while(compare(a, b, aLen, bLen)){
        aLen = sub(a, b, c, aLen, bLen);
    }
    
    //解决商的位数是0或负数的情况 
    if(cLen < 1){
        cLen = 1;
    }
    
    //去除商的前导0 
    cLen = delPreZero(c, cLen);
    
    //输出商c 
    printArr(c, cLen);
    
    //输出余数a 
    printArr(a, aLen);
    
    return 0;
}

速度测试

输入数据:
123456789
123


优化前
优化后

优化后的速度是优化前的17.5倍!
如果被除数更大,除数更小,优化后的提速效果更显著!

商溢出测试

输入数据:
123456789123456789123456789
123


优化后的算法没有溢出

商虽然远大于21.5亿,但它并没有发生溢出。优化前的算法根本跑不出结果来。

关键点

优化前 优化后
利用循环,多次使用减法,容易超时。 从被除数的高位,以最少的次数使用减法,时间通常不超过0.3秒。
将结果放入整形变量,容易溢出。 将结果放入数组,不可能溢出。

测试数据

被除数 除数 余数
63 3 21 0
3 63 0 3
063 0003 21 0
123456789123456789123456789 123 1003713732711030805881762 63
123 123456789 0 123
1 1 1 0
0 123 0 0
00000 123 0 0

特别鸣谢

测试数据提供: 挖坑大师——妈妈
推广平台提供: 简书
测试平台提供: 信息学奥赛一本通网站

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,378评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,356评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,702评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,259评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,263评论 5 371
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,036评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,349评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,979评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,469评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,938评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,059评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,703评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,257评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,262评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,485评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,501评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,792评论 2 345

推荐阅读更多精彩内容