我不知道为什么 Ceiling 的行为会像下面的图片所示。
为什么 processingFee 不等于 Settings.PaymentProcessingFeeInPercentage * prizesSum ?
备用文字 http://img514.imageshack.us/img514/3950/csharpceilingproblem.png
我不知道为什么 Ceiling 的行为会像下面的图片所示。
为什么 processingFee 不等于 Settings.PaymentProcessingFeeInPercentage * prizesSum ?
备用文字 http://img514.imageshack.us/img514/3950/csharpceilingproblem.png
你的百分比实际上不是为0.05,而是一个接近于0.05的值......并且可能略大于0.05。因此当它乘以2600时,你得到的值略大于130.0......然后被"ceilinged"(向上取整)到131.0。
使用我写过的一个小工具(可从此页面了解 .NET 二进制浮点类型),看起来最接近0.05的实际float
值为0.0500000007450580596923828125。对于双精度数,则为0.05000000000000000277555756156289135105907917022705078125。
故事的寓意:不要为此类事情使用float
——使用decimal
。或者,如果你只想表示百分比,并且实际上只需要精确到1%,则使用0-100的整数值即可。
double
,它和 float
有同样的问题。decimal
避免这些问题的原因是它是基于十进制浮点数,而不是基于二进制浮点数。一般来说,对于处理货币,decimal
将是最安全的选择,因为 decimal
的内部表示与您尝试表示的内容相匹配(尽管效率较低)。 - Brian0.05
稍微大于 0.05
,因此乘积稍微大于 130.0
。Math.Ceiling
向上舍入。float
和 double
更改为 decimal
。这是由于浮点数的内部存储格式在十进制表示时本质上是不精确的。在 Stack Overflow 上有很多关于此问题的提问。
你返回的数字可能类似于 130.000000000000001,因为你的计算中的数字无法准确地表示为二进制浮点数。
在我看来,这可能与浮点精度有关。换句话说,2600 × 0.05 的结果是130.0000...001而不是130。
如果您先尝试将结果四舍五入,然后调用Math.Ceiling
会怎样呢?
如果您在大型银行操作中使用浮点数,请不要让我把我的钱漂浮在您的银行里。请使用最小公分母的整数或小数。
但是,如果您对计算量的大小有所假设,可以使用 Math.Round
来帮助您使用 double
或 float
。
double processingFee = Math.Ceiling( Math.Round(
Settings.PaymentProcessingFeeInPercentage * prizesSum, 2 ) );
decimal
仍然是浮点类型。它只是一个浮动的十进制点而不是一个浮动的二进制点。 - Jon Skeet