by HPC_ZY
最近需要做大数计算,且要求结果精度与原始数据一致(不能使用科学计数等近似解)。所以总结分享一些“超大正整数的基本运算方法”,如加、减、乘、除、幂等
一、基本原理
uint32(unsigned int)型可表示的最大数为 ( 2 32 − 1 ) (2^{32}-1) (232−1),uint64(unsigned long long)型可表示的最大数为 ( 2 64 − 1 ) (2^{64}-1) (264−1),超过这样的数就没法直接计算了。
但是我们知道加减乘除的本质还是按位计算,所以我们可以将大数拆分为多个小位数。
根据这个原理最合适的就是使用字符串的形式,这样就将上限从最大数据类型变成了计算机最大内存。
下面我们就来研究字符串格式的加减乘除,首先分享MATLAB中的实现方法,然后改写成C。
注:本文仅研究正整数,暂不涉及负数与小数
二、MATLAB简单实现
1. 加(+)
任意大数相加,主要原理:
1)按位相加
2)满十进一
%% 大数加(输入为字符串格式)
function out = OLNadd(a,b)
% 转数字矩阵(为了逻辑方便,我们将数字反序)
mata = a(end:-1:1)-'0';
matb = b(end:-1:1)-'0';
% 计算位数
la = length(a);
lb = length(b);
% 初始化
if la>=lb
digitStart = lb;
matout = [mata,0];
mattmp = matb;
else
digitStart = la;
matout = [matb,0];
mattmp = mata;
end
% 循环求解
for k = digitStart:-1:1
% 位求和,满十进一
tmp = matout(k)+mattmp(k);
if tmp<10
matout(k) = tmp;
else
matout(k) = tmp-10;
matout(k+1) = matout(k+1)+1;
end
end
% 转字符
out = char(matout(end:-1:1)+'0');
if out(1) == '0'
out(1) = [];
end
end
2. 减(-)
任意大数相减,主要原理:
1)比较大小,以大减小
2)符号由大小关系决定
3)按位相减
4)不够向前借位
%% 大数减(输入为字符串格式)
function out = OLNsub(a,b)
% 转数字矩阵(为了逻辑方便,我们将数字反序)
mata = a(end:-1:1)-'0';
matb = b(end:-1:1)-'0';
% 计算位数
la = length(a);
lb = length(b);
% 初始化
isEqual = 0;
if la>lb % 默认用大的减小的(正负号由大小关系决定)
digitEnd = lb;
matout = [mata,0];
mattmp = matb;
flag = 1; % 结果为正
elseif la<lb
digitEnd = la;
matout = [matb,0];
mattmp = mata;
flag = 0; % 结果为负
else
% 对比第一个不相等的位数,谁大谁小
idx = find(a~=b,1);
if ~isempty(idx)
if a(idx)>b(idx)
digitEnd = lb;
matout = [mata,0];
mattmp = matb;
flag = 1; % 结果为正
else
digitEnd = la;
matout =