一般编程和 Java 中 double 的准确性

Xtr*_*ity 5 java double

我知道由于浮点/双精度的性质,不应将它们用于精确的重要计算。但是,由于对类似问题的混合答案,我对它们的局限性感到有些困惑,无论有效数字如何,浮点数和双精度数是否总是不准确,或者仅不准确到第 16 位。

我在 Java 中运行了一些示例,

System.out.println(Double.parseDouble("999999.9999999999"); 
// this outputs correctly w/ 16 digits
System.out.println(Double.parseDouble("9.99999999999999");
// This also outputs correctly w/ 15 digits
System.out.println(Double.parseDouble("9.999999999999999");
// But this doesn't output correctly w/ 16 digits. Outputs 9.999999999999998
Run Code Online (Sandbox Code Playgroud)

我找不到指向另一个答案的链接,该链接指出 1.98 和 2.02 之类的值将四舍五入为 2.0,因此会造成不准确,但测试表明这些值打印正确。所以我的第一个问题是浮点/双精度值是否总是不准确,或者是否存在可以确保精度的下限。

我的第二个问题是关于使用 BigDecimal。我知道我应该使用 BigDecimal 进行精确的重要计算。因此,我应该使用 BigDecimal 的方法进行算术和比较。但是,BigDecimal 还包括一个doubleValue()将 BigDecimal 转换为双精度的方法。对我确定少于 16 位的双精度值进行比较是否安全?根本不会对它们进行算术运算,因此固有值不应该改变。

例如,我执行以下操作是否安全?

BigDecimal myDecimal = new BigDecimal("123.456");
BigDecimal myDecimal2 = new BigDecimal("234.567");
if (myDecimal.doubleValue() < myDecimal2.doubleValue()) System.out.println("myDecimal is smaller than myDecimal2");
Run Code Online (Sandbox Code Playgroud)

编辑:在阅读了对我自己的答案的一些回复后,我意识到我的理解不正确并已将其删除。以下是其中的一些片段,可能对未来有所帮助。

“双精度不能精确地容纳 0.1。最接近 0.1 的可表示值是 0.1000000000000000055511151231257827021181583404541015625。Java Double.toString 只打印足够的数字来唯一地标识双精度值。” - 帕特里夏·沙纳汉

来源:
https : //stackoverflow.com/a/5749978 - 说明双精度数最多可容纳 15 位数字

小智 1

我建议您阅读此页面:
https://en.wikipedia.org/wiki/Double- precision_floating-point_format

一旦您阅读并理解了它,并且可能将几个示例转换为 64 位浮点格式的二进制表示形式,那么您将更好地了解 Double 可以保存哪些有效数字。