为什么两个浮点值不能正确相加呢?

lqfhib0f  于 2021-07-09  发布在  Java
关注(0)|答案(2)|浏览(331)

如果你问我的话,下面这个例子给我的输出是非常奇怪的。这怎么可能?有没有办法把这两个值加起来?sum(float a,float b)也给出了相同的结果。

import java.text.DecimalFormat;

public class HelloWorld {
  public static void main(String[] args) {
    System.out.println("Sum: " + new DecimalFormat("#").format((1500036225984102400.f + 2000000000.f)));
  }
}

输出为:
金额:1500036225984102400
当然我希望这两个值相加,但是第二个值似乎被忽略了?

zsbz8rwp

zsbz8rwp1#

如果您看看float是如何设置的(ieee-754),您很快就会发现尾数只有23位(实际上是24位,对于非规范化的数字,一位是隐式的)。
1500036225984102400为十六进制

14 d1 33 00 00 00 00 00

所以你看,你的数字中非空的部分适合这24位。这就是为什么你得到的数字打印完全一样,你给它。任何进一步的位将被简单地切断(类似于整数除法,尽管在细节上并不完全相同)。实际上,这是数学上的四舍五入。
如果你现在比较一下你的两个数字:

14 d1 33 00 00 00 00 00
            77 35 94 00

您很快就会看到,加法的结果将不适合可用的24位,不适合的部分将被简单地四舍五入-正是您尝试添加的数字。。。
这通常是浮点数的一个问题,但是在double中不太常见,因为尾数和指数在那里更大。。。

utugiqy6

utugiqy62#

浮点数的精度是有限的。您可以使用 Math.nextUp 方法。例如,可以使用以下方法查找比第一个操作数大的下一个最大数:

float next = Math.nextUp(1500036225984102400.f);

您可以通过减法或使用 Math.ulp ,它告诉您“最后一个位置的单位”的大小,如果调整最低有效位,则数字增加的量:

float ulp = Math.ulp(1500036225984102400.f);

你会发现这个数字比 2000000000.f :

Math.ulp(1500036225984102400.f) = 137438953472.0
                                    2000000000.0

因此你的两个数字之和不能用一个更精确的数字来表示 float1500036225984102400.f .

相关问题