当前位置: 首页 > 面试题库 >

从Java BigDecimal转换为double的精度下降

陆正奇
2023-03-14
问题内容

我正在使用完全基于双精度的应用程序,并且在将字符串解析为双精度的一种实用程序方法中遇到麻烦。我找到了一个解决方法,其中使用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来保留这些额外的精度?

谢谢!

赶上这篇文章后更新。有人提到这超出了double数据类型的精度。除非我未正确阅读此参考文献:http
:
//java.sun.com/docs/books/jls/third_edition/html/typesValues.html#4.2.3,
否则double原语的最大指数值为E max = 2 K-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作为一种选择。

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

使用此浮点转换可以看到您的二进制数字。由于262144(2
^ 18)最接近,因此指数为18。如果您使用小数位然后以二进制形式向上或向下一位,您会发现没有足够的精度来表示您的数字:

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


 类似资料:
  • 问题内容: 在Java中,我想要一个双精度值并将其转换为a 并以一定的精度打印出它的String值。 它打印出这个巨大的东西: 47.47999999999999687361196265555918216705322265625 并不是 47.48 我进行转换的原因是有时double值将包含很多小数位(即),而将double转换为String时将产生科学计数法。我想以非科学计数法存储String值

  • 在Java中,我想取一个double值并将其转换为并打印出其字符串值以达到一定精度。 我进行转换的原因是,有时double值会包含很多小数位(即),而当将double转换为字符串时,会生成科学符号。我想用非科学符号存储字符串值。 我想让BigDecimal始终有两个精度单位,像这样:“47.48”。BigDecimal可以限制转换为字符串时的精度吗?

  • 问题内容: 尝试如下 输出:12.0 但我想获得12.00的精度 请让我知道正确的方法,而不在字符串类中使用format()方法 问题答案: 使用而不是双重: 之所以有效,是因为保持了“精度”,构造函数将其设置为从右边的数字开始,并在中使用它。因此,如果仅将其丢弃,它就会打印出来。

  • 我有下面的抓耳挠腮,演示在和这里 两个版本中的简单编译类中都会发生相同的情况 尽管17警告不再需要 JLS在第5.1节中说明了这一点。2. 14年,在项目清单之后,它包含以下内容 根据我的阅读,这是实现中的错误?我发现执行此转换的唯一可靠方法是。

  • 问题内容: 为什么会收到错误,我该如何解决? 如您所见,在声明变量时,我已经尝试过用顶部附近的位置进行替换,但是似乎并没有完成任务。 问题答案: 更改使用数组索引从double到INT所有变量(即变量,,)。数组索引是整数。

  • 问题内容: 我正在实现一个接口,该接口的功能类似于可以包含某种对象的表的功能。该接口指定以下功能: 在我的实现中,我感到很困惑的是,我将表数据存储在2D 数组()中。当我需要返回值时,我想执行以下操作(假定只在包含double的列上调用,因此将没有): 但是- Java不允许强制转换为。将其强制转换为可以,因为它是一个对象,而不是基元,但是我的接口指定数据将以形式返回。 所以我有两个问题: 有什么