simple precisión float doble c++ double standards precision ieee-754

c++ - precisión - precision simple y doble



¿Están todos los valores enteros perfectamente representados como dobles? (5)

La respuesta corta es "posiblemente". La respuesta portátil es "no en todas partes".

Realmente depende de su plataforma y, en particular, de

  • el tamaño y la representación de double
  • el rango de int

Para plataformas que usan dobles IEEE-754, puede ser cierto si int es de 53 bits o menor. Para plataformas donde int es mayor que el double , obviamente es falso.

Es posible que desee investigar las propiedades en su host de tiempo de ejecución, usando std::numeric_limits y std::nextafter .

Esta pregunta ya tiene una respuesta aquí:

Mi pregunta es si todos los valores enteros tienen garantizada una representación doble perfecta.

Considere el siguiente ejemplo de código que imprime "Mismo":

// Example program #include <iostream> #include <string> int main() { int a = 3; int b = 4; double d_a(a); double d_b(b); double int_sum = a + b; double d_sum = d_a + d_b; if (double(int_sum) == d_sum) { std::cout << "Same" << std::endl; } }

¿Se garantiza que esto sea cierto para cualquier arquitectura, cualquier compilador, cualquier valor de a y b ? ¿ i.0000000000000 entero que haya convertido a double siempre se representará como i.0000000000000 y no, por ejemplo, como i.000000000001 ?

Lo probé para otros números y siempre fue cierto, pero no pude encontrar nada sobre si esto es una coincidencia o por diseño.

Nota: Esto es diferente de esta pregunta (aparte del idioma) ya que estoy agregando los dos enteros.


La respuesta es no. Esto solo funciona si int s son de 32 bits, lo que, aunque es cierto en la mayoría de las plataformas, no está garantizado por el estándar.

Los dos enteros pueden compartir la misma doble representación.

Por ejemplo, this

#include <iostream> int main() { int64_t n = 2397083434877565865; if (static_cast<double>(n) == static_cast<double>(n - 1)) { std::cout << "n and (n-1) share the same double representation/n"; } }

imprimirá

n y (n-1) comparten la misma doble representación

Es decir, tanto 2397083434877565865 como 2397083434877565864 se convertirán al mismo double .

Tenga en cuenta que usé int64_t aquí para garantizar enteros de 64 bits, que, dependiendo de su plataforma, también podría ser lo que es int .


No. Suponga que tiene un tipo entero de 64 bits y un tipo de coma flotante de 64 bits (que es típico para un double ). Hay 2 ^ 64 valores posibles para ese tipo de entero y hay 2 ^ 64 valores posibles para ese tipo de punto flotante. Pero algunos de esos valores de punto flotante (de hecho, la mayoría de ellos) no representan valores enteros, por lo que el tipo de punto flotante puede representar menos valores enteros que el tipo entero.


Tienes 2 preguntas diferentes:

¿Están todos los valores enteros perfectamente representados como dobles?

Eso ya fue respondido por otras personas (TL; DR: depende de la precisión de int y double ).

Considere el siguiente ejemplo de código que imprime "Mismo": [...] ¿Se garantiza que esto sea cierto para cualquier arquitectura, cualquier compilador, cualquier valor de a y b?

Su código agrega dos int sy luego convierte el resultado al doble. La suma de int s se desbordará para ciertos valores, pero la suma de los dos double s convertidos por separado no lo hará (típicamente). Para esos valores los resultados serán diferentes.


Descargo de responsabilidad (según lo sugerido por Toby Speight): aunque las representaciones de IEEE 754 son bastante comunes, una implementación puede usar cualquier otra representación que satisfaga los requisitos del lenguaje.

Los dobles se representan en la forma mantissa * 2^exponent , es decir, algunos de los bits se utilizan para la parte no entera del número doble.

bits range precision float 32 1.5E-45 .. 3.4E38 7- 8 digits double 64 5.0E-324 .. 1.7E308 15-16 digits long double 80 1.9E-4951 .. 1.1E4932 19-20 digits

La parte en la fracción también se puede usar para representar un número entero mediante el uso de un exponente que elimina todos los dígitos después del punto.

Por ejemplo, 2,9979 · 10 ^ 4 = 29979.

Dado que un int común suele ser de 32 bits, puede representar todos los int s como dobles, pero para enteros de 64 bits, por supuesto, esto ya no es cierto. Para ser más precisos (como LThode señaló en un comentario): la doble precisión IEEE 754 puede garantizar esto hasta 53 bits (52 bits de significado y el 1 bit implícito inicial).

Respuesta : sí para entradas de 32 bits, no para entradas de 64 bits.

(Esto es correcto para entornos de CPU de propósito general de servidor / escritorio, pero otras arquitecturas pueden comportarse de manera diferente).

Respuesta práctica como lo expresa Malcom McLean: los dobles de 64 bits son un tipo entero adecuado para casi todos los enteros que puedan contar cosas en la vida real.

Para los empíricamente inclinados, intente this :

#include <iostream> #include <limits> using namespace std; int main() { double test; volatile int test_int; for(int i=0; i< std::numeric_limits<int>::max(); i++) { test = i; test_int = test; // compare int with int: if (test_int != i) std::cout<<"found integer i="<<i<<", test="<<test<<std::endl; } return 0; }

Tiempo de éxito: 0,85 memoria: señal 15240: 0

Subconsulta : Con respecto a la pregunta de diferencias fraccionarias. ¿Es posible tener un número entero que se convierta en un doble que esté justo fuera del valor correcto en una fracción, pero que se convierta nuevamente al mismo número entero debido al redondeo?

La respuesta es no, porque cualquier número entero que se convierte de ida y vuelta al mismo valor, en realidad representa el mismo valor entero en doble. Para mí, la explicación más simple (sugerida por ilkkachu) para esto es que usando el exponente 2^exponent el ancho del paso siempre debe ser una potencia de dos. Por lo tanto, más allá del número entero de 52 bits más grande (signo +1), nunca hay dos valores dobles con una distancia menor que 2, lo que resuelve el problema de redondeo.