C#和漂浮物的恶作剧

ala*_*ere 1 c# floating-point rounding

在测试为什么我的程序没有按预期工作时,我尝试输入似乎未能进入即时窗口的计算.

Math.Floor(1.0f)
1.0 - correct
Run Code Online (Sandbox Code Playgroud)

然而:

200f * 0.005f
1.0

Math.Floor(200f * 0.005f)
0.0 - incorrect
Run Code Online (Sandbox Code Playgroud)

此外:

(float)(200f * 0.005f)
1.0

Math.Floor((float)(200f * 0.005f))
0.0 - incorrect
Run Code Online (Sandbox Code Playgroud)

可能发生一些浮动损失,例如0.99963≠1.00127.

我不介意存储较少的pricise值,但是以非损耗的方式,例如,如果有一个数值类型将值存储为整数,但是只有三个小数位,如果它可以是高性能的.

我想可能有更好的方法来计算(n*0.005f)这样的错误.

编辑:

TY,解决方案:

Math.Floor(200m * 0.005m)
Run Code Online (Sandbox Code Playgroud)

另外,据我所知,如果我不介意将1/200更改为1/256,这将有效:

Math.Floor(200f * 0.00390625f)
Run Code Online (Sandbox Code Playgroud)

我正在使用的解决方案.它是我能在程序中得到的最接近的,似乎工作正常:

float x = ...;
UInt16 n = 200;
decimal d = 1m / n;
... = Math.Floor((decimal)x * d)
Run Code Online (Sandbox Code Playgroud)

Eri*_*ert 13

Floats将数字表示为分母中具有2的幂的分数.也就是说,您可以准确地表示1/2,或3/4或19/256.由于.005是1/200,而200不是2的幂,相反,你得到的0.005f是底部能够容纳32位浮点数的最接近的分数.

小数表示数字为分母中具有10的幂的分数.与浮点数一样,当您尝试表示不符合该模式的数字时,它们会引入错误.1m/333m例如,将给出最接近1/333的数字,其中10的幂为分母,有效数字为29或更少.由于0.005是5/1000,即10的幂,0.005m将为您提供精确的表示.您支付的价格是小数字比浮点数大得多且慢.

您应该始终始终使用小数进行财务计算,从不浮动.

  • @phoog:最后,小数上的算术成为应用程序的瓶颈是很少见的,所以使用双精度因为它们更快就是过早的优化.在汇编中编写一个Forms-over-data GUI应用程序,因为它更快听起来很荒谬?虽然这是过早优化的极端情况,但同样的基本逻辑应适用于此. (2认同)

Jon*_*eet 6

问题是0.005f 实际上是 0.004999999888241291046142578125 ......所以小于0.005.这是最接近float0.005的值.当你乘以200时,你得到的东西少于1.

如果你一直使用decimal- 而不是从中转换float- 你应该在这个特定场景中没问题.所以:

decimal x = 0.005m;
decimal y = 200m;
decimal z = x * y;
Console.WriteLine(z == 1m); // True
Run Code Online (Sandbox Code Playgroud)

但是,不要认为这意味着decimal"无限精度".它仍然是一个精度有限的浮点类型 - 它只是一个浮点小数点类型,所以0.005是完全可表示的.