2016-10-01 10 views
3

これら2つの関数は同じロジックを持っているかどうかについて別の質問にいくつかdisagreementがあるようです:これらの2つの比較式は同じですか?

bool operator<(const screenPoint& left, const screenPoint& right){ 
    if (left.x < right.x) return true; 
    else return left.y < right.y; 
} 

bool operator<(const screenPoint& left, const screenPoint& right){ 
    return left.x < right.x || left.y < right.y; 
} 

私はかなりしばらくの間、これらを見つめていると私は、彼らは異なる動作をする方法を見ることができません。両方とも、left.x < right.xの場合、両方ともtrueを返します。そうでなければ、両方ともleft.y < right.yの結果を返します。右?

もしそうでない場合は、詳細を教えてください。

また、これらのうちの最初のものはstd::tieの字句規則の実装と同じですが、それは本当ですか?

+0

誰かがかっこをすべて乱されています。 –

+1

同じサイズの場合はどうなりますか?異なるサイズではないので、結果は他のものに行き、不正確になるでしょう。 – Charlie

+0

最初のものは、辞書編集の比較を実装する 'std :: tie'と同じではありません。 'left.x'が' right.x'より大きい場合、 'std :: tie'は常にfalseを返します。 – juanchopanza

答えて

6

2つは同じです(最初のifに括弧がない場合は修正してください)が、厳密な弱い順序を実装していないため、使用したくない可能性がありますそれらを標準のコンテナとアルゴリズムで使用する)。

証明:a =(1,3)b =(2,2)の元の関係を考えてみましょう。次に、< bおよびb < a。 (非対称財産が侵害)

正しい辞書式順序は次のようになります。あなたのメンバーのみ<オペレータはなく>オペレータを持っている場合は

bool operator<(const screenPoint& left, const screenPoint& right){ 
    if (left.x < right.x) 
     return true; 
    if (left.x > right.x) 
     return false; 
    return left.y < right.y; 
} 

を、!(right.x < left.x)によりleft.x > right.xを交換してください。これは、辞書順の比較がstd::pairstd::tuplestd::tieによって返されます)によって実装される方法です。

+0

お返事ありがとう! –

2

あなたのコンパイラをとり、違いを確認するためにasmコードを出力させてください。あなたが最初の2つのバージョンが同じである見ることができるように

__Z13operatorLess1RK11screenPointS1_: ## @_Z13operatorLess1RK11screenPointS1_ 
    push rbp 
    mov rbp, rsp 
Ltmp2: 
    movss xmm0, dword ptr [rsi] ## xmm0 = mem[0],zero,zero,zero 
    mov al, 1 
    ucomiss xmm0, dword ptr [rdi] 
    ja LBB0_2 
    movss xmm0, dword ptr [rsi + 4] ## xmm0 = mem[0],zero,zero,zero 
    ucomiss xmm0, dword ptr [rdi + 4] 
    seta al 
LBB0_2: 
    pop rbp 
    ret 
    .cfi_endproc 


__Z13operatorLess2RK11screenPointS1_: ## @_Z13operatorLess2RK11screenPointS1_ 
    .cfi_startproc 
    push rbp 
    mov rbp, rsp 
Ltmp5: 
    movss xmm0, dword ptr [rsi] ## xmm0 = mem[0],zero,zero,zero 
    mov al, 1 
    ucomiss xmm0, dword ptr [rdi] 
    ja LBB1_2 
    movss xmm0, dword ptr [rsi + 4] ## xmm0 = mem[0],zero,zero,zero 
    ucomiss xmm0, dword ptr [rdi + 4] 
    seta al 
LBB1_2: 
    pop rbp 
    ret 
    .cfi_endproc 


__Z13operatorLess3RK11screenPointS1_: ## @_Z13operatorLess3RK11screenPointS1_ 
    push rbp 
    mov rbp, rsp 
Ltmp8: 
    movss xmm0, dword ptr [rdi] ## xmm0 = mem[0],zero,zero,zero 
    movss xmm1, dword ptr [rsi] ## xmm1 = mem[0],zero,zero,zero 
    mov al, 1 
    ucomiss xmm1, xmm0 
    ja LBB2_4 
    ucomiss xmm0, xmm1 
    jbe LBB2_3 
    xor eax, eax 
    pop rbp 
    ret 
LBB2_3: 
    movss xmm0, dword ptr [rsi + 4] ## xmm0 = mem[0],zero,zero,zero 
    ucomiss xmm0, dword ptr [rdi + 4] 
    seta al 
LBB2_4:         ## %_ZNSt3__1ltIJRKfS2_EJS2_S2_EEEbRKNS_5tupleIJDpT_EEERKNS3_IJDpT0_EEE.exit 
    pop rbp 
    ret 
    .cfi_endproc 

__Z13operatorLess4RK11screenPointS1_: ## @_Z13operatorLess4RK11screenPointS1_ 
    .cfi_startproc 
    push rbp 
    mov rbp, rsp 
Ltmp11: 
    movss xmm0, dword ptr [rdi] ## xmm0 = mem[0],zero,zero,zero 
    movss xmm1, dword ptr [rsi] ## xmm1 = mem[0],zero,zero,zero 
    mov al, 1 
    ucomiss xmm1, xmm0 
    ja LBB3_4 
    ucomiss xmm0, xmm1 
    jbe LBB3_3 
    xor eax, eax 
    pop rbp 
    ret 
LBB3_3: 
    movss xmm0, dword ptr [rsi + 4] ## xmm0 = mem[0],zero,zero,zero 
    ucomiss xmm0, dword ptr [rdi + 4] 
    seta al 
LBB3_4: 
    pop rbp 
    ret 
    .cfi_endproc 

clang++ -S -masm=intel -std=c++11 -O2 a.cpp 

利回りでコンパイルさ

#include <tuple> 

__attribute__((noinline)) bool operatorLess1(const screenPoint& left, const screenPoint& right) 
{ 
    if (left.x < right.x) return true; 
    else return (left.y < right.y); 
} 

__attribute__((noinline)) bool operatorLess2(const screenPoint& left, const screenPoint& right) 
{ 
    return left.x < right.x || left.y < right.y; 
} 

__attribute__((noinline)) bool operatorLess3(const screenPoint& left, const screenPoint& right) 
{ 
    return std::tie(left.x, left.y) < std::tie(right.x, right.y); 
} 

__attribute__((noinline)) bool operatorLess4(const screenPoint& left, const screenPoint& right) 
{ 
    if (left.x < right.x) return true; 
    else if (left.x > right.x) return false; 
    else return (left.y < right.y); 
} 

:私のコンパイラ(打ち鳴らす)は二つのバージョンで同じ結果が得られます彼らはxを比較するか、直接yを比較します。 interjayで指摘されているように、代わりにstd::tieのバージョンは、left.x > left.yの完全な弱い順序を返します。実際のコードはoperatorLess4と同じです。

+0

Re:「推測だけではなく、コンパイラを使ってasmコードを発行する」 - 3つ目の可能性があります。**は言語規則を理解していますので、両方のコードスニペットの意味を理解できます。 –

関連する問題