C# 为什么除法结果因类型而异?

C# 为什么除法结果因类型而异?,c#,rounding,integer-division,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 为什么前两次计算结果相差一倍?我应该如何执行此操作,使其快速正确 编辑:我需要字节的结果来理解这个问题,你需要了解浮点表示和运算的基础知识 0.8f不能在内存中使用浮点数精确表示 在数学中,64/0.8等于80。 在浮点算术中,60/0.

以下是我不理解的部分代码:

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.8f不能在内存中使用浮点数精确表示

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

将浮点转换为整数或字节时,只保留数字的整数部分。在您的例子中,浮点除法的不精确结果略小于80,因此转换为整数的结果为79

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

Convert.ToInt32(64/0.8f);

恐怕在这种情况下,快速和正确是不一致的

二进制浮点运算几乎总是产生小的错误,这是由于。所以在初始表达式中,实际上得到的值比数学上正确的值小一点。如果您期望某个特定数学运算的结果是一个整数,并且您得到了非常接近它的结果,那么您可以使用该方法执行正确的舍入并补偿小错误(并确保拾取)

简单地将结果转换为一个类型,例如
byte
int
不会进行舍入-它只会切断小数部分(即使是
1.9999f
当您将其转换为这些类型时,也会变成
1

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

是:

  • 如果你处理的是精确的数量(通常是人为的,如货币),请使用
    decimal
  • 如果处理的是不精确量(如分数物理常数或π等无理数),请使用
    double
  • 如果您处理的是不精确的数量(如上所述),并且速度可能会进一步牺牲某些精度(如处理图形时),请使用
    float

编辑:不完全正确,请参阅:

四舍五入问题:通过转换为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
您可以通过使用舍入来解决此问题:

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

我已经编辑了你的标题。请参阅“”,其中的共识是“不,他们不应该”。Jon Skeet的这篇文章应该涵盖您的问题:80.0f可以很好地表示。但是,0.8f不能,所以你一开始并没有得到80.0f。谢谢你抓住了这个问题-我相应地修正了我的答案。请检查我的后续问题:我得到了(64/0.8f)的二进制数,并反向计算,它实际上正好等于80。