为什么除法结果会根据演员类型而有所不同?

时间:2014-09-06 18:11:48

标签: c# rounding integer-division

这是我不理解的代码的一部分:

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

为什么前两个计算被一个人关闭?我应该如何执行此操作,以便快速正确?

编辑:我需要字节

的结果

3 个答案:

答案 0 :(得分:6)

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

舍入问题:通过转换为byte / int,您将剪切小数位。

但是64 / 0.8不应该导致任何小数位?错误:由于浮点数的性质,0.8f不能完全像内存中的那样表示;它被存储为接近0.8f的东西(但不完全是)。请参阅Floating point inaccuracy examples或类似的主题。因此,计算结果不是80.0f,而是79.xxx,其中xxx接近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 :(得分:5)

在这种情况下,我担心快速和正确是不一致的。

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

简单地将结果转换为byteint等类型不会进行舍入 - 它只会切断小数部分(即使1.99999f也会变为1当你把它投射到这些类型时)。

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

the MidpointRounding strategy you expect是:

  • 如果您正在处理确切的数量(通常是人为的,如金钱),请使用decimal
  • 如果您处理的是不精确的数量(如分数物理常数或π等无理数),请使用double
  • 如果您处理的是不精确的数量(如上所述),并且可以进一步牺牲一些准确性(例如使用图形时),请使用float

答案 2 :(得分:3)

要理解这个问题,您需要了解浮点表示和操作的基础知识。

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

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

将float转换为整数或字节时,只保留数字的整数部分。在你的情况下,浮点除法的不精确结果略小于80,因此转换为整数得到79.

如果您需要整数结果,我建议您对结果进行舍入而不是对其进行舍入。 一种方法是使用以下函数,通过舍入到最接近的整数来转换为整数:

Convert.ToInt32(64/0.8f);