2012-09-26 61 views
42
float a = 0; 
while (true) 
{ 
    a++; 
    if (a > 16777216) 
     break; // Will never break... a stops at 16777216 
} 

¿Alguien puede explicarme por qué un valor flotante deja de incrementarse en 16777216 en este código?¿Por qué una variable flotante deja de incrementarse en 16777216 en C#?

Editar:

O aún más simple:

float a = 16777217; // a becomes 16777216 
+0

http://stackoverflow.com/questions/3448777/how-to-represent-0-1-in-floating-point-arithmetic-and-decimal – horgh

+0

http://stackoverflow.com/questions/6275327/understanding-floating-point-representation-errors-whats-wrong-with-my-thinkin – horgh

+5

Si algo así te atrapa, te aconsejo encarecidamente que leas: Lo que todo científico de la computación debería saber saber sobre la aritmética de punto flotante. Explica cómo se implementan en el hardware y cubre todos los errores que eventualmente se encontrarán. http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html –

Respuesta

47

Roundup corto de números de punto flotante IEEE-754 (32 bits) de la parte superior de la cabeza:

  • 1 bit de signo (0 significa número positivo, 1 significa número negativo)
  • 8 bit exponente (-127 con sesgo, no es importante aquí)
  • 23 bits "mantisa"
  • con excepciones para el exponente valores 0 y 255, se puede calcular el valor como: (sign ? -1 : +1) * 2^exponent * (1.0 + mantissa)
    • Los bits de mantisa representan dígitos binariosdespués de el separador decimal, p. Ej. 1001 0000 0000 0000 0000 000 = 2^-1 + 2^-4 = .5 + .0625 = .5625 y el valor delante del separador decimal no se almacena pero se asume implícitamente como 1 (si el exponente es 255, se asume 0 pero eso no es importante aquí), por ejemplo, para un exponente de 30, este ejemplo de mantisa representa el valor 1.5625

Ahora con su ejemplo:

16777216 es exactamente 2 , y se representaría como flotante de 32 bits, así:

  • signo = 0 (número positivo)
  • exponente = 24 (almacenados como 24 + 127 = 151 = 10010111)
  • mantisa =.0
  • como 32 bits de representación de coma flotante: 0 10010111 00000000000000000000000
  • Por lo tanto: Valor = (+1) * 2^24 * (1.0 + .0) = 2^24 = 16777216

Ahora vamos a ver el número 16777217, o exactamente 2 1:

  • signo y exponente son los mismos
  • mantisa tendrían que ser exactamente 2 -24 para que (+1) * 2^24 * (1.0 + 2^-24) = 2^24 + 1 = 16777217
  • Y aquí está el problema. La mantisa no puede tener el valor 2 -24 porque solo tiene 23 bits, por lo que el número 16777217 simplemente no se puede representar con la precisión de los números de coma flotante de 32 bits.
10

16777217 no se puede representar exactamente con un flotador. El siguiente número más alto que un flotador puede representar exactamente es 16777218.

Por lo tanto, intenta incrementar el valor flotante 16777216 a 16777217, que no se puede representar en un flotante.

11

Cuando observa ese valor en su representación binaria, verá que se trata de uno y muchos ceros, es decir, 1 0000 0000 0000 0000 0000 0000, o exactamente 2^24. Eso significa que, en 16777216, el número acaba de crecer en un dígito.

Como es un número de coma flotante, esto puede significar que el último dígito en su extremo que todavía está almacenado (es decir, dentro de su precisión) también se desplaza hacia la izquierda.

Probablemente, lo que está viendo es que el último dígito de precisión se ha desplazado a algo más grande que uno, por lo que agregar uno ya no hace ninguna diferencia.

+2

¿Puedo aprender la razón del -1? Me gustaría mejorar mi respuesta. –

+1

E incluso si no puedo conocer el motivo de la primera votación negativa, ¿puedo preguntar el motivo de la segunda, por favor? –

2

Imagine esto en forma decimal. Suponga que tiene el número:

1.000000 * 10^6 

o 1,000,000. Si todo lo que tenían eran seis dígitos de precisión, la adición de 0,5 a este número produciría

1.0000005 * 10^6 

Sin embargo, el pensamiento actual con los modos de redondeo fp es el uso de "Ronda a Incluso," en lugar de "redondeo al más cercano." En este caso, cada vez que incremente este valor, volverá a redondear en la unidad de coma flotante a 16,777,216 o 2^24. Los solteros en IEE 754 se representan como:

+/- exponent (1.) fraction 

donde el "1." está implícito y la fracción es otros 23 bits, todos ceros, en este caso. El 1 adicional binario se derramará en el dígito guard, se reducirá al paso de redondeo y se eliminará cada vez, sin importar cuántas veces lo incremente. La unidad ulp o en el último lugar siempre será cero. El último incremento de éxito es de:

+2^23 * (+1.) 11111111111111111111111 -> +2^24 * (1.) 00000000000000000000000 
Cuestiones relacionadas