2014-09-06 49 views
11

这里的,我不理解的代码部分:为什么划分结果会因演员阵容而异?

byte b1 = (byte)(64/0.8f); // b1 is 79 
int b2 = (int)(64/0.8f); // b2 is 79 
float fl = (64/0.8f); // fl is 80 

为什么前两个计算关闭的一个?我应该如何执行这个操作,所以它的快速和正确?

编辑:我需要在字节

+0

我编辑了自己的冠军。请参阅:“[应该在其标题中包含”标签“](http://meta.stackexchange.com/questions/19190/)”,其中的共识是“不,他们不应该”。 – 2014-09-06 18:24:47

+0

Jon Skeet的这篇文章应该涵盖你的问题:http://csharpindepth.com/articles/general/floatingpoint.aspx – Warlock 2014-09-06 19:02:20

回答

6

编辑:不完全正确,请参阅:Why does a division result differ based on the cast type? (Followup)

四舍五入问题:通过转换为字节/ INT,你剪辑的小数位。

64/0.8不应该导致任何小数位?错误:由于浮点数的性质,0.8f不能完全像内存中那样表示;它被存储为接近0.8f(但不完全)。见Floating point inaccuracy examples或类似的线程。因此,计算结果不是80.0f,而是79.xxx,其中xxx接近于1,但仍不完全为1。

您可以通过键入以下到即时窗口在Visual Studio中验证这一点:

(64/0.8f) 
80.0 
(64/0.8f) - 80 
-0.0000011920929 
100 * 0.8f - 80 
0.0000011920929 

您可以通过使用四舍五入解决这个问题:

byte b1 = (byte)(64/0.8f + 0.5f); 
int b2 = (int)(64/0.8f + 0.5f); 
float fl = (64/0.8f); 
+1

80.0f可以表示得很好。然而,0.8f不能,所以你实际上并没有得到80.0f。 – harold 2014-09-06 18:30:33

+0

感谢您的追捕 - 我相应地解决了我的问题。 – Matthias 2014-09-06 18:36:13

+1

请查看我的后续问题:http://stackoverflow.com/questions/25703864/why-does-a-division-result-differ-based-on-the-cast-type-followup我得到了二进制(64/0.8f)并反向工作,它确实等于80。 – ConditionRacer 2014-09-06 19:39:26

3

结果要理解这个问题,你需要了解浮点表示和操作的基本知识。

0.8f不能在内存中使用浮点数精确表示。

在数学中,64/0.8等于80 在浮点算术,60/0.8等于近似80

当你施放一个浮子的整数或一个字节,仅数的整数部分是保持。在你的情况下,浮点除法的不精确结果略小于80,因此转换为整数产生79.

如果你需要一个整数结果,我建议你四舍五入而不是转换结果。 一种方式来做到这一点是使用下面的函数,通过四舍五入到最接近的整数转换为整数:

Convert.ToInt32(64/0.8f); 
5

恐怕快速和正确正处在这样的情况下胜算。

由于the underlying representation in our CPU architectures,二进制浮点运算几乎总是会产生小的错误。所以在你的初始表达式中,你实际上得到的值比数学上正确的值小一点。如果你期望一个整数作为特定数学运算的结果,并且你得到了一个非常接近的数字,你可以使用Math.Round(Double, MidpointRounding)方法来执行正确的舍入并弥补小错误(并确保你选择了the MidpointRounding strategy you expect)。

简单铸造结果的类型,如byteint不做四舍五入 - 它只是切断小数部分(甚至1.99999f将成为1当你只是将它转换为这些类型)。

十进制浮点运算速度较慢且内存密集程度较高,但不会导致这些错误。要执行此操作,请使用文字decimal而不是float(例如64/0.8m)。

The rule of thumb是:

  • 如果你正在处理的确切数量(通常是人造的,如金钱),使用decimal
  • 如果您处理的是不精确数量(如分数物理常数或像π这样的无理数),请使用double
  • 如果您处理的是不精确的数量(如上所述),并且速度可能会进一步牺牲一些精度(例如使用图形时),请使用float