乘法时的十进制精度

Decimal precision when multiplying

提问人:Matt Warren 提问时间:1/3/2013 更新时间:1/3/2013 访问量:3117

问:

给定 2 个值,如下所示:

decimal a = 0.15m;
decimal b = 0.85m;

Where will always be ,这两个值都只指定为小数点后 2 位,并且两个值都是 和a + b1.0m>= 0.0m<= 1.0m

是否保证对于 和 的所有可能的十进制值始终为真?使用以下计算:x == totalxab

decimal x = 105.99m;
decimal total = (x * a) + (x * b);

还是只有小数点后 2 位,但不超过小数点?x == total

如果并且可以指定为无限的小数位(尽可能允许),但只要仍然成立,会有什么区别吗?abDecimala + b = 1.0m

C# .NET 十进制 精度

评论

0赞 Rotem 1/3/2013
指定到无限小数位是什么意思?不等于吗?0.85m0.8500000000000000m
0赞 Rawling 1/3/2013
@Rotem 二进制表示不同;我不确定当你乘以时它是否会导致行为差异。编辑:显然不是 - Trailing zeroes do not affect the value of a Decimal number in arithmetic or comparison operations
0赞 Rotem 1/3/2013
@Rawling 这个引用MSDN的答案是:stackoverflow.com/a/1132777/860585
1赞 poke 1/3/2013
@CubeSchrauber 你看过吗?检查底部和的示例输出。小数不像双精度/浮点数那样存储,而是使用以 10 为基数,这会产生巨大的差异。11.0000000000000000000000000000
1赞 poke 1/3/2013
@CubeSchrauber 你是认真的吗?!当然,它是以二进制形式存储的,因为一切都是(顺便说一句。 是十六进制的,而不是二进制的)。这并没有改变浮点数/双精度数和小数点在内部表示的方式。浮点数用 表示;这就是为什么它可以准确地表示 0.5 () 而不是 0.3。另一方面,小数点以 10 为基数表示,使用 ,因此如果 m 和 e 足够精确,我们可以精确表示所有小数,包括 0.3 ()。阅读 IEEE 754FF(-1)^s * m * 2^e1 * 2^-1(-1)^s * m * 10^e3 * 10^-1

答:

5赞 Charles Lambert 1/3/2013 #1

十进制存储为表示小数位置的数字 10 的符号、整数和整数指数。只要数字的整数部分(例如 105.99 中的 105)不够大,那么 a + b 将永远等于 1。您的等式 (x * a) + (x * b) 的结果将始终具有正确的小数点后四位值。

与浮点数和双精度值不同,精度不会丢失到数据类型的大小(128 位)

来自 MSDN:

Decimal value 类型表示范围为 正数 79,228,162,514,264,337,593,543,950,335 改为负数 79,228,162,514,264,337,593,543,950,335。 十进制值类型为 适用于需要大量 显著的整数和小数数字,无舍入误差。 Decimal 类型并不能消除舍入的需要。相反,它 最大限度地减少由于舍入而导致的错误。例如,以下代码 产生的结果为 0.999999999999999999999999999999999 而不是 1

decimal dividend = Decimal.One;
decimal divisor = 3;
// The following displays 0.9999999999999999999999999999 to the console
Console.WriteLine(dividend/divisor * divisor);
3赞 Roy Dictus 1/3/2013 #2

CLR 中的最大精度为 29 位有效数字。当您使用这种精度时,您实际上是在谈论近似值,尤其是在执行乘法运算时,因为这需要 CLR 必须能够处理的中间结果(另请参见 http://msdn.microsoft.com/en-us/library/364x0z75.aspx)。decimal

如果 x 有 2 个有效数字,比如说 a 有 20 个有效数字,那么 x * a 的最小精度已经为 22 位,中间结果可能需要更多精度。

如果 x 总是只有 2 个有效数字,并且您可以将 a 和 b 中的有效数字数量保持在足够低的水平(比如说,22 位数字——相当不错,并且可能离 27 足够远以处理舍入错误),那么我认为 (x * a) + (x * b) 应该始终是一个非常精确的计算。

最后,a+b是否总是构成1.0m与a和b的各自精度无关。