これを行うとき:
int x = 100;
int result = 1;
for (int i = 1; i < (x + 1); i++) {
result = (result * i);
}
System.out.println(result);
これは明らかに、結果が整数に対して大きすぎるためですが、私はオーバーフローに対して0ではなく大きな負の数を取得することに慣れています。
前もって感謝します!
これに切り替えると:
int x = 100;
int result = 1;
for (int i = 1; i < (x + 1); i++) {
result = (result * i);
System.out.println(result);
}
this を取得します。
大きな負の数は、特定の範囲にオーバーフローした値です。 factorial(100)
の末尾には32を超えるバイナリゼロがあるため、整数に変換するとゼロが生成されます。
1から100までの50の偶数があります。これは、階乗が少なくとも50回2の倍数であることを意味します。つまり、2進数として、最後の50ビットは0になります(実際には、2番目の偶数が2 * 2の倍数であるなど)。
public static void main(String... args) {
BigInteger fact = fact(100);
System.out.println("fact(100) = " + fact);
System.out.println("fact(100).longValue() = " + fact.longValue());
System.out.println("fact(100).intValue() = " + fact.intValue());
int powerOfTwoCount = 0;
BigInteger two = BigInteger.valueOf(2);
while (fact.compareTo(BigInteger.ZERO) > 0 && fact.mod(two).equals(BigInteger.ZERO)) {
powerOfTwoCount++;
fact = fact.divide(two);
}
System.out.println("fact(100) powers of two = " + powerOfTwoCount);
}
private static BigInteger fact(long n) {
BigInteger result = BigInteger.ONE;
for (long i = 2; i <= n; i++)
result = result.multiply(BigInteger.valueOf(i));
return result;
}
プリント
fact(100) = 93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
fact(100).longValue() = 0
fact(100).intValue() = 0
fact(100) powers of two = 97
これは、fact(100)の最下位ビットでは97ビット整数が0になることを意味します。
実際、fact(n)の2の累乗の数はnに非常に近いです。 fact(10000)の場合、9995の2の累乗があります。これは、それがおよそ1/2のn乗の合計であり、合計がn
に近いためです。つまり、2つおきの数はn/2であり、4つおきには2(+ n/4)の追加の累乗があり、8つおきには追加の累乗(+ n/8)があり、合計としてn
に近づきます。
原因を調べるために、階乗の素因数分解を観察することができました。
_fac( 1) = 1 = 2^0
fac( 2) = 2 = 2^1
fac( 3) = 2 * 3 = 2^1 * 3
fac( 4) = 2 * 2 * 2 * 3 = 2^3 * 3
fac( 5) = ... = 2^3 * 3 * 5
fac( 6) = ... = 2^4 * 3^2 * 5
fac( 7) = ... = 2^4 * ...
fac( 8) = ... = 2^7 * ...
fac( 9) = ... = 2^7 * ...
fac(10) = ... = 2^8 * ...
fac(11) = ... = 2^8 * ...
...
fac(29) = ... = 2^25 * ...
fac(30) = ... = 2^26 * ...
fac(31) = ... = 2^26 * ...
fac(32) = ... = 2^31 * ...
fac(33) = ... = 2^31 * ...
fac(34) = ... = 2^32 * ... <===
fac(35) = ... = 2^32 * ...
fac(36) = ... = 2^34 * ...
...
fac(95) = ... = 2^88 * ...
fac(96) = ... = 2^93 * ...
fac(97) = ... = 2^93 * ...
fac(98) = ... = 2^94 * ...
fac(99) = ... = 2^94 * ...
fac(100)= ... = 2^96 * ...
_
_2
_の指数は、基数2ビューの後続ゼロの数です。これは、他のすべての要因が奇数であるため、最後の2進数の_1
_が製品に寄与するためです。
同様のスキームは他の素数でも機能するため、fac(100)
の因数分解を簡単に計算できます。
_fac(100) = 2^96 * 3^48 * 5^24 * 7^16 * 11^9 * 13^7 * 17^5 * 19^5 * 23^4 *
29^3 * 31^2 * 37^2 * 41^2 * 43^2 * 47^2 *
53 * 59 * 61 * 67 * 71 * 73 * 79 * 83 * 89 * 97
_
したがって、コンピューターが基数3に数値を格納し、48トリット数を持っている場合、fac(100)
は0になります(fac(99)
としても、fac(98)
しません:-)
素晴らしい問題-答えは次のとおりです。33の階乗(負の値による)は-2147483648
です。これは0x80000000
、または64ビットを取る場合は0xFFFFFFFF80000000
です。 34(次のメンバー)を掛けると、0xFFFFFFE600000000
の長い値が得られます。これをintにキャストすると、0x00000000
が得られます。
明らかに、その時点以降は0のままになります。
再帰とBigIntegersを使用した簡単なソリューション:
public static BigInteger factorial(int num){
if (num<=1)
return BigInteger.ONE;
else
return factorial(num-1).multiply(BigInteger.valueOf(num));
}
出力:
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
JavaのBigIntegerクラス。 BigIntegerクラスは、使用可能なすべてのプリミティブデータ型の制限外にある非常に大きな整数計算を含む数学演算に使用されます。
非常に大きな数を計算するには、BigIntegerを使用できます。
たとえば、45の階乗を計算する場合は、回答= 119622220865480194561963161495657715064383733760000000000
static void extraLongFactorials(int n) {
BigInteger fact = BigInteger.ONE;
for(int i=2; i<=n; i++){
fact = fact.multiply(BigInteger.valueOf(i));
}
System.out.println(fact);
}
BigIntegerの主なメソッドは、BigInteger.ONE、BigInteger.ZERO、BigInteger.TEN、BigInteger.ValueOf()です。
(見つかった ここ 、質問に合うようにわずかに適応)
public static void main(String[] args) {
BigInteger fact = BigInteger.valueOf(1);
for (int i = 1; i <= 100; i++)
fact = fact.multiply(BigInteger.valueOf(i));
System.out.println(fact);
}
import Java.util.*;
import Java.math.*;
public class BigInteger_Factorial {
public static void main(String args []){
Scanner s = new Scanner(System.in);
BigInteger x,i,fac = new BigInteger("1");
x = s.nextBigInteger();
for(i=new BigInteger("1"); i.compareTo(x)<=0; i=i.add(BigInteger.ONE)){
fac = fac.multiply((i));
}
System.out.println(fac);
}
}
入力としての100の出力:
93326215443944152681699238856266700490715968264381621468592963895217599993229915608941463976156518286253697920827223758251185210916864000000000000000000000000
出力画像: