java printing/persisting 中的大浮点数和双精度数不正确。这种行为是由于有效数字的数量吗?

Large float and double numbers in java printing/persisting incorrectly. Is this behavior due to number of significant digits?

在我正在处理的应用程序中,一些数字从长(18 位)转换并保存为 float/double。这些数字类似于 Reference/Id,但不用于计算。最近我注意到存储为 float/double 的数据存在一些差异。我试图了解这种行为是否是由于浮点数称为有效数字引起的,并且可能对此有一个简单的解释。

我基于以下程序的问题是

  1. 输出 no : 5 显示一个非常大的数字(小数点前 39 位)作为浮点数的最大值。为什么float不能准确显示7位以上的任何东西。这是因为它只支持 6-7 位有效数字。
  2. 输出编号:10 显示一个非常大的数字作为双精度的最大值。为什么 double 不能准确显示 16 位以上的任何内容。这是因为它只支持 15 位有效数字。
  3. 有效数字的真正含义是什么?是不是这个数字后面的数字不管是小数点前还是小数点后都不能准确表示?

注意:经过对这个主题的研究,我现在明白浮点数本质上是不准确的,不应该用来表示需要准确表示的事物。我仍然对上述行为和有效数字感到有点困惑。

public class Main
{
    public static void main(String[] args) {
        System.out.printf( "1. Float value of 50000000115 is : %,f. Expected output was 50000000115.000000 \n", 50000000115f );
        System.out.printf( "2. Float value of 50000000116 is : %,f. Expected output was 50000000116.000000 \n", 50000000116f );
        System.out.printf( "3. Float value of 50000000117 is : %,f. Expected output was 50000000117.000000 \n\n", 50000000117f );

        System.out.printf( "4. Float value of 2175863596593954381 is : %,f. Expected output was 2175863596593954381.000000 \n\n", 2175863596593954381f );

        System.out.printf( "5. Float.MAX_VALUE: %,f\n\n", Float.MAX_VALUE );

        System.out.printf( "6. Double value of 50000000115 is : %,f\n", 50000000115d );
        System.out.printf( "7. Double value of 50000000116 is : %,f\n", 50000000116d );
        System.out.printf( "8. Double value of 50000000117 is : %,f\n\n", 50000000117d );

        System.out.printf( "9. Double value of 2175863596593954381 is : %,f. Expected output was  2175863596593954381.000000 \n\n", 2175863596593954381d );

        System.out.printf( "10. Double.MAX_VALUE: %,f\n\n", Double.MAX_VALUE );

        System.out.printf( "11. Float value of number gives expected result till 7 digits ie 12345678 is : %,f\n", 12345678f );
        System.out.printf( "12. Float value of number gives expected result till 7 digits ie 11111111 is : %,f\n", 11111111f );
        System.out.printf( "13. Double value of number gives expected result till 16 digits ie 1122334455667788 is : %,f\n", 1122334455667788d );
        System.out.printf( "14. Double value of number gives expected result till 16 digits ie 1111222233334444 is : %,f\n", 1111222233334444d );
    }
}

以上程序的输出

  1. 50000000115 的浮点值是:49,999,998,976.000000。预期输出为 50000000115.000000
  2. 50000000116 的浮点值是:49,999,998,976.000000。预期输出为 50000000116.000000
  3. 50000000117 的浮点值是:49,999,998,976.000000。预期输出为 50000000117.000000

  4. 2175863596593954381 的浮点值是:2,175,863,554,941,386,750.000000。预期产量为 2175863596593954381.000 000

  5. Float.MAX_VALUE: 340,282,346,638,528,860,000,000,000,000,000,000,000.000000

  6. 50000000115 的双精度值是:50,000,000,115.000000

  7. 50000000116 的双精度值是:50,000,000,116.000000
  8. 50000000117 的双精度值是:50,000,000,117.000000

  9. 2175863596593954381 的双精度值是:2,175,863,596,593,954,300.000000。预期输出为 2175863596593954381.0 00000

  10. Double.MAX_VALUE:179,769,313,486,231,570,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,00 0,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,00 0,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,00 0,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000.000000

  11. 数字的浮点值给出预期结果直到 7 位即 12345678 是:12,345,678.000000

  12. 数字的浮点值给出了预期的结果,直到 7 位数字即 11111111 是:11,111,111.000000
  13. 数字的双倍值给出预期结果直到 16 位即 1122334455667788 是:1,122,334,455,667,788.000000
  14. 数字的双倍值给出预期结果直到 16 位即 1111222233334444 是:1,111,222,233,334,444.000000

Java 的 Float 类型 (IEEE-754 binary32) 实际上有两个组成部分:

  • 从 −16,777,215 到 +16,777,215 (224−1) 和
  • 的整数个单位
  • 从2104到2−149.
  • 的2的幂的单位

使用使单位数保持在范围内的最小单位(范围内)。

例如,50,000,000,115,我们不能使用2048的单位大小(212),因为50,000,000,115大约是2048的24,414,062个单位,比16,777,215个单位多。所以我们使用 4096 的单位大小。

50,000,000,115正好是4096的12,207,031.278076171875个单位,但是我们只能用整数个单位,所以最接近50,000,000,115的Float值是4096的12,207,031个单位,也就是49,999=6.998=947

您问题中的其他值的表示方式类似,但 Java 使用 %,f 格式化数字的规则导致用于显示该值的小数位数有限。因此,在您的一些示例中,我们看到内部数字的实际数学值不同的尾随零。

对于Double (IEEE-754 binary64),两个组件是:

  • 从 −9,007,199,254,740,991 到 +9,007,199,254,740,991 (253−1) 和
  • 的整数个单位
  • 从2972到2−1074.
  • 的2的幂的单位