2010-08-05 19 views
10

http://www.learncpp.com/cpp-tutorial/25-floating-point-numbers/ He estado sobre esto últimamente para revisar C++.evitar el error de redondeo (flotante específicamente) C++

En general, los profesores de clases de informática tienden a no cubrir estas pequeñas cosas, aunque sabíamos lo que significaban los errores de redondeo.

¿Puede alguien ayudarme con cómo evitar el error de redondeo?

El tutorial muestra un código de ejemplo

#include <iomanip> 
int main() 
{ 
    using namespace std; 
    cout << setprecision(17); 
    double dValue = 0.1; 
    cout << dValue << endl; 
} 

Esto da salida

0,10000000000000001

Por flotador predeterminada se mantiene de 6 dígitos de precisiones. Por lo tanto, cuando anulamos el valor predeterminado y solicitamos más (en este caso, 17 !!), podemos encontrar el truncamiento (como se explica en el tutorial también). Para el doble, el más alto es 16.

En general, ¿cómo los programadores buenos de C++ evitan el error de redondeo? ¿Ustedes siempre miran la representación binaria del número?

Gracias.

+3

Eso establece la precisión del formato de la secuencia Usos del código: nada que ver con la forma en que se representa el número o en otro código. –

Respuesta

0

La mayoría de las rutinas de salida de punto flotante miran para ver si la respuesta está muy cerca de ser incluso cuando se representa en la base 10 y alrededor de la respuesta para estar realmente en la salida. Al establecer la precisión de esta manera, estás cortocircuitando este proceso.

Este redondeo se realiza porque casi ninguna respuesta que sale incluso en la base 10 será pareja (es decir, terminará en una cadena infinita de ceros finales) en la base 2, que es la base en la que el número se representa internamente. Pero, por supuesto, el objetivo general de una rutina de salida es presentar el número de una manera útil para un ser humano, y la mayoría de los seres humanos en el mundo hoy leen los números en la base 10.

0

Versión corta - puede ' Evite realmente el redondeo y otros errores de representación cuando intente representar los números base 10 en la base 2 (es decir, usar un float o un double para representar un número decimal). Tienes que calcular cuántos dígitos significativos tienes en realidad o tienes que cambiar a una biblioteca de precisión arbitraria (más lenta).

0

En otras palabras, para minimizar los errores de redondeo, puede ser útil mantener los números en punto fijo decimal (y en realidad trabajar con enteros).

#include <iostream> 
#include <iomanip> 

int main() { 

    using namespace std; 

    cout << setprecision(17); 

    double v1=1, v1D=10; 
    cout << v1/v1D << endl; // 0.10000000000000001 


    double v2=3, v2D=1000; //0.0030000000000000001 
    cout << v2/v2D << endl; 

    // v1/v1D + v2/v2D = (v1*v2D+v2*v1D)/(v1D*v2D) 

    cout << (v1*v2D+v2*v1D)/(v1D*v2D) << endl; // 0.10299999999999999 

} 
0

que desea utilizar el manipulador llamado "fijo" para dar formato a los dígitos correctamente para que no se redonda o espectáculo en una notación científica después de usuarios fijos que también será capaz de utilizar ajustar la precisión de función() para establecer la ubicación del valor a la derecha de. punto decimal. el ejemplo sería el siguiente usando su código original.

#include <iostream> 
#include <iomanip> 
    int main() { 
      using namespace std; 
      #include <iomanip> 


    double dValue = 0.19213; 
    cout << fixed << setprecision(2) << dValue << endl 


     } 

salidas como:

dValue = 0.19 
0

Al calcular cosa tan simple como la varianza puede tener este tipo de problema ... aquí es mi solución ...

int getValue(double val, int precision){ 
std::stringstream ss; 
ss << val; 
string strVal = ss.str(); 
size_t start = strVal.find("."); 

std::string major = strVal.substr(0, start); 
std::string minor = strVal.substr(start + 1); 

// Fill whit zero... 
while(minor.length() < precision){ 
    minor += "0"; 
} 

// Trim over precision... 
if(minor.length() > precision){ 
    minor = minor.substr(0, precision); 
} 

strVal = major + minor; 
int intVal = atoi(strVal.c_str()); 

return intVal; 
} 

Por lo que hará su cálculo en el rango entero ... por ejemplo 2523.49 se convirtió en 252349 con una precisión de dígitos de remolque, y 2523490 con una precisión de dígito en árbol ... si calcula la media, por ejemplo, primero y O convierte todos los valores en enteros, realiza la suma y obtiene el resultado en doble, para que no acumules errores ... Los errores se amplifican con la operación como raíz cuadrada y la función de potencia ...

Cuestiones relacionadas