C#十进制乘法奇怪的行为

use*_*360 34 c# decimal multiplication

在C#中乘以十进制值时,我注意到一种奇怪的行为.考虑以下乘法运算:

1.1111111111111111111111111111m * 1m = 1.1111111111111111111111111111 // OK
1.1111111111111111111111111111m * 2m = 2.2222222222222222222222222222 // OK
1.1111111111111111111111111111m * 3m = 3.3333333333333333333333333333 // OK
1.1111111111111111111111111111m * 4m = 4.4444444444444444444444444444 // OK
1.1111111111111111111111111111m * 5m = 5.5555555555555555555555555555 // OK
1.1111111111111111111111111111m * 6m = 6.6666666666666666666666666666 // OK
1.1111111111111111111111111111m * 7m = 7.7777777777777777777777777777 // OK
1.1111111111111111111111111111m * 8m = 8.888888888888888888888888889  // Why not 8.8888888888888888888888888888 ?
1.1111111111111111111111111111m * 9m = 10.000000000000000000000000000 // Why not 9.9999999999999999999999999999 ?
Run Code Online (Sandbox Code Playgroud)

我无法理解的是上述最后两个案例.怎么可能?

Jon*_*eet 73

decimal存储28或29位有效数字(96位).基本上尾数在 - /+ 79,228,162,514,264,337,593,543,950,335范围内.

这意味着高达约7.9 ....你可以准确地得到29位有效数字 - 但高于你不能.这就是8和9都出错的原因,但不是早期的价值观.一般来说,你应该只依赖 28位有效数字,以避免像这样的奇怪情况.

将原始输入减少到28位有效数字后,您将获得预期的输出:

using System;

class Test
{
    static void Main()
    {
        var input = 1.111111111111111111111111111m;
        for (int i = 1; i < 10; i++)
        {
            decimal output = input * (decimal) i;
            Console.WriteLine(output);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)