salida extraña en comparación de float con float literal


float f = 0.7;
if( f == 0.7 )
    printf("equal");
else
    printf("not equal");

¿Por qué es la salida not equal?

¿por Qué sucede esto?

Author: Bo Persson, 2009-12-03

6 answers

Esto sucede porque en su declaración

  if(f == 0.7)

El 0.7 se trata como un doble. Intente 0.7 f para asegurarse de que el valor se trata como un flotador:

  if(f == 0.7f)

Pero como Michael sugirió en los comentarios a continuación, nunca debe probar la igualdad exacta de los valores de coma flotante.

 49
Author: halfdan,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-12-06 11:53:07

Esta respuesta para complementar las existentes: tenga en cuenta que 0.7 no es representable exactamente como un flotador (o como un doble). Si se representara exactamente, entonces no habría pérdida de información al convertir a float y luego volver a double, y no tendría este problema.

Incluso se podría argumentar que debería haber una advertencia del compilador para constantes literales de coma flotante que no se pueden representar exactamente, especialmente cuando el estándar es tan borroso con respecto a si el redondeo se realizará en tiempo de ejecución en el modo que se ha establecido como ese momento o en tiempo de compilación en otro modo de redondeo.

Todos los números no enteros que se pueden representar exactamente tienen 5 como su último dígito decimal. Desafortunadamente, lo contrario no es cierto: algunos números tienen 5 como su último dígito decimal y no se pueden representar exactamente. Los enteros pequeños se pueden representar exactamente, y la división por una potencia de 2 transforma un número que se puede representar en otro que puede ser representado, siempre y cuando no entre en el reino de los números desnormalizados.

 14
Author: Pascal Cuoq,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-06-21 16:05:59

En primer lugar vamos a mirar dentro del número flotante. Tomo 0.1 f es de 4 bytes de largo (binary32), en hexadecimal es
3D CC CC CD .
Por el estándar IEEE 754 para convertirlo a decimal debemos hacer así:

introduzca la descripción de la imagen aquí
En binario 3D CC CC CD es
0 01111011 1001100 11001100 11001101
aquí el primer dígito es un bit de signo. 0 (-1)^0 que nuestro número es positivo.
Segundo 8 bits es un Exponente. En binario es 01111011-en decimal 123. Pero el exponente real es 123-127 (siempre 127)=-4, es decir que necesitamos multiplicar el número que obtendremos por 2^(-4).
Los últimos 23 bytes es la precisión Significand. Allí el primer pedacito multiplicamos por 1/(2^1) (0.5), segundo por 1/(2^2) (0.25) y así sucesivamente. Aquí lo que obtenemos:


introduzca la descripción de la imagen aquí introduzca la descripción de la imagen aquí

Necesitamos agregar todos los números(potencia de 2) y agregarle 1 (siempre 1, por standart). Es
1,60000002384185791015625
Ahora vamos a multiplicar este número por 2^(-4), es de Exponente. Acabamos de dividir el número de arriba por 2 cuatro veces:
0,100000001490116119384765625
He utilizado MS Calculator


**

Ahora la segunda parte. Conversión de decimal a binario.

**
Tomo el número 0.1
Es fácil porque no hay parte entera. Primer bit de signo-es 0. Exponente y precisión Significand voy a calcular ahora. La lógica es multiplicar por 2 número entero (0.1 * 2 = 0.2)y si es mayor que 1 restar y continuar.
introduzca la descripción de la imagen aquí
Y el número es .00011001100110011001100110011, standart dice que debemos cambiar a la izquierda antes de obtener 1.(algo). Como ves necesitamos 4 turnos, a partir de este número calculando Exponente(127-4=123). Y la precisión significativa ahora es
10011001100110011001100(y hay partes perdidas).
Ahora el número entero. Bit de signo 0 Exponente es 123 (01111011) y la Mantisa es de precisión 10011001100110011001100 y todo es
00111101110011001100110011001100 comparémoslo con los que tenemos del capítulo anterior
00111101110011001100110011001101
Como ves, los últimos bits no son iguales. Es porque trunco el número. La CPU y el compilador saben que el es algo después de Significand precisión no puede sostener y acaba de establecer el último bit a 1.

 6
Author: Alexandr,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-12 09:21:44

El problema que está enfrentando es, como otros comentaristas han señalado, que generalmente no es seguro probar la equivalencia exacta entre flotadores, ya que los errores de inicialización o los errores de redondeo en los cálculos pueden introducir diferencias menores que harán que el operador == devuelva false.

Una mejor práctica es hacer algo como

float f = 0.7;
if( fabs(f - 0.7) < FLT_EPSILON )
    printf("equal");
else
    printf("not equal");

Asumiendo que FLT_EPSILON ha sido definido como un valor flotante apropiadamente pequeño para su plataforma.

Puesto que el redondeo o es poco probable que los errores de inicialización excedan el valor de FLT_EPSILON, esto le dará la prueba de equivalencia confiable que está buscando.

 1
Author: Kevin Mack,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-21 00:24:25

Considera esto:

int main()
{
    float a = 0.7;
    if(0.7 > a)
        printf("Hi\n");
    else
        printf("Hello\n");
    return 0;
}

Si (0.7 > a) aquí a es una variable flotante y 0.7 es una constante doble. La constante doble 0.7 es mayor que la variable flotante a. Por lo tanto, la condición if se cumple y se imprime 'Hi'

Ejemplo:

int main()
{
    float a=0.7;
    printf("%.10f %.10f\n",0.7, a);
    return 0;
}

Salida:
0.7000000000 0.6999999881

 0
Author: Setu Basak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-05 06:43:56

Muchas de las respuestas alrededor de la web cometen el error de mirar la diferencia abosulute entre los números de coma flotante, esto solo es válido para casos especiales, la forma robusta es mirar la diferencia relativa como se muestra a continuación:

      // Floating point comparison:

        bool CheckFP32Equal(float referenceValue, float value)
        {
           const float fp32_epsilon = float(1E-7);
           float abs_diff = std::abs(referenceValue - value);

           // Both identical zero is a special case
           if( referenceValue==0.0f && value == 0.0f)
              return true;

           float rel_diff = abs_diff / std::max(std::abs(referenceValue) , std::abs(value) ); 

           if(rel_diff < fp32_epsilon)
                 return true;
           else 
                 return false;

        }
 0
Author: Jimmy Pettersson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-26 16:57:57