在测试为什么我的程序没有按预期工作时,我尝试在即时窗口中输入似乎失败的计算。
Math.Floor(1.0f)
1.0 - correct
但是:
200f * 0.005f
1.0
Math.Floor(200f * 0.005f)
0.0 - incorrect
此外:
(float)(200f * 0.005f)
1.0
Math.Floor((float)(200f * 0.005f))
0.0 - incorrect
可能会出现一些 float 损失,例如 0.99963 ≠ 1.00127。
我不介意存储较少的 pricise 值,但以一种无损的方式,例如,如果有一种数字类型可以像整数一样存储值,但只有小数点后三位,如果它可以提高性能的话。
我认为可能有更好的方法来计算此类错误的 (n * 0.005f)。
编辑:
TY,一个解决方案:
Math.Floor(200m * 0.005m)
此外,据我所知,如果我不介意将 1/200 更改为 1/256,这会起作用:
Math.Floor(200f * 0.00390625f)
我正在使用的解决方案。这是我能在我的程序中获得的最接近的并且似乎工作正常:
float x = ...;
UInt16 n = 200;
decimal d = 1m / n;
... = Math.Floor((decimal)x * d)
最佳答案
float 将数字表示为分母为 2 的幂的分数。也就是说,您可以准确表示 1/2、3/4 或 19/256。由于 .005 是 1/200,而 200 不是 2 的幂,因此您得到的 0.005f
是最接近底部的 2 的幂的分数,可以放入 32位 float 。
小数将数字表示为分母为 10 的幂的分数。与 float 一样,当您尝试表示不符合该模式的数字时,它们会引入错误。例如,1m/333m
将为您提供最接近 1/333 的数字,该数字的分母为 10 的幂,有效数字不超过 29 位。由于 0.005 是 5/1000,它是 10 的幂,0.005m
将为您提供精确的表示。您付出的代价是小数比 float 大得多且速度慢。
您应该始终始终使用小数进行财务计算,切勿使用 float 。
关于C# 和 float 的恶作剧,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10364817/