何为大数计算
,比如让你计算一个乘法m*n
,其中m
、n
都是
的数据,并且需要保持原来数据的精度,这时基本数据类型int
、long 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
,表示数组中的第二段0123
,intsNum[3]=3456
,表示数组中的第三段3456
,intsNum[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;
}