const和#define的区别(奇怪的行为)

5

我曾经用#define来替换const,但在下面的例子中会打印false

#include <iostream>
#define x 3e+38

using namespace std;

int main() {
    float p = x;
    if (p==x)
        cout<<"true"<<endl;
    else
        cout<<"false"<<endl;
return 0;
}

但是如果我替换

#define x 3e+38

使用

const float x = 3e+38;

它完美地运作了,问题是为什么?(我知道有关于#define与const的几个话题进行了讨论,但我真的不明白,请求您给予启示)


4
请尝试使用#define x 3e+38f - πάντα ῥεῖ
哇哦,但为什么这不起作用,以及为什么和如何这个起作用? - Dr.PB
3
@Mr.EU 你可能想要阅读“浮点数运算是否存在问题?”(https://dev59.com/G3RB5IYBdhLWcg3wj36c)。很少有浮点数能够进行精确相等的检查,大多数情况下需要使用一个“epsilon”。你不需要花费很长时间去搜索引擎来了解这个。 - Some programmer dude
@JoachimPileborg:没错,但这不是问题所在。这里根本没有数学运算。问题出在往返转换double->float->double上。使用double变量或float字面值都可以解决它。 - MSalters
1
你已经学到了一个教训,那就是编译器有类型的概念 - 宏没有。选择前者而不是后者,并让编译器捕捉到你的错误 - 而不是你的客户。 - Ed Heal
显示剩余4条评论
2个回答

5
在C++中,字面量是双精度的。在第一个示例中,数字3e+38首先在变量初始化中转换为float,然后在比较中再次转换为双精度。这些转换并不完全准确,因此数字可能会有所不同。在第二个示例中,数字始终保持为float。要修复它,您可以将p更改为double,写:
#define x 3e+38f

(定义了浮点字面量),或者将比较改为
if (p == static_cast<float>(x))

该代码执行与变量初始化相同的转换,然后在单精度中进行比较。

另外,正如评论中所述,使用==比较浮点数通常不是一个好主意,因为舍入误差会导致意想不到的结果,例如,x*y可能与y*x不同。


简而言之,要比较A和B,你可以像这样做:if (fabs(A-B)< EPSILON),其中EPSILON是一个小数(例如0.0000001),具体取决于情况。有时候比较相对误差会更好。详见https://dev59.com/P3VD5IYBdhLWcg3wU5-H - Ari Hietanen
在正常情况下,(a_float==b_float)的精度是多少? - Dr.PB
1
只有当它们是完全相同的数字时,该表达式才会评估为true。然而,比如说,比a_float大的最小浮点数取决于a_float的绝对值。例如,3e38f== 3e+38f+1.0f评估为true,因为浮点数不能保留38个有效数字。在这种情况下,EPSILON应至少为1e28左右,因为cout << 3e38f-3e38 << endl;5.49776e+29 - Ari Hietanen

1

由于其数量级,数字3e+38是双精度的。

这个任务

float p = x; 

当存储在p中时,会导致3e+38失去精度,因此失去其值。

这就是为什么要进行比较:

if(p==x)

结果为假,因为p的值与3e+38不同。


它不是数量级使得 3e+38 - Pete Becker

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接