表示整数的浮点数是否也会出现舍入错误?

Do rounding errors occur also in floats representing integers?

按如下方式创建数字范围时,

    float increment = 0.01f;
    for (int i = 0; i < 100; i++) {
        float value = i * increment;
        System.out.println(value);
    }

很明显,我最终会得到一些 i 的值,例如 0.049999997,由于舍入误差,这不是 0.01 的精确倍数。

当我尝试使用通常整数范围内的浮点数时,我从未见过同样的问题:

float increment = 1.0f; //Still a float but representing an int value
for (int i = 0; i < 100; i++) {
    float value = i * increment;
    System.out.println(value);
}

可以预料,这也会打印出例如49.999999 而不是 50,但我从未见过。

我在想,我是否可以依赖于 i 的任何值和 increment 的任何值,只要它代表一个整数(尽管它的类型是 float)。

如果是这样,我很想知道为什么在那种情况下不会发生舍入错误。

它并不真正代表一个整数。它仍然是一个浮点数,您只是试图将值 1.0 添加到其中。一旦 1.0 下溢(只要指数大于零),您就会得到舍入错误。

这是因为 float 是基于浮点数的。

粗鲁地说,它试图将您的十进制数表示为 2 的分数的总和。

这意味着它将尝试对 1/2^n1 + 1/2^n2 + 1/2^n3 .... 1/2^nm 求和,直到得到关闭或您输入的精确值。

例如(粗鲁):
0.5 表示为 1/2
0.25 表示为 1/2²
0.1 表示为 1/2^4
但在这种情况下,它会将数字乘以 1.600000023841858(尾数),它会给出一个更接近但不等于 1 的数字(1/2^4 x 1.600000023841858 = 0,100000001

现在你可以明白为什么在一些循环之后值会变成无意义的值

有关其工作原理的详细信息,请阅读浮点数 IEEE 754

如果你想要精度,你应该使用例如来自 Java 的 BigDecimal,它使用另一种架构来表示十进制数。

Double也有同样的问题

勾选这个工具,看看浮点数的表示: http://www.h-schmidt.net/FloatConverter/IEEE754.html

一定范围内的整数(大约最多一百万左右)可以精确地表示为浮点数。因此,当您只使用它们时不会出现舍入错误。