这感觉像是那种只会在原地失败的代码,但我会尝试将其改编成代表我所看到内容的代码片段。

float f = myFloat * myConstInt; /* Where myFloat==13.45, and myConstInt==20 */
int i = (int)f;
int i2 = (int)(myFloat * myConstInt);

单步执行代码后,i==269,i2==268。这里发生了什么来解释这种差异?

有帮助吗?

解决方案

浮点数学的执行精度比宣传的要高。但一旦将其存储在 float f 中,额外的精度就会丢失。当然,除非您将结果转换为 int,否则您不会失去第二种方法的精度。

编辑:看到这个问题 为什么 C# 中用括号分隔和用语句分隔时浮点精度不同? 以获得比我可能提供的更好的解释。

其他提示

由于浮点变量不是无限准确。如果你需要那种精确的使用十进制。

舍入模式也可起到这个问题,但精度的问题是您正在运行到这里的人,据我所知。

浮点的精确度有限,并且是基于二进制的,而不是小数。十进制数13.45不能以二进制浮点精确表示,因此回合下来。由20乘法进一步夸大的精度损失。此时你有268.999 ... - 不269 - 因此转化为整数截断到268

要得到舍入到最接近的整数,则可以尝试转换回整数之前加入0.5

有关“完美”的算术,你可以尝试使用十进制或合理的数值类型 - 我相信C#有两个库,但我不能肯定。这些会慢一些,但

修改 - 我已经找到了“十进制”类型,到目前为止,但不是一个理性的 - 我可能是错了可用。十进制浮点不准确,就像二进制,但它是一种用来不精确我们,所以它给那么令人惊讶的结果。

替换为

double f = myFloat * myConstInt;

和看看你得到了相同的答案。

我想提供一个不同的解释。

这是我注释过的代码(我查看内存来剖析浮点数):

 float myFloat = 13.45; //In binary is 1101.01110011001100110011
 int myConstInt = 20;
 float f = myFloat * myConstInt; //In binary is exactly 100001101 (269 decimal)
 int i = (int)f; // Turns float 269 into int 269 -- no surprises
 int i2 = (int)(myFloat * myConstInt);//"Extra precision" causes round to 268

让我们仔细看看计算结果:

  • f = 1101.01110011001100110011 * 10100 = 100001100.111111111111111 111

    空格后面的部分是位 25-27,这会导致位 24 向上舍入,因此整个值向上舍入为 269

  • int i2 = (int)(myFloat * myConstInt)

    myfloat 扩展为双精度以进行计算(附加 0):1101.0111001100110011001100000000000000000000000000000

    myfloat * 20 = 100001100.11111111111111111100000000000000000000000000

    第 54 位及以上均为 0,因此不进行舍入:转换结果为整数 268。

    (如果使用扩展精度,类似的解释也会起作用。)

更新:我完善了我的答案并写了一篇完整的文章,名为 当浮点数的行为与浮点数不同时

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top