将比特转换为双精度浮点数后,如何存储实际的浮点/双精度值而不使用BigDecimal?

3
根据几个浮点计算器以及下面的代码,下列 32 位 00111111010000000100000110001001 实际的浮点值为(0.750999987125396728515625)。由于它是实际的浮点数,我认为将其存储在 Double 或 Float 中会保留精度和确切值,只要 (1) 不执行任何运算,(2) 使用实际值,(3) 值不被 down-cast。那么为什么实际值与 casted(举例 1)和字面(举例 2)值 (0.7509999871253967) 不同呢?
我使用了此计算器作为示例: https://www.h-schmidt.net/FloatConverter/IEEE754.html enter image description here
import java.math.BigInteger;
import java.math.BigDecimal;

public class MyClass {
    public static void main(String args[]) {
      int myInteger = new BigInteger("00111111010000000100000110001001", 2).intValue();
      Double myDouble = (double) Float.intBitsToFloat(myInteger);
      String myBidDecimal = new BigDecimal(myDouble).toPlainString();

      System.out.println("      bits converted to integer: 00111111010000000100000110001001 = " + myInteger);
      System.out.println("    integer converted to double: " + myDouble);
      System.out.println(" double converted to BigDecimal: " + myBidDecimal);

      Double myDouble2 = 0.750999987125396728515625;
      String myBidDecimal2 = new BigDecimal(myDouble2).toPlainString();

      System.out.println("");
      System.out.println("       Ignore the binary string: ");
      System.out.println("            double from literal: " + myDouble2);
      System.out.println(" double converted to BigDecimal: " + myBidDecimal2);
    }
}

以下是输出结果:

      bits converted to integer: 00111111010000000100000110001001 = 1061175689
    integer converted to double: 0.7509999871253967
 double converted to BigDecimal: 0.750999987125396728515625

       Ignore the binary string: 
            double from literal: 0.7509999871253967
 double converted to BigDecimal: 0.750999987125396728515625

1
你为什么认为这个值没有被保留?是因为你期望那行代码“integer converted to double”会给你0.750999987125396728515625吗? - Louis Wasserman
是的,我确实希望如此。也许在计算过程中丢失了精度。此外,我期望文字(例如2)打印出完整的值,因为它是32位实际值的文字表示形式匹配。 - poetryrocksalot
1个回答

7
没有实际的精度损失;问题在于你对于将双精度浮点数转换为字符串(例如打印时)的期望不正确。
来自Double.toString文档
有多少位小数必须打印出m或a的分数部分?必须至少有一位数字来表示小数部分,除此之外只需要足以唯一区分类型为double的相邻值的数量。也就是说,假设x是由此方法产生的十进制表示形式所表示的确切数学值,用于有限非零参数d。那么d必须是最接近x的double值;或者如果两个double值与x同样接近,则d必须是它们中的一个,并且d的有效数字的最低位必须为0。
因此,当一个双精度浮点数被打印时,它仅打印具有足以唯一标识该双精度浮点数值的位数,而不是描述实数精确值所需的位数。
如果您想要获得一个double的精确值,包括所有可能的数字,那么new BigDecimal(theDouble).toPlainString()可以帮助您实现这一目标——正如您所演示的,它可以获得正确的结果。

我敢打赌这与双精度浮点数的精度保证有关,即小数点右侧不超过16位。唯一标识符是有意义的,因为在第16位数字之后,第17位数字的变化可能会导致相同的位表示。我的理解正确吗? - poetryrocksalot
1
精度保证实际上与十进制数字无关,而是二进制数字,但这就是这个想法。 - Louis Wasserman
2
@poetryrocksalot 一个double双精度浮点数在每个10的幂次方上摆动在15到17个有效十进制数字之间。二进制精度是在给定2的幂次方上有53个有效二进制数字。 - chux - Reinstate Monica

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接