C++自封装工具类 大数计算器(万进制实现)

何为大数计算,比如让你计算一个乘法m*n,其中mn都是 \color{red}几百位长 的数据,并且需要保持原来数据的精度,这时基本数据类型intlong long肯定不行,早就超过范围了。

Java中,有大数工具类BigInteger等一些大数处理类,在Python中,语言本身就支持不限数据长度的计算,而在C++中,本身并不支持。

博主接连造了几次轮子,现在自封装实现一个大数运算工具类,如果有好的思路欢迎交流。

1、数据输入、输出形式

输入、输出都是数值字符串string类型。

2、计算原理(万进制)

我采用的是万进制逢万进一
输入的是数值字符串,比如"12345601230009",然后转换成int数组intsNum[4, 9, 123, 3456, 12],intsNum[0]表示数组的长度,intsNum[1]=9表示数值字符串中的第一段“0999”,intsNum[2]=123,表示数组中的第二段0123intsNum[3]=3456,表示数组中的第三段3456intsNum[4]=12,表示数组中的第四段12

int数组乘法计算规则
在这里插入图片描述

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

//将两个数组相加,并且结果存放子啊num3
//数组示例[4,123,0,1234,9],4表示长度,真正表示是的值为 ‘9 1234 0000 0123’
void add(int* num1, int* num2, int* num3, int maxLen) {
    if (num1[0] < num2[0]) {
        //维持num1的长度 >= num2的长度
        add(num2, num1, num3, maxLen);
        return;
    }
    memset(num3, 0, maxLen);
    //1、将num1复制到num3中
    for (int i = 0; i <= num1[0]; ++i) {
        num3[i] = num1[i];
    }
    //2、将num2按位加到num3上
    for (int i = 1; i <= num2[0]; ++i) {
        //num1[i]、num2[i]相加,并且加入低位的进位值
        num3[i] += num2[i];
        //num3[i] 逢万进位
        num3[i + 1] += num3[i] / 10000;
        num3[i] %= 10000;
    }
    //3、考虑num3是否会产生最高位的进位
    int carryIndex = num2[0] + 1;
    while (num3[carryIndex] > 9999) {
        num3[carryIndex + 1] += num3[carryIndex] / 10000;
        num3[carryIndex++] %= 10000;
    }
    //更新num3的长度
    if (carryIndex > num3[0] && num3[carryIndex] > 0) {
        num3[0] = carryIndex;
    }
}

//将两个数组相乘,并且结果存放子啊num3
//数组示例[4,123,0,1234,9],4表示长度,真正表示是的值为 ‘9 1234 0000 0123’
void mutli(int* num1, int* num2, int* num3, int maxLen) {
    memset(num3, 0, maxLen);
    //1、对num1、num2进行相乘
    for (int i = 1; i <= num2[0]; ++i) {
        for (int j = 1; j <= num1[0]; ++j) {
            //num1的第j位 与 num2的第i位相乘,应该放在num3的 第i + j - 1位上,画一个多位数相乘算术式可知
            num3[i + j - 1] += num1[i] * num2[j];
            if (num3[i + j - 1] > 9999) {
                //num3[i + j - 1] 逢万进位
                num3[i + j] += num3[i + j - 1] / 10000;
                num3[i + j - 1] %= 10000;
            }
        }
    }
    //2、检查num3是否有进位,注意长度为m、n位的两个数相乘结果长度不会超过 m + n
    //初始化num3的长度为 num1、num2之和
    num3[0] = num1[0] + num2[0];
    for (int i = 1; i < num3[0]; ++i) {
        if (num3[i] > 10000) {
            num3[i + 1] += num3[i] / 10000;
            num3[i] %= 10000;
        }
    }
    //如果最高位为0,说明结果小于
    if (num3[num3[0]] == 0) {
        num3[0] -= 1;
    }
}

//将数字字符串转成int数组,比如"12304560001",转换结果为[3, 1, 456, 123]
void strToInts(const string &num, int* numInts, int maxLen) {
    memset(numInts, 0, maxLen);
    for (int i = (int)num.size() - 1; i >= 0; ) {
        int tempNum = 0, j = 0, weight = 1;
        //取出四位转成整形
        while (i >= 0 && j++ < 4) {
            tempNum +=  (num[i--] - '0') * weight;
            weight *= 10;
        }
        numInts[++numInts[0]] = tempNum;
    }
}

//将int数组转换会字符串类型
string intsToStr(int* numInts) {
    if (numInts[0] == 0) {
        return  "0";
    }
    //最高位不需要补零
    string resStr = to_string(numInts[numInts[0]]);
    //注意访问顺序,是从高->低
    for (int i = numInts[0] - 1; i >= 1; --i) {
        string tempStr = "";
        //中间不足四位需要补零
        if (numInts[i] < 1000) {
            tempStr += '0';
        }
        if (numInts[i] < 100) {
            tempStr += '0';
        }
        if (numInts[i] < 10) {
            tempStr += '0';
        }
        tempStr += to_string(numInts[i]);
        resStr.append(tempStr);
    }
    return resStr;
}

//大数乘法(暂时支持正整形,浮点计算、负号保留计算以后更新)
string bigNumMutli(const string &num1, const string &num2) {
    //没有万进制最大容纳9999,因此100位万进制大约可容纳400长度的计算(乘法最大支持200位左右)
    int intsNum1[101] = { 0 }, intsNum2[101] = { 0 }, intsSum[101] = { 0 };
    strToInts(num1, intsNum1, 101);
    strToInts(num2, intsNum2, 101);
    mutli(intsNum1, intsNum2, intsSum, 101);
    return intsToStr(intsSum);
}

//大数加法(暂时支持正整形,浮点计算、负号保留计算以后更新)
string bigNumAdd(const string &num1, const string &num2) {
    //没有万进制最大容纳9999,因此100位万进制大约可容纳400长度的计算
    int intsNum1[101] = { 0 }, intsNum2[101] = { 0 }, intsSum[101] = { 0 };
    strToInts(num1, intsNum1, 101);
    strToInts(num2, intsNum2, 101);
    add(intsNum1, intsNum2, intsSum, 101);
    return intsToStr(intsSum);
}

int main() {
    string a, b;
    //scanf返回值为正确输入数据的变量个数,当一个变量都没有成功获取数据时,此时返回-1
    while (cin >> a >> b) {
        cout << "两者乘积:" + bigNumMutli(a, b) << endl;
        cout << "两者求和:" + bigNumAdd(a, b) << endl;
    }
    return 0;
}
发布了1008 篇原创文章 · 获赞 272 · 访问量 23万+

猜你喜欢

转载自blog.csdn.net/qq_41855420/article/details/104709200