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

戏子无情 提交于 2019-12-25 00:37:18

问题


In an application I am working some numbers get converted and saved from long(18 digits) to float/double. These numbers are like Reference/Id's but not used for calculations. Recently I noticed some discrepancies in data being stored as float/double. I am trying to understand if the behavior is due to what floating point numbers call significant digits and maybe a simple explanation for the same.

My questions based on below program are

  1. Output no : 5 shows a really big number(39 digits before decimal) as max value of float. Why then float cannot display anything above 7 digits accurately. It is because of is supports only 6-7 significant digits.
  2. Output no : 10 shows a really big number as max value of double. Why then double cannot display anything above 16 digits accurately. It is because of is supports only 15 significant digits.
  3. What is really meant by significant digits ? Does it mean any digits after this number will not be represented accurately regardless of whether it comes before or after decimal point ?

NOTE : After my research on this topic , I do now understand that floating point numbers are by their nature inaccurate and should not be used to represent things that require accurate representations. Still I feel a bit confused about the above behavior and significant digits.

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 );
    }
}

Output of above program

  1. Float value of 50000000115 is : 49,999,998,976.000000. Expected output was 50000000115.000000
  2. Float value of 50000000116 is : 49,999,998,976.000000. Expected output was 50000000116.000000
  3. Float value of 50000000117 is : 49,999,998,976.000000. Expected output was 50000000117.000000

  4. Float value of 2175863596593954381 is : 2,175,863,554,941,386,750.000000. Expected output was 2175863596593954381.000 000

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

  6. Double value of 50000000115 is : 50,000,000,115.000000

  7. Double value of 50000000116 is : 50,000,000,116.000000
  8. Double value of 50000000117 is : 50,000,000,117.000000

  9. Double value of 2175863596593954381 is : 2,175,863,596,593,954,300.000000. Expected output was 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. Float value of number gives expected result till 7 digits ie 12345678 is : 12,345,678.000000

  12. Float value of number gives expected result till 7 digits ie 11111111 is : 11,111,111.000000
  13. Double value of number gives expected result till 16 digits ie 1122334455667788 is : 1,122,334,455,667,788.000000
  14. Double value of number gives expected result till 16 digits ie 1111222233334444 is : 1,111,222,233,334,444.000000

回答1:


Java’s Float type (IEEE-754 binary32) effectively has two components:

  • a integer number of units from −16,777,215 to +16,777,215 (224−1) and
  • a unit that is a power of two from 2104 to 2−149.

The smallest unit (within range) that keeps the number of units within range is used.

For example, with 50,000,000,115, we cannot use a unit size of 2048 (212), because 50,000,000,115 is about 24,414,062 units of 2048, which is more than 16,777,215 units. So we use a unit size of 4096.

50,000,000,115 is exactly 12,207,031.278076171875 units of 4096, but we can only use an integer number of units, so the Float value closest to 50,000,000,115 is 12,207,031 units of 4096, which is 49,999,998,976.

The other values in your question are represented similarly, but Java’s rules for formatting numbers with %,f result in limited numbers of decimal digits being used to show the value. So, in some of your examples, we see trailing zeros where the actual mathematical value of the internal number is different.

For Double (IEEE-754 binary64), the two components are:

  • a integer number of units from −9,007,199,254,740,991 to +9,007,199,254,740,991 (253−1) and
  • a unit that is a power of two from 2972 to 2−1074.


来源:https://stackoverflow.com/questions/57954475/large-float-and-double-numbers-in-java-printing-persisting-incorrectly-is-this

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!