【问题标题】:How do computers evaluate huge numbers?计算机如何评估巨大的数字?
【发布时间】:2013-08-20 11:34:51
【问题描述】:

如果我在 Wolfram Alpha 中输入一个值,例如 1234567^98787878,它可以为我提供许多详细信息。这包括十进制近似值、总长度、最后一位数等。您如何评估如此大的数字?据我了解,编程语言必须具有特殊的数据类型才能存储数字,更不用说将其添加到其他内容中了。虽然我可以看到如何处理两个非常大的数字相加,但我看不出计算的数字有多大。

10^2 可以通过重复相加计算。然而,像上面的例子这样的数字需要一个巨大的循环。有人可以解释如何评估如此大的数字吗?另外,例如,有人如何创建自定义大数据类型来支持 C# 中的大数字?

【问题讨论】:

    标签: math data-structures


    【解决方案1】:

    这很容易,您可以自己完成

    1. 位数可以通过对数获得:
    since `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) 是位数

    1. 第一,比如说位数也可以通过对数得到; 现在我们应该分析小数部分

      B * log(A, 10) = 98787878 * log(1234567, 10) = 601767807.4709646...

      f = 0.4709646...

      第一个数字是10^f(已删除小数点)= 29577...

    2. 最后一个,比如说,五个digits可以得到对应的余数

      最后五位数字 = 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 rem 10^5 = ((A rem 10^5)^B) rem 10^5。这是怎么解释的?
    • @Sundeep:似乎应该有一个换行符:我先计算(A rem 10^5),然后计算((A^B)rem 10^5)。我已经编辑了帖子。
    【解决方案2】:

    通常有一些库为任意大的整数提供 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;
    

    还有一些数论结果产生了特殊的算法来确定大数的属性而无需实际计算它们(准确地说:它们的完整十进制扩展)。

    【讨论】:

    • 这是否意味着计算海量指数没有花哨的捷径?我认为 Wolfram Alpha 必须有一个庞大的分布式系统,仅用于计算大数?
    • @Sam 是也不是。在某些特定情况下有一些捷径,但通常您必须进行全乘,而且 Wolfram Alpha 可能有大型数据中心来回答查询。但是除了计算大数之外,其中大部分将做其他事情,而您的示例 1234567^98787878 只需要两打 bignum 乘法,尽管如果完全评估它确实会产生约 150 兆字节。一台计算机可以在合理的时间内完成这项工作,“巨大的分布式”部分只是进入图片,因为它有成千上万的人同时运行这样的查询。
    • 给定的算法一个花哨的快捷方式,因为它允许重用中间结果。
    • @collapsar 这是一种更高效的算法,但我不会称其为捷径。例如,快捷方式是采用 OP 的表达式并为您提供最后几位而不计算数百万其他数字。
    【解决方案3】:

    要计算有多少位,可以使用以下表达式:

    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
    

    后面的 k 位是通过取幂 mod 10^k 计算的,这样可以防止中间结果变得太大。

    将使用(软件)浮点实现计算近似值,该实现有效地将 a^(98787878 log_a(1234567)) 评估为某个数字 a 的某个固定精度,从而使算术很好地工作(通常是 2 或 e 或10)。这也避免了在任何时候实际处理数百万位数的需要。

    【讨论】:

      【解决方案4】:

      为此有很多库,并且在 python 的情况下,该功能是内置的。您似乎主要关心这些数字的大小以及计算示例中的指数可能需要的时间。所以我稍微解释一下。

      代表 您可以使用数组来保存大数的所有数字。一种更有效的方法是使用 32 位无符号整数数组并存储大数的“32 位块”。您可以将这些块视为具有 2^32 个不同数字或字符的数字系统中的单个数字。以前我在 8 位 Atari800 上使用了一个字节数组来执行此操作。

      做数学 您显然可以通过遍历所有数字并将一个数组的元素添加到另一个数组并跟踪进位来添加两个这样的数字。一旦你知道如何加法,你就可以编写代码来进行“手动”乘法,方法是将数字相乘并将结果放在正确的位置并进行大量加法 - 但软件会很快完成所有这些工作。还有比你在纸上手动使用的更快的乘法算法。纸乘法是 O(n^2),而其他方法是 O(n*log(n))。至于指数,您当然可以乘以相同的数百万次,但每次乘法都将使用前面提到的函数进行乘法运算。有更快的求幂方法需要更少的乘法。例如,您可以通过计算 (((x^2)^2)^2)^2 来计算 x^16,这仅涉及 4 个实际(大整数)乘法。

      实践中 尝试自己编写这些函数既有趣又具有教育意义,但在实践中,您将希望使用经过优化和验证的现有库。

      【讨论】:

        【解决方案5】:

        我认为部分答案在于问题本身 :) 要存储这些表达式,您可以分别存储底数(或尾数)和指数,就像科学记数法一样。扩展到此,您不可能完全评估表达式并存储如此大的数字,尽管理论上您可以预测结果表达式的某些属性。我将带您了解您谈到的每个属性:

        1. 十进制近似值:可以通过评估简单的对数值来计算。
        2. 表达式a^b的总位数,可通过公式计算 Digits = floor function (1 + Log10(a^b)),其中 floor function 是小于数字的最接近的整数。例如10^5 的位数是 6。
        3. 最后一位数:这些可以通过线性递增指数的表达式形成算术级数这一事实来计算。例如在单位所在地; 7, 9, 3, 1 对 7^x 的指数重复。因此,您可以计算出如果 x%4 为 0,则最后一位为 1。 有人可以为大数字创建自定义数据类型吗,我不能说,但我敢肯定,不会评估和存储数字。

        【讨论】:

        • 实际上,这些大整数可以使用 bignum 库以整数形式存储(并且通常是)。有很多这样的工具。
        • @woodchips - 是的,你是对的,我高估了这个数字。精度库只能容纳最大缓冲区的大小。如果使用位数(以及 2 的指数,给出这么多位数)进行计算,则需要约 40MB 来存储它。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-01-19
        • 2012-03-07
        • 1970-01-01
        • 1970-01-01
        • 2017-01-01
        • 2019-10-22
        • 1970-01-01
        相关资源
        最近更新 更多