Java 为什么数学类中的nextUp方法会跳过一些值?

Java 为什么数学类中的nextUp方法会跳过一些值?,java,floating-point,precision,Java,Floating Point,Precision,我只是在摆弄这个方法,看看它能做什么。我创建了一个值为3.14的变量,只是因为在那个实例中我想到了它 double n = 3.14; System.out.println(Math.nextUp(n)); 前面的显示为3.140000000000006 尝试使用3.140000000000001,显示相同 试用333.33,显示333.3300000000004 对于许多其他值,它显示适当的值,例如73.6结果和73.6000000000001 介于3.140000000000000和3.

我只是在摆弄这个方法,看看它能做什么。我创建了一个值为3.14的变量,只是因为在那个实例中我想到了它

double n = 3.14;

System.out.println(Math.nextUp(n));
前面的显示为3.140000000000006

尝试使用3.140000000000001,显示相同

试用333.33,显示333.3300000000004

对于许多其他值,它显示适当的值,例如73.6结果和73.6000000000001


介于3.140000000000000和3.140000000000006之间的值会发生什么变化?为什么它会跳过一些值?我知道硬件相关的问题,但有时它工作正常。此外,即使已知无法进行精确操作,为什么库中包含这种方法?它看起来非常无用,因为它并不总是正确的。

Java中一个有用的技巧是使用
新的BigDecimal(double)
和BigDecimal的
toString
的精确性来显示double的精确值:

import java.math.BigDecimal;

public class Test {
  public static void main(String[] args) {
    System.out.println(new BigDecimal(3.14));
    System.out.println(new BigDecimal(3.1400000000000001));
    System.out.println(new BigDecimal(3.1400000000000006));
  }
}
输出:

3.140000000000000124344978758017532527446746826171875
3.140000000000000124344978758017532527446746826171875
3.1400000000000005684341886080801486968994140625
有有限数量的双精度数,因此只有实数的特定子集才是双精度数的精确值。创建双精度文字时,键入的十进制数由最接近的值表示。默认情况下,当您输出一个double时,它将显示为输入时四舍五入到它的最短小数。您需要做一些类似于我在程序中使用的BigDecimal技术的事情来查看确切的值


在这种情况下,3.14和3.140000000000001都比任何其他双精度更接近于3.14000000000001243449787580175325274467466826171875。上面的下一个可精确表示的数字是3.140000000000056843418808080801486968994140625,与@jgreve类似,它提到了这一点,因为在java中使用了float和double原语类型,这导致了所谓的舍入错误。另一方面,基本类型int是一个定点数字,这意味着它能够在32位内“适合”。双精度不是定点的,这意味着双精度计算的结果必须经常四舍五入以适应其有限表示,这有时会导致(如您的案例中所示)不一致的值

有关更多信息,请参见以下两个链接

解决方案可以是以下两个,这为第一个双精度点提供了一个“方向”

double n = 1.4;
double x = 1.5;
System.out.println(Math.nextAfter(n, x)); 


但要处理浮点值,建议使用
BigDecimal

浮点数以二进制形式存储:十进制表示法仅供人类使用

使用3.14转换为:

11.001000111101011100001010001111010111000010100011111
和3.140000000000006转换为

11.0010001111010111000010100011110101110000101001

这确实是下一个53位有效位的二进制数。

结果表明,浮点数不是平滑的(连续的),由于精度有限,它们有间隙。我认为你的“缺失值”反映了这些差距,在你正在处理的范围内,这些差距非常小。为了解释您看到的行为,我们需要深入到浮点表示的二进制级别。更多信息请参见此处:作为后续内容,我正在阅读这篇文章(从前面的链接):“每个计算机科学家都应该知道浮点运算”,仅仅因为它看起来很有趣——这是一篇ACM文章的翻版。您可以看看为什么API中会包含这样的方法?也许有什么用处吗?@Haggra个人认为,我经常使用nextUp等工具。当我探究浮点行为时,你在问题中所做的那种事情。通常,一个计算的精确结果被一对连续的、完全具有代表性的数字括起来,我想看看它们是什么,以及结果相对于它们之间的中间点落在哪里。这是一个有趣的答案。非常有用,谢谢!
11.0010001111010111000010100011110101110000101001