java - 在 Java 中使用 Double 与 BigDecimal 解析 double 值

标签 java floating-point double

我是一位经验丰富的开发人员,但不是数学专家。我对 IEEE 浮点规范有足够的了解,以至于害怕对解析、打印和比较它们做出假设。

我知道我可以解析 double来自 String使用 Double.parseDouble(String s) .我知道我也可以将相同的字符串解析为 BigDecimal使用 new BigDecimal(String s) ,然后询问 BigDecimal对于 double使用 BigDecimal.doubleValue() .

我看了一眼这两种技术的 API 和代码,似乎 BigDecimal有很多不同的解析和转换选项。

对于所有字符串输入,这两种技术( Double.parseDouble(s)new BigDecimal(s).doubleValue() )是否保证产生完全相同的 double原始值,前提是该值不超出正负范围Double.MAX_DOUBLE ?

最佳答案

对于大多数输入值,两种技术应该产生相同的值。虽然他们仍然有可能不会,但似乎不太可能。
BigDecimal(String) constructor Javadocs 指出:

API Note:

For values other than float and double NaN and ±Infinity, this constructor is compatible with the values returned by Float.toString(float) and Double.toString(double).


但是, Double.parseDouble(String) method 指出:

Returns a new double initialized to the value represented by the specified String, as performed by the valueOf method of class Double.


然后继续描述该方法接受的格式。
让我们来测试一下!
让我们测试一些值。进行详尽的测试似乎是一项非常巨大的工作,但让我们测试一些字符串值,这些值表示已知会产生浮点错误或不精确表示的值。
public static void main(String[] args)
{
    String[] values = {"0", "0.1", "0.33333333333333333333", "-0", "-3.14159265", "10.1e100",
            "0.00000000000000000000000000000000000000000000000000142857142857",
            "10000000000.000000000000000001", "2.718281828459",
            "-1.23456789e-123", "9.87654321e+71", "66666666.66666667",
            "1.7976931348623157E308", "2.2250738585072014E-308", "4.9E-324",
            "3.4028234663852886E38", "1.1754943508222875E-38", "1.401298464324817E-45",
            String.valueOf(Math.E), String.valueOf(Math.PI), String.valueOf(Math.sqrt(2))
    };
    for (String value : values) {
        System.out.println(isDoubleEqual(value));
    }
}
// Test if the representations yield the same exact double value.
public static boolean isDoubleEqual(String s) {
    double d1 = Double.parseDouble(s);
    double d2 = new BigDecimal(s).doubleValue();
    return d1 == d2;
}
对于这些值,我得到了所有 true 。这绝不是详尽无遗的,因此很难证明所有可能的 double 值都为真。只需要一个 false 来显示一个反例。然而,这似乎是所有合法 double 字符串表示都是正确的一些证据。
我也试过前导空格,例如" 4"BigDecimal(String) 构造函数抛出 NumberFormatExceptionDouble.parseDouble 正确修剪了输入。BigDecimal(String) 构造函数不接受 InfinityNaN ,但您只询问了正常的有限范围。 Double.parseDouble 方法接受十六进制浮点表示,但 BigDecimal(String) 不接受。
如果包含这些边缘情况,一种方法可能会抛出异常,而另一种方法则不会。如果您正在寻找范围内有限值的正常 base-10 字符串,答案是“似乎很可能”。

关于java - 在 Java 中使用 Double 与 BigDecimal 解析 double 值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58123149/

相关文章:

java - linux:ps 截断命令行输出

java - 如何检查零是正数还是负数?

c - 简单浮点运算的奇怪结果 - FPU 内部状态错误?

java - 旋转 - 缺乏精度 - Java

java - 有没有办法让需要文件参数的命令行程序使用标准输入?

java - Java 中的包保护条件?

c# - 使用 LibTIFF.NET C# 将具有浮点像素值的 32 位灰度 Tiff 数组化

Java - 2.0 和 2.00000000000D 之间的实际区别

java - 将字符串数组列表存储到双数组列表中?

java - OSGi 依赖关系可视化