1

オーバーロードされた 2 つの比較演算子 (operator==) を持つ RGB カラー クラスがあります。1 つは自己型用で、もう 1 つは 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

誰にもアイデアがありますか?

4

3 に答える 3

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 を導入することにより、式が記述されている方法に近い方法で式を評価するように強制されます。これにより、同じ関数の真をそれ自体に対して評価するという正気を取り戻すことができます。

クラスの定義を変更して、値を整数として格納し、浮動小数点数が必要な場合にのみ浮動小数点数に変換するか、16 進数表現と浮動小数点数の両方を格納し、比較に 16 進数を使用することができます。または、2 つの浮動小数点値が互いに 1/255 以内にあるかどうかをテストする比較を行うことができます。たとえば、次のようなものです。

return (abs(r - rr) < 1/255.0f && ...);
于 2013-06-28T18:06:04.117 に答える
2

あなた RGB::operator=()は決して呼ばれないという事実を知っていますか?

RGB a = 0x555555;

を受け取る RGB のコンストラクターを呼び出しますint。そのようなコンストラクターが定義されていないと、コードはコンパイルされないため、指定されたスニペットは不完全です。でも、

RGB a;
a = 0x555555;

default はインスタンスを構築し、true`RGBを呼び出します。RGB::operator=(int). I tried your code with both, clang++ and g++ and the comparison always evaluates to

std::coutコメントインまたはコメントアウトされた行によってコードの動作が異なる点は、かなり奇妙です。悪である浮動小数点比較と一緒に最適化の問題である可能性があります。理由を確認するには、「浮動小数点比較」をグーグルで検索してください。これを確認するために、デバッガーを接続してrrrgggbおよびの実際の (16 進) 値を確認しbbます。

*this代入演算子は、コピーではなく参照を返す必要があることに注意してください。

于 2013-06-28T17:38:53.330 に答える
0

JoshG79が述べたように、問題は最適化でした。この問題を解決するために、最初に計算を揮発性変数に保存しようとしました。これにより、最適化が妨げられる可能性がありますが、他の処理が行われ、オーバーヘッドが発生します。そこで、GCC 関数の属性を使用することにしました。

したがって、ヘッダーの関数宣言は次のようになります。

bool operator==(const unsigned int hex) __attribute__((optimize("O0")));

今ではすべてが順調で、魔法のように機能しています。

于 2013-06-28T21:33:57.407 に答える