populares motivation hashtags gym fitness español and c++ c floating-point double-precision

c++ - motivation - hashtags fitness gym



salida extraña en comparación de flotación con flotación literal (6)

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

¿Por qué el resultado not equal ?

¿Por qué pasó esto?


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

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");

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

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


En primer lugar, mire dentro del número de flotador. Tomo 0.1f es 4 bytes de largo (binario32), en hex es
CD 3D CC CC .
Según el estándar IEEE 754 para convertirlo a decimal, debemos hacer esto:


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


Necesitamos agregar todos los números (potencia de 2) y agregarle 1 (siempre 1, por estándar). Es
1,60000002384185791015625
Ahora multipliquemos este número por 2 ^ (- 4), es de Exponente. Simplemente damos el número anterior por 2 cuatro veces:
0,100000001490116119384765625
Utilicé MS Calculator


**

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

**
Tomo el número 0.1
Es fácil porque no hay una parte entera. Primer bit de signo: es 0. Exponente y significación y precisión Lo calcularé ahora. La lógica se multiplica por 2 números enteros (0.1 * 2 = 0.2) y si es mayor que 1 resta y continúa.

Y el número es .00011001100110011001100110011, standart dice que debemos cambiar a la izquierda antes de obtener 1. (algo). Como ve, necesitamos 4 turnos, a partir de este número que calcula el exponente (127-4 = 123 ). Y la significación y precisión ahora es
10011001100110011001100 (y hay bits perdidos).
Ahora el número entero. Sign bit 0 Exponent es 123 ( 01111011 ) y Significand y precisión es 10011001100110011001100 y todo es
00111101110011001100110011001100 comparémoslo con los que tenemos del capítulo anterior
00111101110011001100110011001101
Como puede ver, las últimas partes no son iguales. Es porque trunco ​​el número. La CPU y el compilador saben que hay algo después de que Significand y precision no pueden contenerse y simplemente configuran el último bit en 1.


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 representó exactamente, entonces no habría pérdida de información al convertir a flotación y luego a doble, y no tendría este problema.

Incluso podría argumentarse que debería haber una advertencia de compilación para las constantes literales de coma flotante que no se pueden representar exactamente, especialmente cuando el estándar es tan difuso 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 pueden representarse 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. Todos los enteros pequeños pueden representarse exactamente, y la división por una potencia de 2 transforma un número que se puede representar en otro que se puede representar, siempre y cuando no ingrese al reino de los números desnormalizados.


Esto sucede porque en tu declaración

if(f == 0.7)

el 0.7 se trata como un doble. Prueba 0.7f para asegurarte de que el valor se trata como un flotante:

if(f == 0.7f)

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


Muchas de las respuestas en la Web cometen el error de observar la diferencia de abosulte entre los números de punto flotante, esto solo es válido para casos especiales, la forma más sólida es observar 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; }


Considera esto:

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

if (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. De ahí que se cumpla la condición if e imprima ''Hi''

Ejemplo:

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

Salida:
0.7000000000 0.6999999881