簡體   English   中英

我們可以使用 JAVA 19 中的 int 計算出的最大階乘是多少?

[英]What is the greatest factorial we can calculate using an int in JAVA 19?

我們可以使用 Java 19 中的整數計算出的最大階乘是多少?

我發現使用 int 存儲結果的計算直到Factorial(12)都是正確的。

這是我使用的遞歸代碼:

public static int Factorial(int n) {
    if (n >= 13) {
        System.out.println("Trop grand");
        return -1;
    }
    if (n == 0) {
        return 1;
    } else {
        return n * Factorial(n - 1);
    }
}

你找到相同的結果嗎?

附屬問題:你將如何實現帶有 long 變量的 function?

我嘗試了一切,沒有期望,也沒有發生什么特別的事情。 (我必須填補這個空白。)

我沒有在 Java 中編碼,但是基於 C/C++ 的語言中的int是有符號的 integer,這意味着它使用一位作為符號(是的,即使你使用補碼),所以如果你有 32/64 位整數,你可以僅使用數字(不包括):

2^31 = 2147483648
2^63 = 9223372036854775808

現在查看從Fast exact bigint factorial中獲取的前幾個階乘:

[ 0.001 ms ] 1! = 1
[ 0.000 ms ] 2! = 2
[ 0.000 ms ] 3! = 6
[ 0.000 ms ] 4! = 24
[ 0.006 ms ] 5! = 120
[ 0.006 ms ] 6! = 720
[ 0.007 ms ] 7! = 5040
[ 0.005 ms ] 8! = 40320
[ 0.006 ms ] 9! = 362880
[ 0.007 ms ] 10! = 3628800
[ 0.008 ms ] 11! = 39916800
[ 0.012 ms ] 12! = 479001600
            2^31 = 2147483648 <-------------------------
[ 0.013 ms ] 13! = 6227020800
[ 0.014 ms ] 14! = 87178291200
[ 0.016 ms ] 15! = 1307674368000
[ 0.014 ms ] 16! = 20922789888000
[ 0.015 ms ] 17! = 355687428096000
[ 0.017 ms ] 18! = 6402373705728000
[ 0.019 ms ] 19! = 121645100408832000
[ 0.016 ms ] 20! = 2432902008176640000
            2^63 = 9223372036854775808 <-------------------------
[ 0.017 ms ] 21! = 51090942171709440000
[ 0.019 ms ] 22! = 1124000727777607680000

所以我預計20! 應該仍然適合 64 位有符號整數。

如果你使用unsigned int你可以計算兩倍的數字,但是在 64 位的情況下是21! 仍然太大...要計算更多,您需要更大的位寬或將結果分解為尾隨零(十進制或二進制)並將結果以兩個整數的形式出現,例如,如下所示:

void fact(int &man,int &exp,int n)        // man * 10^exp = n!
    {
    man=1; exp=0;
    if (n<=1) return;
    int i,j;
    for (i=2;i<=n;i++)
        {
        j=i;
        while (j%10==0){j/=10; exp++; }
        man*=j;
        if (man<0){ man=0; exp=0; return; }        // overflow
        while (man%10==0){ man/=10; exp++; }
        }
    }

我在VCL和 32 位有符號整數中使用它,如下所示:

int i,m,e;
AnsiString s;
for (i=0;i<40;i++)
    {
    fact(m,e,i);
    s=m; while (e){ s+="0"; e--; } // just print m to s and add e times "0" at the end
    mm_log->Lines->Add(AnsiString().sprintf("%2i! = %s",i,s)); // output to memo
    }

有了這個 output:

 0! = 1
 1! = 1
 2! = 2
 3! = 6
 4! = 24
 5! = 120
 6! = 720
 7! = 5040
 8! = 40320
 9! = 362880
10! = 3628800
11! = 39916800
12! = 479001600
13! = 6227020800
14! = 87178291200
15! = 19184179200 <- this one is overflowed too
16! = 0
17! = 0
18! = 0
19! = 0
20! = 0
21! = 0
22! = 0
23! = 0
24! = 0
25! = 0
26! = 0
27! = 0
28! = 0
29! = 0
30! = 0
31! = 0
32! = 0
33! = 0
34! = 0
35! = 0
36! = 0
37! = 0
38! = 0
39! = 0

