Dealing with accuracy problems in floating-point numbers

别等时光非礼了梦想. 提交于 2019-11-26 02:15:48

问题


I was wondering if there is a way of overcoming an accuracy problem that seems to be the result of my machine\'s internal representation of floating-point numbers:

For the sake of clarity the problem is summarized as:

// str is \"4.600\";   atof( str ) is 4.5999999999999996  
double mw = atof( str )  

// The variables used in the columns calculation below are:   
//  
//                    mw = 4.5999999999999996  
//                    p = 0.2  
//                    g = 0.2  
//                    h = 1 (integer)  

int columns = (int) ( ( mw - ( h * 11 * p ) ) / ( ( h * 11 * p ) + g ) ) + 1;

Prior to casting to an integer type the result of the columns calculation is 1.9999999999999996; so near yet so far from the desired result of 2.0.

Any suggestions most welcome.


回答1:


A very simple and effective way to round a floating point number to an integer:

int rounded = (int)(f + 0.5);

Note: this only works if f is always positive. (thanks j random hacker)




回答2:


When you use floating point arithmetic strict equality is almost meaningless. You usually want to compare with a range of acceptable values.

Note that some values can not be represented exactly as floating point vlues.

See What Every Computer Scientist Should Know About Floating-Point Arithmetic and Comparing floating point numbers.




回答3:


There's no accurracy problem.

The result you got (1.9999999999999996) differed from the mathematical result (2) by a margin of 1E-16. That's quite accurate, considering your input "4.600".

You do have a rounding problem, of course. The default rounding in C++ is truncation; you want something similar to Kip's solution. Details depend on your exact domain, do you expect round(-x)== - round(x) ?




回答4:


If you haven't read it, the title of this paper is really correct. Please consider reading it, to learn more about the fundamentals of floating-point arithmetic on modern computers, some pitfalls, and explanations as to why they behave the way they do.




回答5:


If accuracy is really important then you should consider using double precision floating point numbers rather than just floating point. Though from your question it does appear that you already are. However, you still have a problem with checking for specific values. You need code along the lines of (assuming you're checking your value against zero):

if (abs(value) < epsilon)
{
   // Do Stuff
}

where "epsilon" is some small, but non zero value.




回答6:


On computers, floating point numbers are never exact. They are always just a close approximation. (1e-16 is close.)

Sometimes there are hidden bits you don't see. Sometimes basic rules of algebra no longer apply: a*b != b*a. Sometimes comparing a register to memory shows up these subtle differences. Or using a math coprocessor vs a runtime floating point library. (I've been doing this waayyy tooo long.)

C99 defines: (Look in math.h)

double round(double x);
float roundf(float x);
long double roundl(long double x);

.

Or you can roll your own:

template<class TYPE> inline int ROUND(const TYPE & x)
{ return int( (x > 0) ? (x + 0.5) : (x - 0.5) ); }

For floating point equivalence, try:

template<class TYPE> inline TYPE ABS(const TYPE & t)
{ return t>=0 ? t : - t; }

template<class TYPE> inline bool FLOAT_EQUIVALENT(
    const TYPE & x, const TYPE & y, const TYPE & epsilon )
{ return ABS(x-y) < epsilon; }



回答7:


Use decimals: decNumber++




回答8:


You can read this paper to find what you are looking for.

You can get the absolute value of the result as seen here:

x = 0.2;  
y = 0.3;  
equal = (Math.abs(x - y) < 0.000001)  


来源:https://stackoverflow.com/questions/590822/dealing-with-accuracy-problems-in-floating-point-numbers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!