gpt4 book ai didi

java - 从 java BigDecimal 转换为 double 时丢失精度

转载 作者:行者123 更新时间:2023-12-01 17:22:14 25 4
gpt4 key购买 nike

我正在使用一个完全基于 double 的应用程序,并且在将字符串解析为 double 的实用程序方法中遇到了麻烦。我找到了一个修复方法,使用 BigDecimal 进行转换可以解决问题,但当我将 BigDecimal 转换回 double 时,会出现另一个问题:我失去了几个精度位。例如:

import java.math.BigDecimal;
import java.text.DecimalFormat;

public class test {
public static void main(String [] args){
String num = "299792.457999999984";
BigDecimal val = new BigDecimal(num);
System.out.println("big decimal: " + val.toString());
DecimalFormat nf = new DecimalFormat("#.0000000000");
System.out.println("double: "+val.doubleValue());
System.out.println("double formatted: "+nf.format(val.doubleValue()));
}
}

这会产生以下输出:

$ java test
big decimal: 299792.457999999984
double: 299792.458
double formatted: 299792.4580000000

格式化的 double 表明它在第三位之后丢失了精度(应用程序需要那些较低的精度)。

如何让 BigDecimal 保留这些额外的精度位置?

谢谢!

<小时/>

catch 这篇文章后进行更新。有几个人提到这超出了 double 据类型的精度。除非我错误地阅读了此引用文献: http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.2.3那么 double 原语的最大指数值为 Emax = 2K-1-1,标准实现的 K=11。那么,最大指数应该是 511,不是吗?

最佳答案

您已达到该数字的 double 的最大精度。这是不可能的。在这种情况下,该值将被四舍五入。从 BigDecimal 进行的转换是不相关的,并且精度问题是相同的。请参阅以下示例:

System.out.println(Double.parseDouble("299792.4579999984"));
System.out.println(Double.parseDouble("299792.45799999984"));
System.out.println(Double.parseDouble("299792.457999999984"));

输出是:

299792.4579999984
299792.45799999987
299792.458

对于这些情况,double 小数点后的精度超过 3 位。它们恰好是您的数字的零,这是您可以放入 double 中的最接近的表示形式。在这种情况下,它更接近四舍五入,因此您的 9 似乎消失了。如果你尝试这样做:

System.out.println(Double.parseDouble("299792.457999999924"));

您会注意到它保留了 9,因为它更接近向下舍入:

299792.4579999999

如果您要求保留号码中的所有数字,那么您必须更改在double上运行的代码。您可以使用 BigDecimal 来代替它们。如果您需要性能,那么您可能需要探索 BCD作为一个选项,尽管我不知道有任何库。

<小时/>

响应您的更新: double float 的最大指数实际上是 1023。但这不是您的限制因素。您的数字超出了表示有效数的 52 个小数位的精度,请参阅 IEEE 754-1985 .

使用this floating-point conversion以二进制形式查看您的号码。指数为 18,因为 262144 (2^18) 最接近。如果您将小数位以二进制形式向上或向下一位,您会发现没有足够的精度来表示您的数字:

299792.457999999900 // 0010010011000100000111010100111111011111001110110101
299792.457999999984 // here's your number that doesn't fit into a double
299792.458000000000 // 0010010011000100000111010100111111011111001110110110
299792.458000000040 // 0010010011000100000111010100111111011111001110110111

关于java - 从 java BigDecimal 转换为 double 时丢失精度,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61271885/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com