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

syd*_*ydd 11 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
Run Code Online (Sandbox Code Playgroud)

为什么前两个计算一个一个?我应该如何执行此操作,所以它快速而正确?

编辑:我需要字节结果

Mat*_*ias 6

编辑:不完全正确,请参阅:为什么除法结果会根据演员类型而有所不同?(跟进)

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

但是64 / 0.8不应该导致任何小数位?错误:由于浮点数的性质,0.8f不能完全像内存中的那样表示; 它被存储为接近0.8f的东西(但不完全是).请参阅浮点不准确示例或类似线程.因此,计算结果不是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
Run Code Online (Sandbox Code Playgroud)

你可以通过使用舍入来解决这个问题:

byte b1 = (byte)(64 / 0.8f + 0.5f);
int b2 = (int)(64 / 0.8f + 0.5f);
float fl = (64 / 0.8f);
Run Code Online (Sandbox Code Playgroud)


The*_*kis 5

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

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

简单地将结果转换为类型byteint不进行舍入的类型 - 它只是切断小数部分(甚至在您将它转换为这些类型时1.99999f也会成为1).

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

经验法则是:

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