2 votos

Calcular el número total de números en coma flotante en un rango determinado

Esto se inspiró en esta pregunta de Stack Overflow .

Actualmente está en espera como off-topic y downvoted, así que por si acaso se borra aquí está la captura de pantalla (para nosotros los menos mortales con menos de 10K rep en ese sitio): enter image description here

El programa está tratando de enumerar todos los double valores entre estos dos números:

0.009999999999999999999999999999
0.099999999999999999999999999999

El código de la captura de pantalla no lo hará realmente, pero dejemos eso de lado por ahora.

Para aquellos que no estén familiarizados con el sistema de tipos de C#, un doble es un número en coma flotante (que se utiliza para representar números reales) con los siguientes atributos:

El tipo de valor Double representa un número de 64 bits de doble precisión con valores que van de 1,79769313486232e308 negativo a 1,79769313486232e308 positivo, así como cero positivo o negativo, PositiveInfinity, NegativeInfinity y no un número (NaN). Está pensado para representar valores extremadamente grandes (como las distancias entre planetas o galaxias) o extremadamente pequeños (la masa molecular de una sustancia en kilogramos) y que a menudo son imprecisos (como la distancia de la Tierra a otro sistema solar). El tipo Double cumple la norma IEC 60559:1989 (IEEE 754) para la aritmética binaria de punto flotante.

Ahora, obviamente, hay un número infinito de números reales entre estos valores, pero sólo un número finito de números en coma flotante (ya que cualquier número en un ordenador real sólo puede tener, obviamente, un número finito de dígitos).

La otra cosa que hay que entender es Doble.Epsilon que es la siguiente constante:

El valor de la propiedad Epsilon refleja el menor valor positivo de Double que es significativo en operaciones numéricas o comparaciones cuando el valor de la instancia Double es cero...

Más concretamente, el formato de punto flotante consta de un signo, una mantisa o significante de 52 bits y un exponente de 11 bits. Como muestra el siguiente ejemplo, el cero tiene un exponente de -1022 y una mantisa de 0. Epsilon tiene un exponente de -1022 y una mantisa de 1. Esto significa que Epsilon es el menor valor positivo de Double mayor que cero y representa el menor valor posible y el menor incremento posible para un Double cuyo exponente es -1022.

Mi pregunta, entonces: ¿cuántos números dobles hay entre 0,0099999999999999999999 y 0,099999999999999999999999999999?

Si no me equivoco, creo que preguntar cuántos números hay entre 0,009999999999999999999999 y 0,0999999999999999999999999999 es exactamente lo mismo que preguntar cuántos números hay entre 0,0 y 0,09 (que además es bastante más cómodo de leer y trabajar).

Como experimento, he probado el siguiente programa para tener una mejor idea del tamaño del número (sin esperar que se complete la ejecución):

double num = 0.0;
long count = 0;

// Loop through all of the double numbers from 0.0 to 0.09
while (num <= 0.09)
{
    // Add the smallest possible increment
    num += Double.Epsilon;

    // Keep count of how many there are
    count++;
}

// Print the number at the end
Console.WriteLine(count);

Detuve el programa después de dejarlo correr por un tiempo; el número actual era 1.86324012918674E-314 y el conteo era 3,771,240,006.

Sospecho fuertemente que podrías hacer alguna forma de aritmética en los exponentes o posiblemente establecer esto como una permutación de algún tipo; ¿hay una ecuación que pueda describir este problema?

4voto

Shabaz Puntos 403

Tienes que mirar la estructura de cómo se almacena un número de punto flotante. En la norma IEEE 754 se define que un flotante de 64 bits tiene un bit de signo SS , 1111 bits de exponente EE y 5353 bits de mantisa MM . El primer bit de la mantisa es siempre 11 y no se almacena, por lo que sólo 5252 los bits se almacenan. El valor es (1)S2E1023M(1)S2E1023M donde MM está en binario con el punto radial después del primer bit (no almacenado). Esto da que hay 252252 valores de MM por lo que para cada valor del exponente obtenemos 252252 números de punto flotante.

Para contar los números entre n1=0.009999999999999999999999999999n1=0.009999999999999999999999999999 y n2=0.099999999999999999999999999999n2=0.099999999999999999999999999999 primero contamos los pasos completos del exponente, y luego manejamos los pasos parciales al final. n1<26=0.015625n1<26=0.015625 y n2>24=0.0625n2>24=0.0625 por lo que obtenemos 32523252 números allí. En el paso donde la parte del exponente es 2727 el ϵϵ est 259259 por lo que hay 259(0.015625n1)=3242591731706757259(0.015625n1)=3242591731706757 . En el paso donde el exponente es 2323 el ϵϵ est 255255 , por lo que hay 255(n20.0625)=13510798882111487255(n20.0625)=13510798882111487 . Si mis habilidades de copiar y pegar funcionan el total es 3026418949592973230264189495929732 Creo que el redondeo es correcto. No me importa intentar enumerarlas todas. Definitivamente no es lo mismo que de 00 a 0.090.09 porque eso tiene más de 10001000 pasos de un factor dos, por lo que sobre 10002521000252 números. En coma flotante los números son muy densos cerca del cero. Usted está añadiendo un tramo cerca de cero, por lo que la adición de un montón de números y no la eliminación de casi tantos ya que el tramo eliminado es "lejos de cero".

Si se dispone de la herramienta adecuada, se puede obtener la representación binaria de n1n1 y n2n2 y restarlos. Como las representaciones en coma flotante están ordenadas de la misma manera que los valores correspondientes, eso te dará la cuenta. Recuerda que debes restar uno porque no debes contar ninguno de los extremos.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X