C# 和 float 的恶作剧

标签 c# floating-point rounding

在测试为什么我的程序没有按预期工作时,我尝试在即时窗口中输入似乎失败的计算。

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/

相关文章:

c++ - 我怎样才能得到 double 值?

python - 在 Python 中,整数除法中向零舍入的好方法是什么?

C# - 将十进制转换为 int32

c# - winform 应用程序中的按钮文本

math - float 学坏了吗?

php - 为什么在 PHP 中 NAN 不等于除 true 之外的所有内容?

mysql - 坐标为主键

c# - gridview 行中的 jQuery 确认对话框始终回发

javascript - 访问 NestedViewTemplate 中的子 RadGrid 页脚

C# : Direct3D in a control, 和辅助监视器上的全屏 - 最好的方法是什么?