如您所見,我最多可以計算14! 這樣而不是12! ...

此外,您正在使用遞歸計算階乘......迭代要好得多,除非您實現快速階乘,如果沒有大整數就沒有意義。

可以使用int在 Java 中計算的最大階乘是 12. = 479001600, (12, = 479.001,600)。

這是一些代碼來測試:

public static void factorialTest () {
    int i = 0, r = 1;
    
    while (r > 0) { 
        r = factorial (i);
        System.out.println ((i++) + "! = " + r);
    }
}  

public static int factorial(int n) {
    if (n < 0) {  return -1;  }
    if (n == 0 || n == 1) { return 1; }
    int r = 1;
    try {
        for (int i = 1; i <= n; ++i) {
            r = Math.multiplyExact (r, i);
        }
    } catch (ArithmeticException ex) {
        return -2;
    }
    return r;
}

如果傳遞負數,方法public static int factorial(int n)返回-1 ,如果n的值會導致計算的數字可能溢出int ,則返回-2

Java 中的 Integer 計算可以溢出而不產生異常。 如果計算結果太大,則結果“環繞”。 有時,需要檢測溢出。 為了支持這一點,Java Math API有許多~Exact方法。 當發生溢出時,它們會拋出ArithmeticException

所以,這里的想法是計算 integer 階乘,從 1 開始,遞增直到捕獲到溢出,使用try... catch

可以想象,這可以在不使用try... catch的情況下通過測試乘法結果小於先前結果的結果來完成。 由於結果序列是嚴格遞增的,因此在結果序列中找到較小的值將表明發生了回繞。 然而,這是不可靠的:計算可能會回繞,但仍會產生比先前結果更大的不正確結果。

在 Java 中使用long可以計算出的最大階乘是 20. = 2432902008176640000,即 20,= 2,432,902,008,176.640,000。 可以通過將上面代碼中的所有int更改為long來測試這一點。

注釋:雖然 Java 不允許聲明unsigned integer 類型,但無符號 integer 計算是可能的。 對無符號計算的支持包括結果環繞的計算和無符號方法,例如toUnsignedString 然而,這似乎與本次討論無關,因為計算 13! 會溢出unsigned int和 21 的計算! 會溢出unsigned long

評論:O/P 使用遞歸來計算階乘。 我使用了迭代。 雖然我是遞歸的粉絲,但當迭代解決方案很容易找到和實現時,我更喜歡使用迭代。 遞歸可以使用比迭代更多的開銷。

評論:優化編譯器有時會將使用遞歸的代碼更改為使用迭代。 O/P 的代碼中可能就是這種情況。

Output,使用long

0! = 1
1! = 1
2! = 2
3! = 6
4! = 24
5! = 120
6! = 720
7! = 5040
8! = 40320
9! = 362880
10! = 3628800
11! = 39916800
12! = 479001600
13! = 6227020800
14! = 87178291200
15! = 1307674368000
16! = 20922789888000
17! = 355687428096000
18! = 6402373705728000
19! = 121645100408832000
20! = 2432902008176640000
21! = -2

理論上,Java 最多支持 2^MAXINT-1 的階乘。 顯然,這是一個非常瘋狂的數字。 特定的 JVM,根據它們的實現,可能支持更大的值,但這不是語言規范所要求的。

這是您能夠裝入 BigInteger 的最高值。 您是否真的可以計算出那么高的數字,這顯然取決於您 go 如何進行該計算以及您手頭有多少時間來執行計算。

來自 JDK API 文檔:

當為任何輸入參數傳遞 null object 引用時,此 class 中的所有方法和構造函數都會拋出 NullPointerException。 BigInteger 必須支持 -2Integer.MAX_VALUE(不包括)到 +2Integer.MAX_VALUE(不包括)范圍內的值,並且可以支持該范圍之外的值。 當 BigInteger 構造函數或方法生成超出支持范圍的值時,將拋出 ArithmeticException。

請參閱 Java™ 語言規范:4.2.2 Integer 操作

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM