6

なぜ:

double dividend = 1.0;
double divisor = 3.0;
Console.WriteLine(dividend / divisor * divisor);

出力1.0、

しかし:

decimal dividend = 1;
decimal divisor = 3;
Console.WriteLine(dividend / divisor * divisor);

出力0.9999999999999999999999999999

?

1/3 を正確に計算できないことは理解しているので、丸めが必要です。しかし、Double では答えが 1.0 に丸められるのに、Decimal では丸められないのはなぜでしょうか?

また、double が 1.0/3.0 を 0.3333333333333331 と計算するのはなぜですか? 丸めが使用されている場合、最後の 3 は 0 に丸められません。なぜ 1 なのですか?

4

2 に答える 2

14

double としての 1/3 が 0.33333333333333331 である理由

1/3 を 2 進数で表す最も近い方法は次のようになります: 0.0101010101... これは級数 1/4 + (1/4)^2 + (1/4)^3 + (1/4)^ と同じです。 4...

もちろん、これは double に格納できるビット数によって制限されます。double は 64 ビットですが、そのうちの 1 つは符号ビットで、別の 11 は指数を表します (科学的表記法のように考えてください。ただし、2 進数です)。したがって、仮数または仮数と呼ばれる残りは52ビットです。最初に 1 を想定し、その後の 1/4 の累乗ごとに 2 ビットを使用します。つまり、保存できることを意味します: 1/4 + 1/4^2 + ... + 1/4 ^ 27 つまり 0.3333333333333331

3 を掛けると 1 に丸められる理由

したがって、1/3 は 2 進数で表され、double のサイズによって制限されます。私が言ったように、1 の後に始まるビットを保存し、指数と符号に別々のビットを使用します。しかし、基数 2 で実際にどのように記述するかを検討すると便利だと思います。

この「数学者のバイナリ」表現に固執し、double のサイズ制限を無視しましょう。このようにする必要はありませんが、便利だと思います。この近似値を 1/3 にして 3 を掛ける場合、それはビット シフトして 2 を掛けてから、元の値を加算するのと同じです。これにより、1/3 * 3 = 0.11111111111111111111111111111111111111111111111111 が得られます。

しかし、それを二重に保存できますか?いいえ、覚えておいてください、最初の 1 の後には 52 ビットの仮数しか持てず、その数には 54 個の 1 があります。したがって、丸められることがわかっています。この場合、正確に 1 に切り上げられます。

10 進数で 0.9999999999999999999999999999 を取得する理由

10 進数では、10 の 28 乗までの指数を表す追加のビットを使用して、整数を表す 96 ビットを取得します。したがって、最終的にはすべてバイナリとして格納されますが、ここでは 10 の累乗で作業しているので、考えるのは理にかなっています。基数 10 の数値の 96 ビットでは、最大 79,228,162,514,264,337,593,543,950,335 を表すことができますが、1/3 を表すには、小数点の右側にシフトできる最大 28 個までのすべての 3 を使用します。 0.333333333333333333333333333.

この 1/3 の近似値に 3 を掛けると、正確に表現できる数値が得られます。これはちょうど 28 個の 9 で、すべて小数点の右側にシフトされています: 0.999999999999999999999999999。double の場合とは異なり、この時点で丸めの 2 回目のラウンドはありません。

于 2013-03-11T04:21:39.367 に答える
-2

This is by design of the decimal type which is optimized for accuracy unlike the double type which is optimized for low accuracy but higher performance.

The Decimal value type represents decimal numbers ranging from positive 79,228,162,514,264,337,593,543,950,335 to negative 79,228,162,514,264,337,593,543,950,335.

The Decimal value type is appropriate for financial calculations requiring large numbers of significant integral and fractional digits and no round-off errors. The Decimal type does not eliminate the need for rounding. Rather, it minimizes errors due to rounding. Thus your code produces a result of 0.9999999999999999999999999999 rather than 1.

One reason that infinite decimals are a necessary extension of finite decimals is to represent fractions. Using long division, a simple division of integers like 1⁄9 becomes a recurring decimal, 0.111…, in which the digits repeat without end. This decimal yields a quick proof for 0.999… = 1. Multiplication of 9 times 1 produces 9 in each digit, so 9 × 0.111… equals 0.999… and 9 × 1⁄9 equals 1, so 0.999… = 1:

于 2013-03-11T05:01:10.097 に答える