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


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

Author: nbro, 2010-03-05

11 answers

Enorme diferencia.

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

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

double tiene 52 bits mantissa + 1 bit oculto: log(253)÷log (10) = 15,95 dígitos

float tiene 23 bits mantissa + 1 bit oculto: log(224)÷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 hacia arriba, 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 que

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

También, el valor máximo de float es aproximadamente 3e38, pero double es aproximadamente 1.7e308, por lo que usar float puede golpear "infinito" (es decir, un número especial de punto flotante) mucho más fácilmente que double para algo simple, por ejemplo, computando el factorial de 60.

Durante las pruebas, tal vez algunos casos de prueba contengan estos números enormes, lo que puede causar su programas que fallan si usa flotadores.


Por supuesto, a veces, incluso double no es lo suficientemente preciso, por lo tanto, a veces tenemos long double[1] (el ejemplo anterior da 9.0000000000000000066 en Mac), pero todos los tipos de coma flotante sufren de 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 sumar muchos números de coma flotante, ya que los errores se acumulan pronto. Si estás usando Python, usa fsum. De lo contrario, intente implementar el algoritmo de suma de Kahan .


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

 407
Author: kennytm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-10 10:55:48

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

Hay tres tipos de coma 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 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++ añade:

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

Yo sugeriría echar un vistazo a la excelente Lo que Todo Científico de la Computación Debe Saber Acerca de la Aritmética de Coma Flotante que cubre el estándar de coma flotante IEEE en profundidad. Aprenderá sobre los detalles de la representación y se dará cuenta de que hay un equilibrio entre magnitud y precisión. La precisión de la la representación de coma 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 más precisión.

 50
Author: Gregory Pakosz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-06 17:29:32

Dada una ecuación cuadrática: x2 - 4.0000000 x + 3.9999999 = 0, las raíces exacta a 10 dígitos significativos son, r1 = 2.000316228 y r2 = 1.999683772.

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

#include <stdio.h>
#include <math.h>

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 programa me da:

2.00000 2.00000
2.00032 1.99968

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

(De hecho, lo anterior no es el mejor forma de resolver ecuaciones cuadráticas usando 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.)

 24
Author: Alok Singhal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-05 17:57:25
  • Un doble es 64 y una sola precisión (flotador) es de 32 bits.
  • El doble tiene una mantisa mayor (los bits enteros del número real).
  • Cualquier inexactitud será menor en el doble.
 18
Author: graham.reeds,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-05 12:53:20

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 que es relevante.

En esencia, si está realizando un cálculo y el resultado es un número irracional o decimal recurrente, entonces habrá errores de redondeo cuando ese número se aplaste en la estructura de datos de tamaño finito que está utilizando. Dado que double es el doble del tamaño de float, el error de redondeo será mucho más pequeño.

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

 11
Author: Dolbz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-10 11:05:03

Los flotadores tienen menos precisión que los dobles. Aunque ya lo sabes, lee Lo Que Deberíamos Saber Sobre la Aritmética de Coma Flotante para una mejor comprensión.

 8
Author: N 1.1,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-05 13:09:51

Tipo flotador, 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), tiene solo 7 dígitos significativos.

El tipo doble, de 64 bits de largo, tiene un rango más grande (*10^+/-308) y una precisión de 15 dígitos.

El tipo long double es nominalmente de 80 bits, aunque un emparejamiento compilador/sistema operativo dado puede almacenarlo como 12-16 bytes para propósitos de alineación. El doble largo tiene un exponente que simplemente ridículamente enorme y debe tener precisión de 19 dígitos. 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 type double cuando necesite un valor/variable de punto flotante. Los valores literales de coma flotante utilizados en expresiones se tratarán como dobles por defecto, y la mayoría de las funciones matemáticas que devuelven valores de coma flotante devuelven dobles. Te ahorrarás muchos dolores de cabeza y encasillamientos si usas doble.

 8
Author: Humble Coder,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-11-17 23:29:38

Me encontré con un error que me llevó una eternidad averiguar y potencialmente puede darle un buen ejemplo de precisión de flotador.

#include <iostream>
#include <iomanip>

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

La salida 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 disminuye significativamente.

Sin embargo, si configuro t como double, tal problema no sucederá.

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

 7
Author: Elliscope Fang,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-03-10 11:06:08

Al usar números de coma flotante, no puede confiar en que sus pruebas locales sean exactamente las mismas que las pruebas que se realizan en el lado del servidor. El entorno y el compilador 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.

 3
Author: Tuomas Pelkonen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-03-05 13:00:57

Las operaciones de comparación integradas difieren como cuando se comparan 2 números con coma flotante, la diferencia en el tipo de datos (es decir, flotante o doble) puede dar lugar a resultados diferentes.

 2
Author: Johnathan Lau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-11-05 01:35:45

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

 -1
Author: Nykal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-09-05 12:10:09