相乘时的十进制精度

本文关键字:十进制 精度 | 更新日期: 2023-09-27 17:50:37

给定如下2个值:

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

其中a + b总是1.0m,两个值都只指定到小数点后2位,并且两个值都是>= 0.0m<= 1.0m

是否保证对于x, ab的所有可能的十进制值,x == total总是为真?使用下面的计算:

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

或者x == total只到小数点后2位,但不超过2位?

如果ab可以被指定为无限的小数点(只要Decimal允许),但只要a + b = 1.0m仍然有效,会有什么不同吗?

相乘时的十进制精度

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

与float和double不同,精度不会丢失,直到数据类型的大小(128位)

从MSDN:

Decimal值类型表示从正79,228,162,514,264,337,593,543,950,335到负79228162514264337593543950335年。十进制值类型为适用于需要大量的财务计算有效的整数和小数,没有四舍五入错误。Decimal类型并不能消除舍入的需要。相反,它最小化舍入误差。例如,下面的代码产生的结果是0.9999999999999999999999999999999999而不是1

decimal dividend = Decimal.One;
decimal divisor = 3;
// The following displays 0.9999999999999999999999999999 to the console
Console.WriteLine(dividend/divisor * divisor);

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

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

如果x总是只有2位有效数字,并且你可以将a和b中的有效数字保持得足够低(例如,22位——很好,可能离27足够远,可以处理舍入误差),那么我认为(x * a) + (x * b)应该总是一个相当精确的计算。

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