我有一个RGB颜色类,有两个重载的比较运算符(operator ==)。 一个用于self类型,一个用于int(HEX)。
// this one assigns the value correctly
RGB RGB::operator=(const int hex)
{
this->r = (hex>>16 & 0xFF) / 255.0f;
this->g = (hex>>8 & 0xFF) / 255.0f;
this->b = (hex & 0xFF) / 255.0f;
return *this;
}
//--------------------------------------------------------------------------------------
// also works
bool RGB::operator==(const RGB &color)
{
return (r == color.r && g == color.g && b == color.b);
}
// this is evil
bool RGB::operator==(const int hex)
{
float rr = (hex>>16 & 0xFF) / 255.0f;
float gg = (hex>>8 & 0xFF) / 255.0f;
float bb = (hex & 0xFF) / 255.0f;
// if i uncomment these lines then everything is fine
//std::cout<<r<<" "<<rr<<std::endl;
//std::cout<<g<<" "<<gg<<std::endl;
//std::cout<<b<<" "<<bb<<std::endl;
return (r == rr &&
g == gg &&
b == bb);
}
RGB::RGB(int hex)
{
setHex(hex);
}
inline void RGB::setHex(unsigned hex)
{
r = (float)(hex >> 16 & 0xFF) / 255.0f;
g = (float)(hex >> 8 & 0xFF) / 255.0f;
b = (float)(hex & 0xFF) / 255.0f;
}
...然后我在main.cpp中比较:
RGB a = 0x555555;
bool equals = (a == 0x555555); // returns false
我不知道会发生什么。比较返回false,但如果我取消注释定义中的std :: cout行,则函数按预期工作并返回true。
这也没有问题:
RGB a = 0x555555;
RGB b = 0x555555;
bool equals = (a == b); // returns true
有人有想法吗?
答案 0 :(得分:4)
如果没有优化,您不应该获得浮点比较效果。这是因为在这两种情况下你都有相同的功能。
如果没有优化,以下情况属实:
float func(float);
float a = ...;
func(a) == func(a); //< always true
这就是你所拥有的,你的函数是移位并除以255。
然而 - 通过优化,这是一个不同的故事。 GCC进行了优化(参见例如-freciprocal-math,-fassociative-math),可以重新排列表达式。
在您的情况下,您有:
float rr = (X) / 255.0f;
...
r == rr
例如,它可以在优化时做一些与此相关的事情:
255.0f * r == (X)
现在 会受到浮点比较效果的影响。然而,通过在中间引入stdout,你迫使它更接近于它们的编写方式来评估表达式,这再次使你回到在同一函数上对自己评估真值的理智。
您可以更改类的定义以将值存储为整数,并仅在需要浮点数时转换为float,或者存储十六进制表示和浮点数并使用十六进制进行比较。或者你可以使用大于/小于而不是双等于比较来测试两个浮点值是否在彼此的1/255之内。例如。像这样的东西:
return (abs(r - rr) < 1/255.0f && ...);
答案 1 :(得分:2)
你知道你的事实吗?
RGB::operator=()
永远不会被召唤?
RGB a = 0x555555;
调用RGB的构造函数,该构造函数接受int
。
如果没有定义任何这样的构造函数,您的代码将无法编译,因此,给出的代码段不完整。然而,
RGB a;
a = 0x555555;
默认构造RGB
实例并调用您的RGB::operator=(int).
I tried your code with both, clang++ and g++ and the comparison always evaluates to
true`。
代码在注释或注释时std::cout
行的行为方式不同,这一点非常奇怪。这可能是一些优化问题以及浮点数比较邪恶:google进行“浮点比较”以了解原因。
为了验证这一点,我会附加一个调试器,并查看r
,rr
,g
,gg
的实际(十六进制)值,{ {1}}和b
。
请注意,您的赋值运算符应返回对bb
的引用,而不是副本。
答案 2 :(得分:0)
谢谢大家,问题在于JoshG79所说的优化。 为了解决这个问题,首先我尝试将计算存储在volatile变量中,这可能会阻止它们进行优化,但是它们会做一些其他的事情而导致开销。所以我决定使用GCC function attributes。
所以标题中的函数声明如下所示:
bool operator==(const unsigned int hex) __attribute__((optimize("O0")));
现在一切都很好,就像魅力一样。