Float Fractional Precision

后端 未结 2 1249
独厮守ぢ
独厮守ぢ 2021-01-20 00:43

How many places of precision does a float have between 1.0f and 0.0f such that every value could be uniquely represented?

For

相关标签:
2条回答
  • 2021-01-20 01:00
    std::numeric_limits<float>::digits10
    

    From http://en.cppreference.com/w/cpp/types/numeric_limits/digits10

    The standard 32-bit IEEE 754 floating-point type has a 24 bit fractional part (23 bits written, one implied), which may suggest that it can represent 7 digit decimals (24 * std::log10(2) is 7.22), but relative rounding errors are non-uniform and some floating-point values with 7 decimal digits do not survive conversion to 32-bit float and back: the smallest positive example is 8.589973e9, which becomes 8.589974e9 after the roundtrip. These rounding errors cannot exceed one bit in the representation, and digits10 is calculated as (24-1)*std::log10(2), which is 6.92. Rounding down results in the value 6.

    Edit2: This shows that the number is not 7 but only 6 digits for any float, just like the std::numeric_limits<float>::digits10 call will tell.

    float orgF = 8.589973e9;
    int i = orgF;
    float f = i;
    assert(f == orgF);
    

    This will fail as the roundtrip changes the value.

    So if we are only looking for numbers between 1.0 and 0.0, positive the answer is 7, as the lowest positive number which has a problem is 8.589973e9.

    0 讨论(0)
  • 2021-01-20 01:21

    If I understood your question correctly, the answer is 6.

    #include <iostream>
    #include <string>
    #include <sstream>
    #include <iomanip>
    using namespace std;
    
    int main() {
        int i = 10;  /* Number of distinct number after 1 place of decimal */
        int k = 1;   /* Number of decimal places */
        for(;/* ever */;)
        {
            float prev = 0.0f;
            for(int j = 1; j <= i; ++j)
            {
                stringstream ss;
                ss << "0.";  /* Prepare stream with 0. followed by k digit number with leading zeroes */
                ss << setfill('0') << setw(k) << j;
                float next; /* Read the number */
                ss >> next;
                if(prev == next) return 0;  /* If previous number and current number can not be distinguished */
                prev = next;
            }
            cout << "Works for " << k << " places" << endl;
            i *= 10; /* 10 times more tests to be conducted for 1 more decimal places */
            k++;     /* Try for more decimal places */
        }
        return 0;
    }
    

    What does the code do

    1. Set precision to 1 place after decimal
    2. Compare 0.0 with 0.1, 0.1 with 0.2 .... 0.8 with 0.9 and 0.9
       with 1.0, if any of these are equal (not distinguish), exit.
       Otherwise print Works for 1 place.
    3. Set precision to 2 places after decimal
    4. Compare 0.00 with 0.01, 0.01 with 0.02 .... 0.98 with 0.99 and 0.99
       with 1.00, if any of these are equal (not distinguish), exit. Otherwise
       print Works for 2 places.
    5. Repeat similar steps for 3 and more digits unless you exit
    
    0 讨论(0)
提交回复
热议问题