¿Cuál es la diferencia entre float y double?

He leído sobre la diferencia entre la precisión doble y la precisión simple. Sin embargo, en la mayoría de los casos, float y double parecen intercambiables, es decir, el uso de uno u otro parece no afectar los resultados. ¿Es este realmente el caso? ¿Cuándo son flotantes y dobles intercambiables? Cuáles son las diferencias entre ellos?

Gran diferencia.

Como su nombre lo indica, un double tiene 2 veces la precisión de float [1] . En general, un double tiene 15 dígitos decimales de precisión, mientras que el float tiene 7.

Así es como se calcula el número de dígitos:

double tiene 52 bits de mantisa + 1 bit oculto: log (2 53 ) ÷ log (10) = 15.95 dígitos

float tiene 23 bits de mantisa + 1 bit oculto: log (2 24 ) ÷ log (10) = 7.22 dígitos

Esta pérdida de precisión podría conducir a errores de truncamiento mucho más fáciles de flotar, por ejemplo

 float a = 1.f / 81; float b = 0; for (int i = 0; i < 729; ++ i) b += a; printf("%.7g\n", b); // prints 9.000023 

mientras

 double a = 1.0 / 81; double b = 0; for (int i = 0; i < 729; ++ i) b += a; printf("%.15g\n", b); // prints 8.99999999999996 

Además, el valor máximo de float es aproximadamente 3e38 , pero el doble es aproximadamente 1.7e308 , por lo que usar float puede alcanzar "infinito" (es decir, un número especial de coma flotante) mucho más fácil que double algo simple, por ejemplo, calcular el factorial de 60 .

Durante las pruebas, tal vez algunos casos de prueba contengan estos números enormes, lo que puede hacer que sus progtwigs fallen si usa flotadores.


Por supuesto, a veces, incluso el double no es lo suficientemente preciso, por lo tanto, a veces tenemos long double [1] (el ejemplo anterior da 9.000000000000000066 en Mac), pero todos los tipos de coma flotante sufren errores de redondeo , por lo que si la precisión es muy importante (por ejemplo, procesamiento de dinero) debe usar int o una clase de fracción.


Además, no use += para sumr muchos números de coma flotante, ya que los errores se acumulan rápidamente. Si está usando Python, use fsum . De lo contrario, intente implementar el algoritmo de sum Kahan .


[1]: los estándares C y C ++ no especifican la representación de float , double y long double . Es posible que los tres estén implementados como IEEE de doble precisión. Sin embargo, para la mayoría de las architectures (gcc, MSVC; x86, x64, ARM) el float es realmente un número de coma flotante de precisión simple IEEE (binary32) y el double es un número de coma flotante de doble precisión IEEE (binary64).

Esto es lo que dicen las normas estándar C99 (ISO-IEC 9899 6.2.5 §10) o C ++ 2003 (ISO-IEC 14882-2003 3.1.9 §8):

Hay tres tipos de punto flotante: float , double y long double . El tipo double proporciona al menos tanta precisión como float , y el tipo long double proporciona al menos tanta precisión como el double . El conjunto de valores del tipo float es un subconjunto del conjunto de valores del tipo double ; el conjunto de valores del tipo double es un subconjunto del conjunto de valores del tipo long double .

El estándar C ++ agrega:

La representación del valor de los tipos de coma flotante está definida por la implementación.

Sugeriría echar un vistazo al excelente Lo que todo científico debería saber sobre la aritmética de punto flotante que cubre el estándar de coma flotante IEEE en profundidad. Aprenderá sobre los detalles de representación y se dará cuenta de que hay una compensación entre magnitud y precisión. La precisión de la representación del punto flotante aumenta a medida que la magnitud disminuye, por lo tanto, los números de coma flotante entre -1 y 1 son los que tienen la mayor precisión.

Dada una ecuación cuadrática: x 2 – 4.0000000 x + 3.9999999 = 0, las raíces exactas a 10 dígitos significativos son, r 1 = 2.000316228 yr 2 = 1.999683772.

Usando float y double , podemos escribir un progtwig de prueba:

 #include  #include  void dbl_solve(double a, double b, double c) { double d = b*b - 4.0*a*c; double sd = sqrt(d); double r1 = (-b + sd) / (2.0*a); double r2 = (-b - sd) / (2.0*a); printf("%.5f\t%.5f\n", r1, r2); } void flt_solve(float a, float b, float c) { float d = b*b - 4.0f*a*c; float sd = sqrtf(d); float r1 = (-b + sd) / (2.0f*a); float r2 = (-b - sd) / (2.0f*a); printf("%.5f\t%.5f\n", r1, r2); } int main(void) { float fa = 1.0f; float fb = -4.0000000f; float fc = 3.9999999f; double da = 1.0; double db = -4.0000000; double dc = 3.9999999; flt_solve(fa, fb, fc); dbl_solve(da, db, dc); return 0; } 

Ejecutar el progtwig me da:

 2.00000 2.00000 2.00032 1.99968 

