【问题标题】:Fast exponentiation when only first k digits are required?只需要前 k 位时的快速求幂?
【发布时间】:2010-10-12 17:17:21
【问题描述】:

这实际上是为了编程比赛,但我已经很努力了,甚至连最微弱的线索都没有。

找到 nm 的第一个和最后 k 个数字,其中 n 和 m 可以非常大 ~ 10^9。

对于最后 k 位,我实现了模幂运算。

对于第一个 k,我想使用二项式定理达到一定的幂,但这涉及到大量的阶乘计算,我不确定如何找到一个最佳点,在该点处 n^m 可以扩展为 (x +y)m.

那么有没有已知的方法可以在不执行整个计算的情况下找到前k个数字?

更新 1 m

中的数字

【问题讨论】:

  • K 是任意的吗?还是限制在特定范围内?

标签: math exponentiation


【解决方案1】:

不确定,但恒等式 nm = exp10(m log10(n)) = exp(q (m log(n)/q)) 其中 q = log(10) 得出请注意,exp10(x) 的前 K 位数字 = exp10(frac(x)) 的前 K 位数字,其中 frac(x) = x = x - floor(x) 的小数部分。

更明确地说:nm 的前 K 位是其 mantissa = exp(frac(m log(n)/q) * q) 的前 K 位,其中q = log(10)。

或者你甚至可以在这个会计练习中走得更远,并使用 exp((frac(m log(n)/q)-0.5) * q) * sqrt(10),它也有相同的尾数(+ 因此相同的前 K 位数字)以便 exp() 函数的参数以 0 为中心(在 +/- 0.5 log 10 = 1.151 之间)以实现快速收敛。

(一些例子:假设你想要 2100 的前 5 位数字。这等于 exp((frac(100 log(2)/q)-0.5)*q 的前 5 位数字)*sqrt(10) = 1.267650600228226。根据MATLAB,2100的实际值为1.267650600228229e+030,我手边没有bignum库。对于21,000,000,000的尾数 我得到 4.612976044195602 但我真的没有办法检查....Mersenne primes 上有一个页面,有人已经完成了艰苦的工作;220996011-1 = 125,976,895,450 ...我的公式给出了在 MATLAB 中计算的 1.259768950493908,它在第 9 位之后失败。)

我可能会使用Taylor series(对于 exp 和 log,而不是对于 nm)连同它们的错误界限,并继续添加术语,直到错误界限下降到以下前 K 个数字。 (通常我不使用泰勒级数进行函数逼近——它们的误差被优化为在单个点附近最准确,而不是在所需的区间上——但它们确实具有数学上简单的优势,而且你只需添加附加项即可将准确度提高到任意精度)

对于对数,我会使用您最喜欢的近似值。

【讨论】:

  • @nlucaroni:谢谢,但将这样的想法作为您自己的评论提交会更有礼貌。
  • 泰勒级数对于这个函数不会很简单。 f(x) = x^n, f'(x) = nx^(n-1), f''(x) = n(n-1)x^(n-2) - 你看到了问题。每个术语都需要评估一个类似于您要近似的函数。如果 n=10^9,你需要很多项才能得到 f 的 n 次导数
  • 我不是说 n^m 的泰勒级数,我指的是 exp() 和 log()
  • 仍然不是要走的路,IMO。他们不会足够快地收敛。我更喜欢看 Abramowitz 和 Stegun 或类似的东西:myweb.lmu.edu/dmsmith/MComp89.pdf
  • 也许我遗漏了什么......你需要 K 做什么? exp(K (m log(n)/K)) === exp(m log(n))
【解决方案2】:

嗯。我们要计算 并且只得到 n 个第一个数字。

通过以下迭代计算:

你有。 不完全计算每个。 问题是 的相对误差较小 比 an 倍相对误差。

您希望获得小于 的最终相对误差。 因此,每一步的相对误差可能是。 删除每一步的最后一位数字。

例如,a=2、b=16、n=1。最终相对误差为 10^{-n} = 0,1。 每一步的相对误差为 0,1/16 > 0,001。 因此,3 位数字在每一步都很重要。 如果 n = 2,则必须保存 4 位。

2 (1), 4 (2), 8 (3), 16 (4), 32 (5), 64 (6), 128 (7), 256 (8), 512 (9), 1024 ( 10) --> 102, 204 (11), 408 (12), 816 (13), 1632 (14) -> 163, 326 (15), 652 (16)。

答案:6。

该算法的复杂度为O(b)。但是很容易改变它来获得 O(log b)

【讨论】:

    【解决方案3】:

    假设您在每一步都截断?不确定这有多准确,但是,例如,采取 n=11 m=某个大数 你想要前 2 位数字。

    递归:

    1. 11 x 11 -> 121,截断 -> 12(1 个截断或舍入) 然后取截断值并再次加注
    2. 12 x 11 -> 132 截断 -> 13 重复,

    3. (132 截断)x 11 -> 143。 ...

    最后加上 #0 等于你已经完成的截断次数。

    【讨论】:

    • 此方法需要与有效的求幂方法相结合。如果您想要 7^23421613 的最后 10 位数字,您当然不想执行乘法和截断方法 23421613 次。
    • 这不起作用,例如。 65^5 = 116... 对于 k = 3,但通过截断,答案是 115。
    • 另外你必须注意你的错误界限。即使你只需要 2 位数,在中间计算中也需要 2 位数以上。
    【解决方案4】:

    你看过exponentiation by squaring吗?您也许可以修改其中一种方法,以便只计算必要的部分。

    在我上一堂算法课中,我们必须实现与您正在做的类似的事情,我隐约记得那个页面很有用。

    【讨论】:

      猜你喜欢
      • 2013-07-04
      • 2012-07-22
      • 1970-01-01
      • 2012-08-31
      • 1970-01-01
      • 2018-12-15
      • 2016-06-10
      • 2018-09-13
      • 1970-01-01
      相关资源
      最近更新 更多