¿Es la precisión más significativa de los dígitos decimales que se puede convertir en binario y volver a decimal sin pérdida de importancia 6 o 7,225?

He encontrado dos fórmulas de precisión diferentes para números de coma flotante.

⌊ (N-1) log 10 (2) ⌋ = 6 dígitos decimales (precisión única)

y

N log 10 (2) ≈ 7.225 dígitos decimales (precisión única)

Donde N = 24 bits significativos (precisión única)

La primera fórmula se encuentra en la parte superior de la página 4 de ” IEEE Standard 754 for Binary Floating-Point Arithmetic ” escrita por el Profesor W. Kahan .

La segunda fórmula se encuentra en el artículo de Wikipedia ” Formato de coma flotante de precisión simple ” en la sección IEEE 754 formato binario de coma flotante de precisión simple: binary32 .

Para la primera fórmula, el profesor W. Kahan dice

Si una cadena decimal con un máximo de 6 sig. dic. se convierte a Single y luego se convierte de nuevo al mismo número de sig. dec., entonces la secuencia final debe coincidir con el original.

Para la segunda fórmula, Wikipedia dice

… la precisión total es de 24 bits (equivalente a log 10 (2 24 ) ≈ 7.225 dígitos decimales ).

Los resultados de ambas fórmulas (6 y 7.225 dígitos decimales) son diferentes, y esperaba que fueran los mismos porque asumí que los dos estaban destinados a representar los dígitos decimales más significativos que se pueden convertir a binario de coma flotante y luego se pueden volver a convertir a decimal con el mismo número de dígitos decimales significativos con los que comenzó.

¿Por qué estos dos números son diferentes y cuál es la precisión más significativa de los dígitos decimales que se puede convertir a binario y volver a decimal sin pérdida de importancia?

Estos están hablando de dos cosas ligeramente diferentes.

Los 7.225 1 dígitos son la precisión con la que se puede almacenar un número internamente . Por ejemplo, si hiciste un cálculo con un número de precisión doble (por lo que comenzaste con algo así como 15 dígitos de precisión), luego lo redondeaste a un único número de precisión, la precisión que tendrías en ese punto sería aproximadamente 7 dígitos

Los 6 dígitos hablan de la precisión que se puede mantener mediante una conversión de ida y vuelta desde una cadena de dígitos decimales, a un número de coma flotante y luego a otra serie de dígitos decimales.

