sirve que para float ejemplos definicion and c++ c floating-point precision

que - float c++ ejemplos



¿Cuál es la diferencia entre flotar y doble? (11)

He leído acerca de 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 los resultados. ¿Es este realmente el caso? ¿Cuándo son intercambiables los flotadores y los dobles? Cuáles son las diferencias entre ellos?


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 números después del punto decimal.


Al usar números de punto flotante, no puede confiar en que sus pruebas locales serán exactamente las mismas que las 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 punto flotante.


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í obtiene efectos de cancelación usando float .

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


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, entonces habrá errores de redondeo cuando ese número sea aplastado en la estructura de datos de tamaño finito que está utilizando. Como el doble es el doble del tamaño del flotador, el error de redondeo será mucho menor.

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


El tipo float, de 32 bits de longitud, 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 longitud, tiene un rango mayor (* 10 ^ + / - 308) y precisión de 15 dígitos.

Type long double es nominalmente de 80 bits, aunque un par de compilador / SO dado puede almacenarlo como 12-16 bytes para propósitos de alineación. El doble largo tiene un exponente que es ridículamente grande y debe tener una precisión de 19 dígitos. Microsoft, en su infinita sabiduría, limita el doble de largo a 8 bytes, lo mismo que el doble simple.

En términos generales, simplemente use tipo doble cuando necesite un valor / variable de punto flotante. Los valores de punto flotante literales utilizados en las expresiones se tratarán como dobles de manera predeterminada, y la mayoría de las funciones matemáticas que devuelven valores de punto flotante devuelven el doble. Te ahorrarás muchos dolores de cabeza y encasillados si solo usas el doble.


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 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 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 de C ++ agrega:

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

Yo sugeriría echar un vistazo a la excelente información sobre aritmética de punto flotante que cubre todo el estándar de punto flotante de IEEE. Aprenderá sobre los detalles de representación y se dará cuenta de que hay una compensación entre la magnitud y la precisión. La precisión de la representación de punto flotante aumenta a medida que disminuye la magnitud, por lo que los números de punto flotante entre -1 y 1 son los que tienen la mayor precisión.


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 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 llevar a errores de truncamiento mucho más fáciles de hacer 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 el "infinito" (es decir, un número especial de punto flotante) mucho más fácilmente que el double para algo simple, por ejemplo, calcular el factorial de 60 .

Durante las pruebas, quizás unos pocos casos de prueba contengan estos números enormes, lo que puede hacer que sus programas fallen si utiliza flotadores.

Por supuesto, a veces, incluso el double no es lo suficientemente preciso, por lo tanto, a veces tenemos el long double [1] (el ejemplo anterior da 9.00000000000000000066 en Mac), pero todos los tipos de punto 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 sumar muchos números de punto flotante, ya que los errores se acumulan rápidamente. Si estás usando Python, usa fsum . De lo contrario, intente implementar el algoritmo de suma 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 doble precisión IEEE. 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 simple IEEE (binary32), y double es un número de punto flotante de precisión doble IEEE (binary64).


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



Simplemente me encontré con un error que me llevó una eternidad descubrir y, potencialmente, puedo darle un buen ejemplo de precisión flotante.

#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 se puede ver después de 0.83, la precisión se reduce significativamente.

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

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


  • 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á menor en el doble.