9

我想知道是否有办法克服似乎是我的机器内部浮点数表示的结果的准确性问题:

为了清楚起见,将问题总结为:

// 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.9999999999999996;距离 2.0 的预期结果如此接近但如此遥远。

欢迎提出任何建议。

4

8 回答 8

15

当您使用浮点算术时,严格相等几乎没有意义。您通常希望与一系列可接受的值进行比较。

请注意,某些值不能完全表示为浮点值。

看看每个计算机科学家应该知道的关于浮点运算比较浮点数的知识。

于 2009-02-26T14:48:03.257 回答
12

不存在精度问题。

您得到的结果 (1.9999999999999996) 与数学结果 (2) 相差 1E-16。考虑到您的输入“4.600”,这非常准确。

当然,你确实有一个舍入问题。C++ 中的默认舍入是截断;你想要类似于 Kip 解决方案的东西。详细信息取决于您的确切域,您期望round(-x)== - round(x)吗?

于 2009-02-26T15:31:56.100 回答
10

如果你没有读过,这篇论文的标题真的是正确的。请考虑阅读它,以了解更多关于现代计算机上浮点运算的基础知识、一些陷阱以及对它们为何如此行事的解释。

于 2009-02-26T14:47:23.180 回答
5

将浮点数舍入为整数的一种非常简单有效的方法:

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

注意:这仅在f始终为正时才有效。(感谢 j 随机黑客)

于 2009-02-26T14:57:11.490 回答
5

如果准确性真的很重要,那么您应该考虑使用双精度浮点数而不仅仅是浮点数。虽然从你的问题看来你已经是了。但是,您在检查特定值时仍然存在问题。您需要以下代码(假设您正在检查您的值是否为零):

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

其中“epsilon”是一些小但非零值。

于 2009-02-26T15:51:29.907 回答
3

在计算机上,浮点数从来都不是精确的。它们始终只是一个近似值。(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; }
于 2009-02-26T16:36:17.630 回答
2

使用小数:decNumber++

于 2009-02-26T14:41:29.013 回答
2

您可以阅读本文以找到您要查找的内容。

您可以获得结果的绝对值,如下所示

x = 0.2;  
y = 0.3;  
equal = (Math.abs(x - y) < 0.000001)  
于 2009-02-26T14:43:25.687 回答