Java浮点数基本类型是否有符合IEEE 754标准的实现?

14
我想知道Java是否使用IEEE 754标准来实现其浮点算术。在这里,我在文档中看到了这样的内容:

操作定义在IEEE 754-2008中

据我所知,IEEE 754的好处是提高浮点算术的精度,因此如果我在Java中使用doublefloat,计算精度会与BigDecimal相同吗?如果不是,那么在Math类中使用IEEE 754标准有什么意义呢?

1
链接已经失效。 - Safron
1个回答

21
我想知道Java是否使用IEEE 754标准来实现其浮点运算。

IEEE-754定义了多种浮点类型的标准。多年来,它们都是二进制浮点数;这就是Java的floatdouble所代表的: float是32位IEEE-754二进制浮点值(标准称之为binary32)。double是64位(标准称之为binary64)。这些二进制浮点数对于计算机进行计算非常高效,但由于它们使用二进制而我们使用十进制,因此存在一些期望不匹配的情况;例如,0.1无法在double中精确存储,您会得到奇怪的结果,例如0.1 + 0.2的结果为0.30000000000000004。有关详细信息,请参见浮点数计算是否出现问题?。它们不适用于金融计算等场景。

BigDecimal是一个Java类,它实现了带任意精度的十进制小数。与使用double相比,它要慢得多,但结果符合我们对十进制的期望(例如,0.1 + 0.2将会是0.3)。

IEEE-754的2008版添加了重要的新格式,特别是decimal32, decimal64, 和 decimal128。它们是十进制浮点数,因此它们的工作方式与我们一样。 0.1可以准确地存储在decimal64中。0.1 + 0.2decimal64中是0.3。然而,据我所知,它们并不真正与您的问题相关。

由于 BigDecimal 的发布时间早于 IEEE-754 2008 标准(相差很大),因此它定义了自己的语义。

如果不是这样,那么在 Math 类中使用 IEEE 754 标准有什么意义呢?

JDK9 在 Math 中添加了新的操作,这些操作根据 IEEE-754 2008 规范执行(例如 fma,它执行 融合乘加运算),因此为了清晰起见,它使用 IEEE-754 2008 规范定义了这些操作。

更多阅读:


当指定精度时,BigDecimal的语义是否与decimalxx不同?例如,new BigDecimal("0.1", MathContext.DECIMAL64)是否与decimal64不同? - Safron
@Safron - 我从未深入研究过它们的语义,但是鉴于BigDecimal定义了一个带有方法的不可变对象类型,而IEEE-754 decimalXX类型是原始类型,我怀疑如此。它们可能具有不同的默认舍入行为等等,特别是BigDecimal的每个实例都可以配置。 - T.J. Crowder
@TJCrowder 我也怀疑过这样的事情,但看来我们都错了。:) 根据 DECIMAL64 的文档:一个 MathContext 对象,其精度设置与 IEEE 754-2019 decimal64 格式的精度匹配,即 16 位数字,并采用 HALF_EVEN 舍入模式。(请参见 https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/math/MathContext.html#DECIMAL64) - Safron
@Safron - 那只是精度问题,而不是语义学问题。 :-) - T.J. Crowder
1
@TJCrowder 您是正确的,看来我有点太快了。我在Java 17文档中找到了实际的语义差异。请参阅https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/math/BigDecimal.html中的“与IEEE 754十进制算术的关系”部分。 - Safron

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接