开发者

avoid rounding error (floating specifically) c++

http://www.learncpp.com/cpp-tutorial/25-floating-point-numbers/ I have been about this lately to review C++.

In general computing class professors tend not to cover these small things, although we knew what rounding errors meant.

Can someone please help me with how to avoid rounding error?

The tutorial shows a sample code

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

This outputs

0.10000000000000001

By default float is kept 6-digits of precisions. Therefore, when we override the default, and asks for more (n this case, 17!!), we may encounter truncation (as explained by the tutorial as well). For double, the highest is 16.

In general, how do good C++ programmers avoid rounding error? Do you guys always look at the binary representation of the number?

Th开发者_Go百科ank you.


The canonical advice for this topic is to read "What Every Computer Scientist Should Know About Floating-Point Arithmetic", by David Goldberg.


In other words, to minimize rounding errors, it can be helpful to keep numbers in decimal fixed-point (and actually work with integers).

#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

}


Short version - you can't really avoid rounding and other representation errors when you're trying to represent base 10 numbers in base 2 (ie, using a float or a double to represent a decimal number). You pretty much either have to work out how many significant digits you actually have or you have to switch to a (slower) arbitrary precision library.


Most floating point output routines look to see if the answer is very close to being even when represented in base 10 and round the answer to actually be even on output. By setting the precision in this way you are short-circuiting this process.

This rounding is done because almost no answer that comes out even in base 10 will be even (i.e. end in an infinite string of trailing 0s) in base 2, which is the base in which the number is represented internally. But, of course, the general goal of an output routine is to present the number in a fashion useful for a human being, and most human beings in the world today read numbers in base 10.


When you calculate simple thing like variance you can have this kind of problem... here is my solution...

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;
}

So you will make your calcul in the integer range... for example 2523.49 became 252349 whit a precision of tow digits, and 2523490 whit a precision of tree digit... if you calculate the mean for example first you convert all value in integer, make the summation and get the result back in double, so you not accumulate error... Error are amplifie whit operation like square root and power function...


You want to use the manipulator called "Fixed" to format your digits correctly so they do not round or show in a scientific notation after you use fixed you will also be able to use set the precision() function to set the value placement to the right of the . decimal point. the example would be as follows using your original code.

#include <iostream>
#include <iomanip>

int main() 
{
    using namespace std;     
    
    double dValue = 0.19213;
    cout << fixed << setprecision(2) << dValue << endl;
    
}

outputs as:

dValue = 0.19
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