Entonces, supongamos que empiezo con un número como 1.23456789 como una cadena, luego lo convierto en un float32, luego convierto el resultado a una cadena. Cuando haya hecho esto, puedo esperar que 6 dígitos coincidan exactamente. Sin embargo, el séptimo dígito puede ser redondeado, por lo que no puedo esperar necesariamente que coincida (aunque probablemente será +/- 1 de la cadena original.

Por ejemplo, considere el siguiente código:

 #include  #include  int main() { double init = 987.23456789; for (int i = 0; i < 100; i++) { float f = init + i / 100.0; std::cout << std::setprecision(10) << std::setw(20) << f; } } 

Esto produce una tabla como la siguiente:

  987.2345581 987.2445679 987.2545776 987.2645874 987.2745972 987.2845459 987.2945557 987.3045654 987.3145752 987.324585 987.3345947 987.3445435 987.3545532 987.364563 987.3745728 987.3845825 987.3945923 987.404541 987.4145508 987.4245605 987.4345703 987.4445801 987.4545898 987.4645386 987.4745483 987.4845581 987.4945679 987.5045776 987.5145874 987.5245972 987.5345459 987.5445557 987.5545654 987.5645752 987.574585 987.5845947 987.5945435 987.6045532 987.614563 987.6245728 987.6345825 987.6445923 987.654541 987.6645508 987.6745605 987.6845703 987.6945801 987.7045898 987.7145386 987.7245483 987.7345581 987.7445679 987.7545776 987.7645874 987.7745972 987.7845459 987.7945557 987.8045654 987.8145752 987.824585 987.8345947 987.8445435 987.8545532 987.864563 987.8745728 987.8845825 987.8945923 987.904541 987.9145508 987.9245605 987.9345703 987.9445801 987.9545898 987.9645386 987.9745483 987.9845581 987.9945679 988.0045776 988.0145874 988.0245972 988.0345459 988.0445557 988.0545654 988.0645752 988.074585 988.0845947 988.0945435 988.1045532 988.114563 988.1245728 988.1345825 988.1445923 988.154541 988.1645508 988.1745605 988.1845703 988.1945801 988.2045898 988.2145386 988.2245483 

Si miramos a través de esto, podemos ver que los primeros seis dígitos significativos siempre siguen el patrón con precisión (es decir, cada resultado es exactamente 0.01 mayor que su predecesor). Como podemos ver en el double original, el valor es en realidad 98x.xx456 - pero cuando convertimos el flotador de precisión simple a decimal, podemos ver que el séptimo dígito con frecuencia no se leería correctamente, ya que el el dígito subsiguiente es mayor que 5, debe redondear hasta 98x.xx46, pero algunos de los valores no (por ejemplo, el penúltimo elemento en la primera columna es 988.154541 , que sería redondeado hacia abajo en lugar de hacia arriba, por lo tanto terminaríamos con 98x.xx45 en lugar de 46 Por lo tanto, aunque el valor (tal como está almacenado) es de 7 dígitos (más un poco), para el momento en que realicemos un viaje de ida y vuelta del valor a través de una conversión a decimal y viceversa , no podemos depender de que ese séptimo dígito coincida exactamente más (aunque hay suficiente precisión que lo hará con mucha frecuencia).


1. Eso significa básicamente 7 dígitos, y el 8º dígito será un poco más preciso que nada, pero no mucho; por ejemplo, si estuviéramos convirtiendo desde un doble de 1.2345678 , los dígitos de precisión de .225 significan que el último dígito sería con +/- .775 de lo que comenzó allí (mientras que sin los dígitos de precisión de .225 , sería básicamente +/- 1 de lo que comenzó allí).

¿Cuál es la precisión más significativa de los dígitos decimales que se puede convertir en binario y volver a decimal sin pérdida de importancia?

La precisión más significativa de los dígitos decimales que se puede convertir en binario y volver a decimal sin pérdida de significado (para números de coma flotante de precisión simple o 24 bits) es de 6 dígitos decimales.


¿Por qué estos dos números difieren?

Los números 6 y 7.225 difieren, porque definen dos cosas diferentes. 6 es la mayoría de los dígitos decimales que se pueden disparar en redondo. 7.225 es el número aproximado de precisión de dígitos decimales para un entero binario de 24 bits porque un entero binario de 24 bits puede tener 7 u 8 dígitos decimales dependiendo de su valor específico.

7.225 se encontró usando la fórmula entera binaria específica.

d spec = b · log 10 (2) ( especificación d = dígitos decimales específicos, b = bits)

Sin embargo, lo que normalmente necesita saber son los dígitos decimales mínimo y máximo para un entero de b-bit. Las siguientes fórmulas se utilizan para encontrar los dígitos decimales mínimo y máximo (7 y 8 respectivamente para 24 bits) de un entero binario específico.

d min = ⌈ (b-1) · log 10 (2) ⌉ (d min = dígitos decimales mínimos, b = bits, ⌈x⌉ = mínimo entero ≥ x)

d max = ⌈b · log 10 (2) ⌉ (d max = dígitos decimales máximos, b = bits, ⌈x⌉ = d entero más pequeño ≥ x)

Para obtener más información acerca de cómo se derivan estas fórmulas, lea Número de dígitos decimales en un entero binario , escrito por Rick Regan.

Esto está muy bien, pero puede preguntar, ¿por qué es 6 la mayoría de los dígitos decimales para una conversión de ida y vuelta si dice que el lapso de dígitos decimales para un número de 24 bits es de 7 a 8?

La respuesta es ¡porque las fórmulas anteriores solo funcionan para enteros y no para números de coma flotante!

Cada entero decimal tiene un valor exacto en binario. Sin embargo, no puede decirse lo mismo para cada número decimal de coma flotante. Tome .1 por ejemplo. .1 en binario es el número 0.000110011001100... , que es un binario repetitivo o recurrente. Esto puede producir un error de redondeo.

Además, se necesita un bit más para representar un número de coma flotante decimal que para representar un número entero decimal de igual importancia. Esto se debe a que los números de coma flotante son más precisos cuanto más cerca están de 0 y menos precisos cuanto más lejos están de 0. Debido a esto, muchos números de coma flotante se encuentran cerca de los rangos de valores mínimo y máximo (e min = -126 y e max = +127 para precisión simple) pierde 1 bit de precisión debido a un error de redondeo. Para ver esto visualmente, mira lo que todo progtwigdor de computadoras debe saber sobre punto flotante, parte 1 , escrito por Josh Haberman.

Además, hay al menos 784,757 números decimales positivos de siete dígitos que no pueden retener su valor original después de una conversión de ida y vuelta. Un ejemplo de tal número que no puede sobrevivir al viaje de ida y vuelta es 8.589973e9 . Este es el número positivo más pequeño que no conserva su valor original.

Aquí está la fórmula que debería usar para la precisión del número de coma flotante que le dará 6 dígitos decimales para la conversión de ida y vuelta.

d max = ⌊ (b-1) · log 10 (2) ⌋ (d max = dígitos decimales máximos, b = bits, ⌊x⌋ = mayor entero ≤ x)

Para obtener más información acerca de cómo se deriva esta fórmula, lea Número de dígitos necesarios para las conversiones de ida y vuelta , también escrito por Rick Regan. Rick hace un excelente trabajo mostrando la derivación de fórmulas con referencias a pruebas rigurosas.


Como resultado, puede utilizar las fórmulas anteriores de una manera constructiva; Si comprende cómo funcionan, puede aplicarlos a cualquier lenguaje de progtwigción que utilice tipos de datos de coma flotante. Todo lo que debe saber es el número de bits significativos que tiene su tipo de datos de punto flotante, y puede encontrar su número respectivo de dígitos decimales con los que puede contar para no perder ninguna importancia después de una conversión de ida y vuelta.

Actualización del 18 de junio de 2017: Deseo incluir un enlace al nuevo artículo de Rick Regan, que entra en más detalles y, en mi opinión, responde mejor esta pregunta que cualquier respuesta proporcionada aquí. Su artículo es ” Precisión decimal de números binarios de coma flotante ” y se puede encontrar en su sitio web http://www.exploringbinary.com .

Tenga en cuenta que son exactamente las mismas fórmulas. Recuerde su identidad de libro de matemáticas de la escuela secundaria:

  Log(x^y) == y * Log(x) 

Ayuda a calcular realmente los valores para N = 24 con su calculadora:

  Kahan's: 23 * Log(2) = 6.924 Wikipedia's: Log(2^24) = 7.225 

Kahan se vio forzado a truncar 6.924 con 6 dígitos debido al piso (), fastidio. La única diferencia real es que Kahan usó 1 menos de precisión.

Bastante difícil de adivinar por qué, el profesor podría haber confiado en notas antiguas. Escrito antes de IEEE-754 y sin tener en cuenta que el 24º bit de precisión es gratis. El formato utiliza un truco, el bit más significativo de un valor de punto flotante que no es 0 es siempre 1. Por lo tanto, no es necesario almacenarlo. El procesador lo vuelve a agregar antes de realizar un cálculo. Convertir 23 bits de precisión almacenada en 24 de precisión efectiva.

O tuvo en cuenta que la conversión de una cadena decimal a un valor de punto flotante binario genera un error. Muchos buenos valores decimales redondos, como 0.1, no se pueden convertir perfectamente a binarios. Tiene un número infinito de dígitos, al igual que 1/3 en decimal. Sin embargo, eso genera un resultado que está desactivado en +/- 0.5 bits, logrado por simple redondeo. Entonces el resultado es exacto a 23.5 * Log (2) = 7.074 dígitos decimales. Si supone que la rutina de conversión es torpe y no redondea adecuadamente, el resultado puede ser de +/- 1 bit y N-1 es apropiado. Ellos no son torpes.

O pensó como un científico típico o (el cielo no lo quiera) contable y quiere que el resultado de un cálculo se convierta nuevamente en decimal. Tal como obtendría cuando busque trivialmente un número decimal de 7 dígitos cuya conversión de ida y vuelta no produzca el mismo número. Sí, eso agrega otro error de +/- 0.5 bit, sumndo hasta un total de error de 1 bit.

Pero nunca, nunca cometas ese error, siempre debes incluir los errores que obtienes al manipular el número en un cálculo. Algunos de ellos pierden dígitos significativos muy rápidamente, la sustracción en particular es muy peligrosa.