Me pregunto cuál es la forma correcta de invertir este cálculo:

float x = a * 25.0f + b; // where a and b are integers and b is in [0-25[

¿Cómo puedo evitar posibles errores de redondeo de punto flotante? Las respuestas son obvias incluso si x tiene algún error, por lo que debería ser posible implementarlo.

-1
Adam Hunyadi 23 may. 2017 a las 14:56

2 respuestas

La mejor respuesta

Intente usar modulo arithmetics , es decir, la división entera / y el resto %:

int a = ((int) (x + 0.5f)) / 25; 
int b = ((int) (x + 0.5f)) % 25; 

Si x puede tener errores de redondeo , p. x = 53.999997 en lugar de 54 y luego redondear al entero más cercano: (int) (x + 0.5f). Tenga en cuenta que x debe ser lo suficientemente pequeño para ser lanzado a int: x = 1e30f definitivamente fallará.

0
Dmitry Bychenko 23 may. 2017 a las 12:11

Para el rango de a que diste, no puedes recuperar b con seguridad.

Para a = 10 ^ 6, necesitas 20 bits. Si multiplica por 25, necesita 5 bits más. Por lo tanto, para valores extremos de a, necesitará 25 bits de significado para representar x. El flotador de precisión simple IEEE 754 solo le ofrece 24. Eso significa que x puede perder el bit menos significativo. En lugar del valor verdadero x, tienes x +/- 1.

Pero tiene acceso a más información:

  • si x <2 ^ 24, entonces sabe que puede recuperar bya mediante un algoritmo ingenuo
  • si x> = 2 ^ 24 y el significado es impar ((int)(x))%4 == 2, entonces sabe que no se realizó ningún redondeo. De hecho, cancelar el último bit es un caso de empate exacto y conduce a un redondeo al par más cercano en el modo de redondeo predeterminado IEEE 754.
  • solo en el caso de x> = 2 ^ 24 y el significado es par, no puede concluir, y tiene 3 valores posibles para la pareja {a, b}.

Conclusión: deberás usar doble precisión aquí

1
aka.nice 9 jun. 2017 a las 19:33