如果我在Wolfram Alpha中输入一个值,例如1234567 ^ 98787878,它可以为我提供一些细节。这包括十进制近似,总长度,最后一位数等。您如何评估这么大的数字?据我所知,编程语言必须有一个特殊的数据类型才能存储数字,更不用说将它添加到其他东西了。虽然我可以看到人们如何接近两个非常大的数字,我看不出有多大的数字被评估。
可以通过重复添加来计算10 ^ 2。然而,诸如上述示例之类的数字将需要巨大的循环。有人可以解释如何评估这么大的数字吗?另外,有人如何创建自定义大型数据类型以支持C#中的大数字?
嗯,这很容易,你可以自己完成
位数 可以通过获得 对数:
以来 A^B = 10 ^ (B * log(A, 10))
我们可以计算 (A = 1234567; B = 98787878)
在我们的情况下
B * log(A, 10)
= 98787878 * log(1234567, 10)
= 601767807.4709646...
integer part + 1
(601767807 + 1 = 601767808) 是位数
第一比方说 五, 数字 可以通过 对数 以及;
现在我们应该分析一小部分
B * log(A, 10)
= 98787878 * log(1234567, 10)
= 601767807.4709646...
f = 0.4709646...
第一个数字是 10^f
(删除小数点)= 29577...
持续比方说 五, 数字 可以作为相应的获得 余:
最后五位= A^B rem 10^5
A rem 10^5
= 1234567 rem 10^5
= `34567
A ^ B rem 10 ^ 5**=**
((A rem 10 ^ 5)^ B)rem 10 ^ 5**=**
(34567 ^ 98787878)rem 10 ^ 5=
45009`
最后五位数 45009
你可能会发现 BigInteger.ModPow
(C#)在这里非常有用
最后
1234567 ^ 98787878 = 29577 ... 45009(601767808位数)
嗯,这很容易,你可以自己完成
位数 可以通过获得 对数:
以来 A^B = 10 ^ (B * log(A, 10))
我们可以计算 (A = 1234567; B = 98787878)
在我们的情况下
B * log(A, 10)
= 98787878 * log(1234567, 10)
= 601767807.4709646...
integer part + 1
(601767807 + 1 = 601767808) 是位数
第一比方说 五, 数字 可以通过 对数 以及;
现在我们应该分析一小部分
B * log(A, 10)
= 98787878 * log(1234567, 10)
= 601767807.4709646...
f = 0.4709646...
第一个数字是 10^f
(删除小数点)= 29577...
持续比方说 五, 数字 可以作为相应的获得 余:
最后五位= A^B rem 10^5
A rem 10^5
= 1234567 rem 10^5
= `34567
A ^ B rem 10 ^ 5**=**
((A rem 10 ^ 5)^ B)rem 10 ^ 5**=**
(34567 ^ 98787878)rem 10 ^ 5=
45009`
最后五位数 45009
你可能会发现 BigInteger.ModPow
(C#)在这里非常有用
最后
1234567 ^ 98787878 = 29577 ... 45009(601767808位数)
通常存在为任意大整数提供bignum数据类型的库(例如映射数字) k*n...(k+1)*n-1, k=0..<some m depending on n and number magnitude>
一个大小的机器字 n
重新定义算术运算)。对于c#,您可能感兴趣 的BigInteger。
取幂可以递归分解:
pow(a,2*b) = pow(a,b) * pow(a,b);
pow(a,2*b+1) = pow(a,b) * pow(a,b) * a;
还有一些数论结果已经产生了特殊算法来确定大数的性质而不实际计算它们(确切地说:它们的完整十进制扩展)。
要计算有多少位数,可以使用以下表达式:
decimal_digits(n) = 1 + floor(log_10(n))
这给出了:
decimal_digits(1234567^98787878) = 1 + floor(log_10(1234567^98787878))
= 1 + floor(98787878 * log_10(1234567))
= 1 + floor(98787878 * 6.0915146640862625)
= 1 + floor(601767807.4709647)
= 601767808
通过进行指数mod 10 ^ k来计算尾随k个数字,这使得中间结果不会变得太大。
将使用(软件)浮点实现来计算近似值,该实现有效地将^(98787878 log_a(1234567))评估为某个数字a的某个固定精度,这使得算法很好地工作(通常为2或e或10)。这也避免了在任何时候实际使用数百万个数字的需要。
这有很多库,并且在python的情况下内置了该功能。您似乎主要关注此类数字的大小以及执行计算所需的时间,例如示例中的指数。所以我会解释一下。
表示
您可以使用数组来保存大数字的所有数字。更有效的方法是使用32位无符号整数数组并存储大数字的“32位块”。您可以将这些块视为具有2 ^ 32个不同数字或字符的数字系统中的单个数字。我在当天的8位Atari800上使用了一个字节数组来执行此操作。
做数学
显然,您可以通过循环所有数字并将一个数组的元素添加到另一个数组并跟踪进位来添加两个这样的数字。一旦你知道如何添加,你就可以编写代码来通过乘以数字进行“手动”乘法并将结果放在正确的位置并添加很多 - 但软件可以很快地完成所有这些操作。比在纸上手动使用的算法还要快。纸张乘法是O(n ^ 2),其他方法是O(n * log(n))。至于指数,你当然可以乘以相同的数字数百万次,但这些乘法中的每一次都将使用前面提到的乘法函数。有更快的方法可以进行求幂,这需要更少的乘法。例如,您可以通过计算(((x ^ 2)^ 2)^ 2)^ 2来计算x ^ 16,其仅涉及4个实际(大整数)乘法。
在实践中
尝试自己编写这些函数很有趣,也很有教育意义,但在实践中,您需要使用已经过优化和验证的现有库。
我认为答案的一部分在于问题本身:)要存储这些表达式,您可以单独存储基数(或尾数)和指数,就像科学记数法一样。扩展到那个,你不可能完全评估表达式并存储这么大的数字,但是,理论上你可以预测结果表达式的某些属性。我将带您了解您谈到的每个属性:
- 十进制近似:可以通过评估简单的对数值来计算。
- 表达式a ^ b的总位数可以通过公式计算
数字=地板函数(1 + Log10(a ^ b)),其中floor函数是小于数字的最接近的整数。对于例如10 ^ 5中的位数是6。
- 最后的数字:这些可以通过线性增加的指数的表达形成算术级数的事实来计算。对于例如在单位;对于7 ^ x的指数重复7,9,3,1。因此,您可以计算出如果x%4为0,则最后一位为1。
有人可以为大数字创建自定义数据类型,我不能说,但我相信,这个数字不会被评估和存储。