Tenga en cuenta que los números no son grandes, pero aún obtiene efectos de cancelación mediante float .

(De hecho, lo anterior no es la mejor manera de resolver ecuaciones cuadráticas utilizando números de coma flotante de precisión simple o doble, pero la respuesta permanece sin cambios incluso si se usa un método más estable .)

  • Un doble es 64 y la precisión simple (flotante) es de 32 bits.
  • El doble tiene una mantisa más grande (los bits enteros del número real).
  • Cualquier inexactitud será más pequeña en el doble.

El tamaño de los números involucrados en los cálculos de punto flotante no es lo más relevante. Es el cálculo que se está realizando lo que es relevante.

En esencia, si está realizando un cálculo y el resultado es un número irracional o un decimal recurrente, habrá errores de redondeo cuando ese número se aplasta en la estructura de datos de tamaño finito que está utilizando. Como el doble es el doble del flotador, el error de redondeo será mucho menor.

Las pruebas pueden usar números específicos que causarían este tipo de error y, por lo tanto, probaron que había utilizado el tipo apropiado en su código.

Los flotadores tienen menos precisión que los dobles. Aunque ya sabes, lee Lo que debemos saber sobre la aritmética de coma flotante para una mejor comprensión.

Tipo flotante, 32 bits de largo, tiene una precisión de 7 dígitos. Si bien puede almacenar valores con un rango muy grande o muy pequeño (+/- 3.4 * 10 ^ 38 o * 10 ^ -38), solo tiene 7 dígitos significativos.

Tipo doble, 64 bits de largo, tiene un rango mayor (* 10 ^ + / – 308) y 15 dígitos de precisión.

Tipo largo doble es nominalmente 80 bits, aunque un par de comstackdor / sistema operativo dado puede almacenarlo como 12-16 bytes para fines de alineación. El doble largo tiene un exponente que es ridículamente enorme y debería tener 19 dígitos de precisión. Microsoft, en su sabiduría infinita, limita el doble largo a 8 bytes, lo mismo que el doble simple.

En términos generales, solo use tipo doble cuando necesite un valor / variable de punto flotante. Los valores de coma flotante literal utilizados en las expresiones se tratarán como dobles de forma predeterminada, y la mayoría de las funciones matemáticas que devuelven los valores de coma flotante se duplican. Te ahorrarás muchos dolores de cabeza y tipos de letra si solo utilizas el doble.

Acabo de encontrarme con un error que me demoró para siempre en descifrarlo y posiblemente pueda darte un buen ejemplo de precisión de flotación.

 #include  #include  int main(){ for(float t=0;t<1;t+=0.01){ std::cout << std::fixed << std::setprecision(6) << t << std::endl; } } 

El resultado es

 0.000000 0.010000 0.020000 0.030000 0.040000 0.050000 0.060000 0.070000 0.080000 0.090000 0.100000 0.110000 0.120000 0.130000 0.140000 0.150000 0.160000 0.170000 0.180000 0.190000 0.200000 0.210000 0.220000 0.230000 0.240000 0.250000 0.260000 0.270000 0.280000 0.290000 0.300000 0.310000 0.320000 0.330000 0.340000 0.350000 0.360000 0.370000 0.380000 0.390000 0.400000 0.410000 0.420000 0.430000 0.440000 0.450000 0.460000 0.470000 0.480000 0.490000 0.500000 0.510000 0.520000 0.530000 0.540000 0.550000 0.560000 0.570000 0.580000 0.590000 0.600000 0.610000 0.620000 0.630000 0.640000 0.650000 0.660000 0.670000 0.680000 0.690000 0.700000 0.710000 0.720000 0.730000 0.740000 0.750000 0.760000 0.770000 0.780000 0.790000 0.800000 0.810000 0.820000 0.830000 0.839999 0.849999 0.859999 0.869999 0.879999 0.889999 0.899999 0.909999 0.919999 0.929999 0.939999 0.949999 0.959999 0.969999 0.979999 0.989999 0.999999 

Como puede ver después de 0.83, la precisión se reduce significativamente.

Sin embargo, si configuro t como el doble, tal problema no ocurrirá.

Me tomó cinco horas darme cuenta de este error menor, que arruinó mi progtwig.

Al usar números de coma flotante, no puede confiar en que sus pruebas locales serán exactamente las mismas que las que se realizan en el servidor. El entorno y el comstackdor son probablemente diferentes en su sistema local y donde se ejecutan las pruebas finales. He visto este problema muchas veces antes en algunas competiciones de TopCoder, especialmente si intentas comparar dos números de coma flotante.

Las operaciones de comparación incorporadas difieren al comparar 2 números con coma flotante, la diferencia en el tipo de datos (es decir, flotante o doble) puede dar como resultado diferentes resultados.

A diferencia de un int (número entero), un float tiene un punto decimal, y también un double . Pero la diferencia entre los dos es que un double es dos veces más detallado que un float , lo que significa que puede tener el doble de la cantidad de números después del punto decimal.