我刚用LINQPad进行了测试:
你能解释一下天花板方法为何如此反应?请注意中间的123.12。
Math.Ceiling(123.121 * 100) / 100 'display 123.13
Math.Ceiling(123.1200000000001 * 100) / 100 'display 123.13
Math.Ceiling(123.12000000000001 * 100) / 100 'display 123.12
Math.Ceiling(123.12000000000002 * 100) / 100 'display 123.13
我在VB.NET中进行了测试,但它在C#中应该是相同的。
答案 0 :(得分:2)
这是浮点舍入。 C#将123.12000000000001和123.12解析为具有相同的值。 123.12000000000002被解析为下一个可用的双精度。
var bytes = BitConverter.ToString(BitConverter.GetBytes(123.12));
// outputs 48-E1-7A-14-AE-C7-5E-40
var bytes1 = BitConverter.ToString(BitConverter.GetBytes(123.12000000000001));
// outputs 48-E1-7A-14-AE-C7-5E-40
var bytes2 = BitConverter.ToString(BitConverter.GetBytes(123.12000000000002));
// outputs 49-E1-7A-14-AE-C7-5E-40
答案 1 :(得分:0)
这是由于浮点舍入而不是Math.Ceiling 本身,这是因为浮点值不能以100%的准确度表示所有值。
无论如何,你的例子有点人为,因为如果你试图在visual studio中输入123.12000000000001
,则将其更改为123.12
,因为它知道该值不能表示为double。
在此处阅读:What Every Computer Scientist Should Know About Floating-Point Arithmetic(顺便说一下,这不是特定于.NET)
要修复您的问题,您可以使用小数值而不是双精度值。 Math.Ceiling有一个接受十进制的重载(所有这些都显示123.13):
Debug.WriteLine(Math.Ceiling(123.121D * 100) / 100)
Debug.WriteLine(Math.Ceiling(123.1200000000001D * 100) / 100)
Debug.WriteLine(Math.Ceiling(123.12000000000001D * 100) / 100)
Debug.WriteLine(Math.Ceiling(123.12000000000002D * 100) / 100)
此修复程序当然是否合适取决于您需要的准确度。
答案 2 :(得分:0)
Ceiling
如果是整数,则返回传递给它的数字,否则返回下一个最高整数。因此5.0
保持5.0
但5.00001
变为6.0
。
因此,在以下示例中,以下内容显而易见:
Math.Ceiling(123.121 * 100) / 100 // Obtain 12312.1, next highest is 12313.0, then divide by 100 is 123.13
Math.Ceiling(123.1200000000001 * 100) / 100 // Likewise
Math.Ceiling(123.12000000000002 * 100) / 100 // Likewise
更令人困惑的是:
Math.Ceiling(123.12000000000001 * 100) / 100 //display 123.12
但是,让我们来看看:
123.12000000000001 * 100 - 12312.0 // returns 0
与:相比:
123.1200000000001 * 100 - 12312.0 // returns 1.09139364212751E-11
123.12000000000002 * 100 - 12312.0 // returns 1.81898940354586E-12
后两次乘法的结果略高于12312.0,因此当(123.12000000000002 * 100).ToString()
返回"12312"
时,123.12000000000002 * 100
生成的实际数字在数学上12312.000000000002
最近的double
{ {1}} 123.12000000000002
的{1}}是123.1200000000000181898940354586
,这就是正在进行的工作。
如果您习惯于只进行十进制算术,123.12000000000002
被“舍入”到123.1200000000000181898940354586
似乎很奇怪,但请记住,这些数字是以二进制值的形式存储的,舍入取决于你工作的基地。
因此虽然字符串表示没有表明它,但确实略高于12312
,因此其上限为12313
。
同时使用123.12000000000001 * 100
,数学上为12312.000000000001
,但最接近double
到123.12000000000001
的是它可以容纳的123.12
。这就是用于乘法的内容,当结果传递给后续调用Ceiling()
时,其结果为12312
。
答案 3 :(得分:-1)
Ceiling方法返回下一个更高的等效整数。
所以天花板(123.01)= 124
&安培;天花板(123.0)= 123