Printf width specifier to maintain precision of floating-point value

后端 未结 8 1359
萌比男神i
萌比男神i 2020-11-21 13:39

Is there a printf width specifier which can be applied to a floating point specifier that would automatically format the output to the necessary number of s

8条回答
  •  礼貌的吻别
    2020-11-21 14:08

    I run a small experiment to verify that printing with DBL_DECIMAL_DIG does indeed exactly preserve the number's binary representation. It turned out that for the compilers and C libraries I tried, DBL_DECIMAL_DIG is indeed the number of digits required, and printing with even one digit less creates a significant problem.

    #include 
    #include 
    #include 
    #include 
    #include 
    
    union {
        short s[4];
        double d;
    } u;
    
    void
    test(int digits)
    {
        int i, j;
        char buff[40];
        double d2;
        int n, num_equal, bin_equal;
    
        srand(17);
        n = num_equal = bin_equal = 0;
        for (i = 0; i < 1000000; i++) {
            for (j = 0; j < 4; j++)
                u.s[j] = (rand() << 8) ^ rand();
            if (isnan(u.d))
                continue;
            n++;
            sprintf(buff, "%.*g", digits, u.d);
            sscanf(buff, "%lg", &d2);
            if (u.d == d2)
                num_equal++;
            if (memcmp(&u.d, &d2, sizeof(double)) == 0)
                bin_equal++;
        }
        printf("Tested %d values with %d digits: %d found numericaly equal, %d found binary equal\n", n, digits, num_equal, bin_equal);
    }
    
    int
    main()
    {
        test(DBL_DECIMAL_DIG);
        test(DBL_DECIMAL_DIG - 1);
        return 0;
    }
    

    I run this with Microsoft's C compiler 19.00.24215.1 and gcc version 7.4.0 20170516 (Debian 6.3.0-18+deb9u1). Using one less decimal digit halves the number of numbers that compare exactly equal. (I also verified that rand() as used indeed produces about one million different numbers.) Here are the detailed results.

    Microsoft C

    Tested 999507 values with 17 digits: 999507 found numericaly equal, 999507 found binary equal
    Tested 999507 values with 16 digits: 545389 found numericaly equal, 545389 found binary equal
    

    GCC

    Tested 999485 values with 17 digits: 999485 found numericaly equal, 999485 found binary equal
    Tested 999485 values with 16 digits: 545402 found numericaly equal, 545402 found binary equal
    

提交回复
热议问题