提问人:AndyUK 提问时间:2/26/2009 最后编辑:xanAndyUK 更新时间:2/27/2009 访问量:16831
处理浮点数中的精度问题
Dealing with accuracy problems in floating-point numbers
问:
我想知道是否有一种方法可以克服精度问题,这似乎是我的机器内部浮点数表示的结果:
为清楚起见,问题总结为:
// 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;
在转换为整数类型之前,列计算的结果是 1.999999999999999996;离 2.0 的预期结果如此之近,但又如此之远。
欢迎任何建议。
答:
使用小数:decNumber++
评论
你可以阅读这篇论文,找到你要找的东西。
您可以获得结果的绝对值,如下所示:
x = 0.2;
y = 0.3;
equal = (Math.abs(x - y) < 0.000001)
如果你还没有读过它,这篇论文的标题真的很正确。请考虑阅读它,以了解有关现代计算机上浮点运算的基础知识、一些陷阱以及它们为什么会这样做的解释。
当你使用浮点运算时,严格相等几乎是没有意义的。您通常希望与一系列可接受的值进行比较。
请注意,某些值不能完全表示为浮点。
了解每个计算机科学家都应该了解的有关浮点运算和比较浮点数的知识。
将浮点数四舍五入为整数的一种非常简单有效的方法:
int rounded = (int)(f + 0.5);
注意:这仅在始终为正的情况下才有效。(感谢 J Random Hacker)f
评论
0.5
(0.5 - (f < 0))
f
(f < 0)
0
0.5
f
(f < 0)
1
0.5
-0.5
没有准确性问题。
你得到的结果 (1.999999999999999996) 与数学结果 (2) 相差 1E-16。考虑到您的输入“4.600”,这是非常准确的。
当然,您确实有四舍五入的问题。C++ 中的默认舍入是截断;你想要类似于 Kip 的解决方案。详细信息取决于您的确切域名,您期望吗?round(-x)== - round(x)
如果精度真的很重要,那么您应该考虑使用双精度浮点数,而不仅仅是浮点数。虽然从你的问题来看,你似乎已经是了。但是,在检查特定值时仍然有问题。您需要如下代码(假设您正在检查您的值是否为零):
if (abs(value) < epsilon)
{
// Do Stuff
}
其中“epsilon”是一些小的,但不是零的值。
评论
在计算机上,浮点数从来都不准确。它们总是只是一个近似值。(1E-16 很接近。
有时有些隐藏的部分你看不到。有时代数的基本规则不再适用:a*b != b*a。有时,将寄存器与内存进行比较会发现这些细微的差异。或者使用数学协处理器与运行时浮点库。(我这样做太久了。
C99 定义:(查看 math.h)
double round(double x);
float roundf(float x);
long double roundl(long double x);
.
或者你可以自己滚动:
template<class TYPE> inline int ROUND(const TYPE & x)
{ return int( (x > 0) ? (x + 0.5) : (x - 0.5) ); }
对于浮点等价,请尝试:
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; }
下一个:Python 中的负零
评论