数值处理-高精度

在现实中的计算问题:

1.天文学中的距离计算

在天文学领域,科学家们常常需要计算星系之间的距离。例如,测量地球与遥远星系仙女座星系的距离。仙女座星系距离地球约 254 万光年,1 光年约等于(9.461×10^12)千米。那么地球与仙女座星系的距离大约是(2540000×9.461×10^12)千米。这个数值非常巨大,使用常规的数值类型(如 double )很难精确表示。double 虽然能表示很大的数,但在精度上会有所损失,特别是对于这种需要精确计算的天文距离。

2.密码学中的大整数运算

在现代密码学中,RSA 加密算法是一种广泛使用的非对称加密算法。RSA 算法的核心运算涉及到非常大的整数的乘法和取模运算。例如,生成 RSA 密钥对时,需要选择两个大质数p和q,这两个质数通常有几百位甚至上千位。计算(n = p×q)时,这个乘积n就是一个极大的整数。如果使用常规数据类型,根本无法容纳这么大的数值,更无法进行后续基于这个大整数的加密和解密运算。

高精度算法可以通过模拟多位数字的运算,准确地表示和计算这些巨大数值,确保数据的准确性。

一、什么是高精度计算

高精度计算主要用于需要极高精度和处理大数字的场景,如科学研究、金融计算、密码学、天文学等领域。它是一种能够处理超出普通数据类型(如32位整数、64位浮点数等)表示范围的数值计算方法。

核心思想:将大数分解为计算机可处理的基本单元,使用数组或其他数据结构来存储和操作,通过模拟人工计算的逻辑(如逐位操作、进位/借位处理)实现高精度运算。

二、高精度计算过程

1.数据存储

以整数为例,将数字的每一位存储在数组的一个元素中。例如,对于整数 12345,可以用数组 [5, 4, 3, 2, 1] 表示,低位数字放在数组的低索引位置,高位数字放在高索引位置(便于从左到右遍历数字,方便从低位开始计算)。

例如,数字 1234567890123456 可以存储为字符串 "1234567890123456" 。

2.运算实现

高精度算法通过模拟手工计算的方法来实现基本的算术运算,包括加法、减法、乘法和除法。

加法:

减法:

乘法:

除法:

三、高精度算法的实现

3.1 高精度加法

两个大整数 987654321012345 和 666677778888 相加,使用高精度加法的实现过程如下:

1.准备数据:(以数组为例)

将两个大数分别反向存于整数数组a和b,左低右高

数组a:

543210123456789

数组b:

888877776666

2.计算过程:逐位相加并处理进位

创建一个结果数组 c 并初始化为0,数组c的长度为a,b数组最大长度加1,max(len(a),len(b))+1。

创建一个保存进位的临时变量 t 。

逐位相加并处理进位:

                 
变量t0111100000111000
a543210123456789 
b888877776666    
c3321978990338890

3.输出结果:

去掉数组c高位的0,反向输出数组c: 988330998791233。

 

示例代码(用数组实现):

 

3.2 高精度减法

两个大整数 987654321012345 和 666677778888 相减,使用高精度减法的实现过程如下:

1.准备数据:(以字符串为例)

将两个大数分别存入字符串a和b,两个数相减后位数不会增加,所以这里不用反转数字。

a=“987654321012345” , b=“666677778888”

声明并初始化一个结果字符串 s=“” ;

2.确保被减数大于减数,即 a-b 时 a 要大于 b,如果 b>a 就交换 a 和 b。

3.从后向前逐位相减,并循环处理借位。把得数添加到结果数组 s 中。

4.删除结果中的前导 0 ,并输出。

 

示例代码(用字符串实现):

3.3 高精度乘法

两个大整数 987654321012345 和 666677778888 相减,使用高精度减法的实现过程如下:

1.准备数据

创建并初始化一个结果数组,大小为两个乘数的长度之和。

2.逐位相乘

使用嵌套循环,从最低位开始逐位相乘。对于每个乘积,将其加到结果数组的相应位置。

3.处理进位

在逐位相乘的过程中,如果某一位的乘积加上之前的进位大于等于10,则需要将进位加到下一位。这一步也可以在逐位相乘完成之后单独处理。

4.去掉前导零并输出。

计算过程示例:

示例代码:

3.4 高精度除法

3.4.1 高精除以低精(按位相除法)

以123456789/45为例的处理过程:

  1. 初始化:设被除数为数组 A[]={1,2,3,4,5,6,7,8,9}表示123456789,除数为 b=45,结果数组 C[],余数 r = 0

  2. 从高位到低位计算(逐位计算):

    • 对每一位i(从最高位开始):

      • 当前被除数部分:r = r * 10 + A[i]

      • 计算商:C[i] = r / b

      • 更新余数:r = r % b

  3. 去除前导零

  4. 输出结果

参考示例: