385 votos

Diferencia entre flotante y doble

Lo sé, he leído sobre la diferencia entre la doble precisión y la simple precisión, etc. Pero deberían dar los mismos resultados en la mayoría de los casos, ¿verdad?

Estaba resolviendo un problema en un concurso de programación y había cálculos con números de punto flotante que no eran realmente grandes, así que decidí usar el flotador en lugar del doble, y lo comprobé - estaba obteniendo los resultados correctos. Pero cuando envié la solución, decía que sólo 1 de 10 pruebas era correcta. Lo comprobé una y otra vez, hasta que descubrí que usar el flotador no es lo mismo que usar el doble. Puse el doble para los cálculos y el doble para la salida, y el programa dio los MISMOS resultados, pero esta vez pasó las 10 pruebas correctamente.

Repito, la salida fue la MISMA, los resultados fueron los MISMOS, pero poner flotador no funcionó, sólo el doble. Los valores no eran tan grandes también, y el programa dio los mismos resultados en las mismas pruebas tanto con flotador como con doble, pero el juez en línea aceptó sólo la solución de doble.

¿Por qué? ¿Cuál es la diferencia?

479voto

KennyTM Puntos 232647

Una gran diferencia.

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

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

Además, el valor máximo de la float es sólo alrededor de 3e38 pero el doble se trata de 1.7e308 así que usando float puede llegar al Infinito mucho más fácil que el doble por algo simple, por ejemplo, ¡cálculo 60!.

Tal vez el caso de prueba contiene estos enormes números que hacen que su programa falle.


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


Por cierto, no uses += para sumar muchos números en coma flotante a medida que los errores se acumulan rápidamente. Si estás usando Python, usa fsum . De lo contrario, trate de implementar el El algoritmo de suma de Kahan .


[1]: Las normas C y C++ no especifican la representación de float , double y long double . Es posible que los tres se hayan implementado 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 punto flotante de precisión única del IEEE (binario32), y double es un número de punto flotante de doble precisión del IEEE (binario64).

54voto

Gregory Pakosz Puntos 35546

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

Hay tres tipos de puntos flotantes: 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 del valor de los tipos de punto flotante está definida por la aplicación.

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

26voto

Alok Singhal Puntos 33073

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 y r 2  = 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í se obtienen efectos de cancelación usando float .

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

19voto

graham.reeds Puntos 9363
  • Un doble es 64 y una precisión simple (flotar) es de 32 bits.
  • El doble tiene una mantisa más grande (los bits enteros del número real).
  • Cualquier inexactitud será menor en el doble.

8voto

N 1.1 Puntos 7687

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

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X