Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to calculate 32-bit floating-point epsilon?

In book Game Engine Architecture : "..., let’s say we use a floating-point variable to track absolute game time in seconds. How long can we run our game before the magnitude of our clock variable gets so large that adding 1/30th of a second to it no longer changes its value? The answer is roughly 12.9 days." Why 12.9 days, how to calculate it ?

like image 702
Xia Cuo Avatar asked May 25 '16 15:05

Xia Cuo


People also ask

How do I find the epsilon for floating point?

In general, if you look at a machine number with base b, mantissa m (and exponent e), you can define eps:=b1−m2. To your example: You would probably represent 4 normalized as (0.10000000)2⋅23. The next number 4+132 is then represented as (0.10000001)2⋅23, i.e. you have m=8 and thus eps=2−8.

What is machine epsilon in floating point?

Machine epsilon or machine precision is an upper bound on the relative approximation error due to rounding in floating point arithmetic. This value characterizes computer arithmetic in the field of numerical analysis, and by extension in the subject of computational science.

How is Machine Epsilon calculated?

How can this be measured? For any format, the machine epsilon is the difference between 1 and the next larger number that can be stored in that format. 2−23 ·= 1.19 × 10−7 i.e., we can store approximately 7 decimal digits of a number x in decimal format.

What is epsilon and how is it calculated?

In Statistics. In regression analysis, epsilon (ε) is a measurement of how far from the true regression line the observation y is (e.g. in the equation, Y = Xβ + ε). The true regression line is the line of the means (the mean of epsilon is zero).


2 Answers

When the result of a floating point computation can't be represented exactly, it is rounded to the nearest value. So you want to find the smallest value x such that the increment f = 1/30 is less than half the width h between x and the next largest float, which means that x+f will round back to x.

Since the gap is the same for all elements in the same binade, we know that x must be the smallest element in its binade, which is a power of 2.

So if x = 2k, then h = 2k-23 since a float has a 24-bit significand. So we need to find the smallest integer k such that

2k-23/2 > 1/30

which implies k > 19.09, hence k = 20, and x = 220 = 1048576 (seconds).

Note that x / (60 × 60 × 24) = 12.14 (days), which is a little bit less that what your answer proposes, but checks out empirically: in Julia

julia> x = 2f0^20
1.048576f6

julia> f = 1f0/30f0
0.033333335f0

julia> x+f == x
true

julia> p = prevfloat(x)
1.04857594f6

julia> p+f == p
false

UPDATE: Okay, so where did the 12.9 come from? The 12.14 is in game time, not actual time: these will have diverged due to the rounding error involved in floating point (especially near the end, when the rounding error is actually quite large relative to f). As far as I know, there's no way to calculate this directly, but it's actually fairly quick to iterate through 32-bit floats.

Again, in Julia:

julia> function timestuff(f)
           t = 0
           x = 0f0
           while true
               t += 1
               xp = x
               x += f
               if x == xp
                   return (t,x)
               end
           end
       end
timestuff (generic function with 1 method)

julia> t,x = timestuff(1f0/30f0)
(24986956,1.048576f6)

x matches our result we calculated earlier, and t is the clock time in 30ths of a second. Converting to days:

julia> t/(30*60*60*24)
9.640029320987654

which is even further away. So I don't know where the 12.9 came from...

UPDATE 2: My guess is that the 12.9 comes from the calculation

y = 4 × f / ε = 1118481.125 (seconds)

where ε is the standard machine epsilon (the gap between 1 and the next largest floating point number). Scaling this to days gives 12.945. This provides an upper bound on x, but it is not the correct answer as explained above.

like image 51
Simon Byrne Avatar answered Oct 09 '22 10:10

Simon Byrne


#include <iostream>
#include <iomanip>

/*
https://en.wikipedia.org/wiki/Machine_epsilon#How_to_determine_machine_epsilon
*/

typedef union
{
    int32_t i32;
    float   f32;
} fi32_t;

float float_epsilon(float nbr)
{
    fi32_t flt;
    flt.f32 = nbr;
    flt.i32++;
    return (flt.f32 - nbr);
}

int main()
{
    // How to calculate 32-bit floating-point epsilon?

    const float one {1.}, ten_mills {10e6};
    std::cout << "epsilon for number " << one << " is:\n"
        << std::fixed << std::setprecision(25)
        << float_epsilon(one)
        << std::defaultfloat << "\n\n";

    std::cout << "epsilon for number " << ten_mills << " is:\n"
        << std::fixed << std::setprecision(25)
        << float_epsilon(ten_mills)
        << std::defaultfloat << "\n\n";


    // In book Game Engine Architecture : "..., let’s say we use a
    // floating-point variable to track absolute game time in seconds.
    // How long can we run our game before the magnitude of our clock
    // variable gets so large that adding 1/30th of a second to it no
    // longer changes its value? The answer is roughly 12.9 days."
    // Why 12.9 days, how to calculate it ?

    const float one_30th {1.f/30}, day_sec {60*60*24};
    float time_sec {}, time_sec_old {};

    while ((time_sec += one_30th) > time_sec_old)
    {
        time_sec_old = time_sec;
    }

    std::cout << "We can run our game for "
        << std::fixed << std::setprecision(5)
        << (time_sec / day_sec)
        << std::defaultfloat << " days.\n";


    return EXIT_SUCCESS;
}

This outputs

epsilon for number 1 is:
0.0000001192092895507812500

epsilon for number 10000000 is:
1.0000000000000000000000000

We can run our game for 12.13630 days.
like image 21
francek Avatar answered Oct 09 '22 11:10

francek