階乗を解決するアプリケーションを作成しましたが、変数に 20 桁を超える数値を入力するとlong
、負の数値が返されます。long
C# の変数が制限を超えたときに負の値を返す理由を知りたいですか? こんなはずじゃないの?
8 に答える
これは、オーバーフローと呼ばれる非常に正常な動作です。
最初のステップとして、それをエラーに変えます
checked
{
// your calculations
}
そして、この本には、すべてのビットとバイトを含む完全な説明があります.
これは、それを理解するのに役立つかもしれません:
static void Main2(string[] args)
{
short s = 0;
Console.WriteLine("Dec: {0,6} Hex {0:X4}", s);
s -= 1;
Console.WriteLine("Dec: {0,6} Hex {0:X4}", s);
s = short.MaxValue;
Console.WriteLine("Dec: {0,6} Hex {0:X4}", s);
s += 1;
Console.WriteLine("Dec: {0,6} Hex {0:X4}", s);
Console.WriteLine(s == short.MinValue); // is MaxValue+1 == MinValue ?
}
印刷します
Dec: 0 Hex 0000
Dec: -1 Hex FFFF
Dec: 32767 Hex 7FFF
Dec: -32768 Hex 8000
True
16 進文字をビットとして読み取る:
0 = 0000
1 = 0001
7 = 0111
8 = 1000
F = 1111
最上位 (左端) ビットが+/-
符号として使用されていることがわかります。
なぜ負になるのかは誰もがすでに述べているので、階乗関数を変更する方法を説明します。BigIntegerを使用します (.NET 4.0 を使用していると仮定します)。
static BigInteger Factorial(BigInteger bigInt) {
if (bigInt == 0) {
return 0;
}
else if (bigInt == 1) {
return 1;
}
else {
return bigInt * Factorial(bigInt - 1);
}
}
これは算術オーバーフローと呼ばれます。
4 ビットの例:
1101
+0101
-----
10010
ご覧のとおり、正解には 5 ビットが必要ですが、これを 4 ビットに格納するにはどうすればよいでしょうか?! オーバーフローが発生する必要があります。
直接の質問に答えるために、値は署名されているため負になり、オーバーフローすると下限にラップアラウンドします。
c# のすべての数値型は max 関数をサポートしているため、Long.MaxValueで制限がわかります。2 の補数でエンコードされた数値の上位ビットの設定に関係する負の値になる理由については、
long
データ型にはMSDNリファレンスがあります。基本的に、あなたが私たちに伝えていることは、すべての話ではありません。この長い上限は9.223372037x10^18
であり、階乗の 20 は2.432902008x10^18
の上限よりも小さいですlong
。
実際に何が起こっているかを確認できるように、いくつかのコードを投稿します。
この種のオーバーフローが望ましくない場合は、 の使用を検討してBigInteger
ください。これを使用するには、C# プロジェクトに .NET アセンブリへの参照を含める必要がありますSystem.Numerics.dll
。そして、コードファイルに含める必要があります
using System.Numerics;
上に。
はい、21です!長い制限よりも素晴らしいですが、20! ではありません。このように溢れています。