escala apropiada para la conversión a través de BigDecimal a punto flotante

rwallace:

He escrito una clase de números racionales de precisión arbitraria que necesita para proporcionar una forma de convertir a punto flotante. Esto se puede hacer sin rodeos a través de BigDecimal:

return new BigDecimal(num).divide(new BigDecimal(den), 17, RoundingMode.HALF_EVEN).doubleValue();

pero esto requiere un valor para el parámetro de escala cuando se dividen los números decimales. Recogí 17 como la conjetura inicial, ya que es aproximadamente la precisión de un doble precisión el número de coma flotante, pero no sé si eso es realmente correcto.

¿Cuál sería el número correcto de uso, que se define como el número más pequeño de tal manera que lo que cualquier mayor no tendría la respuesta más precisa?

Eric Postpischil:

Introducción

No es suficiente precisión finita.

El problema planteado en la pregunta es equivalente a:

  • Lo precisión p garantiza que la conversión de los números racionales x de p dígitos decimales y luego a punto flotante se obtiene el número de coma flotante cercana x (o, en caso de empate, ninguno de los dos más cercana x )?

Para ver esto es equivalente, observar que la BigDecimalbrecha se muestra en la pregunta vuelve num/ diva un número seleccionado de cifras decimales. La pregunta entonces se pregunta si el aumento de ese número de decimales podría aumentar la precisión del resultado. Claramente, si hay un número de coma flotante más cerca de x que el resultado, a continuación, la precisión podría mejorarse. Por lo tanto, nos preguntamos cómo se necesitan muchos lugares decimales para garantizar el número de coma flotante más cercano (o uno de los dos atados) se obtiene.

Dado que BigDecimalofrece una selección de los métodos de redondeo, voy a considerar si alguna de ellas es suficiente. Para la conversión a punto flotante, supongo ronda a-cerca con lazos-a-incluso se usa (que BigDecimalparece utilizar al convertir a Doubleo Float). Doy una prueba utilizando el formato binary64 IEEE-754, que utiliza Java para Double, pero la prueba se aplica a cualquier binario formato de punto flotante cambiando el 2 52 utilizado a continuación para 2 w -1 , donde w es el número de bits en el significand.

Prueba

Uno de los parámetros a una BigDecimaldivisión es el método de redondeo. Java BigDecimaldispone de varios métodos de redondeo . Tan sólo hay que tener en cuenta tres, ROUND_UP, ROUND_HALF_UP y ROUND_HALF_EVEN. Los argumentos para los otros son análogos a los de abajo, mediante el uso de diversas simetrías.

A continuación, supongamos que convertir a decimal usando cualquier gran precisión p . Es decir, p es el número de dígitos decimales en el resultado de la conversión.

Deje que m sea el número racional 2 52 + 1 + ½-10 - p . Los dos números binary64 vecinos m son 2 52 1 y 2 52 2. m está más cerca de la primera, de modo que es el resultado que requerimos de la conversión de m primero a decimal y luego a punto flotante.

En decimal, m es 4503599627370497,4999 ..., donde hay p -1 detrás 9s. Cuando redondeado a p dígitos significativos con ROUND_UP, ROUND_HALF_UP, o ROUND_HALF_EVEN, el resultado es 4503599627370497.5 = 2 52 + 1 + ½. (Reconocer que, en la posición donde se produce el redondeo, hay 16 9s arrastran se descartan, efectivamente una fracción de ,9999999999999999 relación a la posición de redondeo. En ROUND_UP, cualquier no-cero cantidad desechada causa redondeo. En ROUND_HALF_UP y ROUND_HALF_EVEN, una descartado cantidad mayor que ½ en esa posición hace que redondeo.)

2 52 + 1 + ½ es igualmente cerca de los números binary64 vecinos 2 52 +1 y 2 52 2, por lo que el método de ronda a-cerca con lazos-to-incluso produce 2 52 2.

Por lo tanto, el resultado es 2 52 2, que no es el valor binary64 más cercana a m .

Por lo tanto, ninguna precisión finita p es suficiente para completar todos los números racionales correctamente.

Supongo que te gusta

Origin http://43.154.161.224:23101/article/api/json?id=313882&siteId=1
Recomendado
Clasificación