Saltar al contenido

¿Cómo calcular el épsilon de punto flotante de 32 bits?

Siéntete libre de divulgar nuestra web y códigos en tus redes, necesitamos tu ayuda para ampliar nuestra comunidad.

Solución:

Cuando el resultado de un cálculo de punto flotante no se puede representar exactamente, se redondea al valor más cercano. Así que quieres encontrar el valor más pequeño X tal que el incremento F = 1/30 es menos de la mitad del ancho h Entre X y el siguiente flotador más grande, lo que significa que x+f se redondeará a X.

Dado que la brecha es la misma para todos los elementos en el mismo binario, sabemos que X debe ser el elemento más pequeño en su binade, que es una potencia de 2.

Así que si X = 2kdespués h = 2k-23 ya que un float tiene un significado de 24 bits. Así que tenemos que encontrar el entero más pequeño k tal que

2k-23/2 > 1/30

lo que implica k > 19.09, por lo tanto k = 20, y X = 220 = 1048576 (segundos).

Tenga en cuenta que X / (60 × 60 × 24) = 12,14 (días), que es un poco menos de lo que propone su respuesta, pero se comprueba empíricamente: en 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

ACTUALIZACIÓN: Bien, entonces, ¿de dónde vino el 12.9? El 12.14 está en tiempo de juego, no en tiempo real: estos habrán divergido debido al error de redondeo involucrado en el punto flotante (especialmente cerca del final, cuando el error de redondeo es bastante grande en relación con F). Hasta donde yo sé, no hay forma de calcular esto directamente, pero en realidad es bastante rápido iterar a través de flotantes de 32 bits.

Nuevamente, en 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 coincide con nuestro resultado que calculamos anteriormente, y t es el tiempo del reloj en 30ths de un segundo. Convirtiendo a días:

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

que está aún más lejos. Así que no sé de dónde vino el 12.9…

ACTUALIZACIÓN 2: supongo que el 12.9 proviene del cálculo

y = 4 × F / ε = 1118481.125 (segundos)

donde ε es el épsilon estándar de la máquina (la brecha entre 1 y el siguiente número de punto flotante más grande). Escalando esto a días da 12.945. Esto proporciona un límite superior en Xpero no es la respuesta correcta como se explicó anteriormente.

#include 
#include 

/*
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 << "nn";

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


    // 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;

Esto produce

epsilon for number 1 is:
0.0000001192092895507812500

epsilon for number 10000000 is:
1.0000000000000000000000000

We can run our game for 12.13630 days.

Puedes auxiliar nuestra tarea ejecutando un comentario o puntuándolo te damos la bienvenida.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *