【问题标题】:Efficient way to count the digits of very big factorials计算非常大阶乘位数的有效方法
【发布时间】:2014-09-23 15:07:00
【问题描述】:

假设我们有一个非常大的阶乘,例如 (10^7)!,有没有一种有效的方法来计算它的 exact 位数? (Wolfram alpha 结果显示 (10^7)!有 65,657060 位)

当然,我不能使用将值逐一乘以的幼稚实现,因为评估结果太慢了。

我认为这个问题的解决方案可能以两种方式结束

  1. 如何在不计算阶乘的情况下找到阶乘的数字
  2. 如何更有效地计算阶乘(最好使用 BigInteger 或 BigDecimal)

我更喜欢 1. 而不是 2. 因为我只想知道阶乘的位数。 有什么建议吗?

【问题讨论】:

标签: java factorial


【解决方案1】:

将所有要乘以的数字的对数相加应该可以解决问题:

public long facDigits(long n) {
    double logFacN = 0;
    for (long i = 2; i <= n; i++) {
        logFacN += Math.log10(i);
    }
    return (long) logFacN + 1;
}

public void test() {
    double tenToThe7th = Math.pow(10, 7);
    long digits = facDigits((long) tenToThe7th);
    System.out.println("Digits in " + tenToThe7th + "! = " + digits);
}

打印

Digits in 1.0E7! = 65657060

这里的逻辑是,当你在计算阶乘时乘以 x 时,实际上是在加上 log10(x) 数字所以这里我只是把它们加起来。

【讨论】:

  • 至少不需要 BigInteger 占用内存。
  • 这仅与您的日志计算一样准确
  • @KevinL - 你是对的 - 但它似乎在 10 ^ 7 时有效!我很惊讶。它肯定比计算log10(10^7!) 更快。在我的设备上,它在 1.356 秒内得到答案。
  • @OldCurmudgeon a double 为您提供 15 位精度,一旦您转换为对数计算,由于您的答案是 8 位,您有大约 7 位用于舍入,这显然足够接近跨度>
  • 这几乎是 100% 正确的。您应该将结果设为 1,因为位数是由 floor(log(N))+1 计算的。 floor 由转换为long 完成,并且产品的对数等于您在循环中计算的和数的对数之和。你只是缺少+1
【解决方案2】:

@OldCurmudgeon 的解决方案很好,但你可以尝试使用 Kamentsky 的公式:

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {
    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        int numOfTests = Integer.parseInt(in.readLine());

        in.lines()
                .limit(numOfTests)
                .map(n -> Integer.parseInt(n))
                .forEach(n -> System.out.println(KamenetskyFormula(n)));
    }

    private static long KamenetskyFormula(int n) {
        if (n < 2) {
            return 1;
        }
        double x = n * Math.log10(n / Math.E) + Math.log10(2 * Math.PI * n) / 2.0;
        return (long) (Math.floor(x) + 1);
    }
}

连接到Count number of digits in factorial - performance issue

【讨论】:

  • 既好又快,但 Kamenetsky 公式给出了近似结果,并且对于某些数字可能会失败
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-11
  • 2016-11-29
  • 2010-11-25
相关资源
最近更新 更多