关于优化:如何优化表格“if(A == B){…} else if(A< B){…} else {…}”

How to optimize a statement of the form “if (A == B) { …} else if (A < B) {…} else { …}”

我有一段代码

1
2
3
4
5
6
7
8
9
10
11
12
if (A == B)
{
    ...
}
else if (A < B)
{
    ...
}
else // (A > B)
{
    ...
}

我认识到有一个冗余问题,因为在计算==<时会进行一些相同的位比较。我如何优化我的代码,使其更高级更快?


您没有指定语言,但根据语言的不同,可以用多种方式重写

Ruby Way(使用宇宙飞船操作员):

1
2
3
4
5
case A <=> B
    when -1 then... # A < B
    when  0 then... # A = B
    when  1 then... # A > B
end

perl、php7和groovy也有相同的操作符。许多其他语言具有类似的运算符或函数,用于相同的组合比较目的,如python 2中的cmp、ocaml中的compare和kotlin中的compareTo。C没有该运算符,但它具有与compareTo方法的IComparable接口。

VB方式:

1
2
3
4
5
6
7
8
Select Case A
    Case Is < B
        ...
    Case Is = B
        ...
    Case Is > B
        ...
End Select

在C、C++和许多类似C语言的语言中,如果没有EDCOX1×2的方法,可以使用这种方法。

1
2
3
4
5
6
7
int cmp = (A > B) - (A < B);
switch (cmp)
{
    case -1: ...
    case  0: ...
    case  1; ...
}

许多像Java这样的语言不允许你直接使用比较结果作为数值。在这种情况下,您可以使用signum函数

1
switch(Integer.signum(A - B))

你可以在C和C++中很容易地实现EDCOX1 6函数

这些是高级语言的。在装配级别,事情更简单。在x86程序集中,只需要一个比较,然后根据结果,我们将跳转到相应的块,因此它不是3个比较,编译器足够聪明,可以优化这个简单的情况。例如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    cmp eax, ebx
    je EQUAL_TO      ; jump if =
    ja GREATER_THAN  ; jump if >

    ; less than case's code
    jmp END_CMP

EQUAL_TO:
    ; equal case's code
    jmp END_CMP

GREATER_THAN:
    ; larger than case's code

END_CMP:

与其他带有比较标志(如ARM或68K)的体系结构相同…对于没有mips标志的体系结构,您可能需要再进行一次比较,但不能再进行三次比较。

MIPS实例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    beq $t0, $t1, EQUAL_TO       # $t0 = A, $t1 = B; if ($t0 == $t1) equal();
    slt $t0, $t1, $t2            # $t2 = is_less_than = ($t0 < $t1);
    beq $t2, $zero, GREATER_THAN # if (!is_less_than) larger();

    #"less than" code here
    # ...
    j END_CMP

EQUAL_TO:
    #"equal" code
    # ...
    j END_CMP

GREATER_THAN:
    #"larger" code
    # ...

END_CMP:

对于带有条件指令(如ARM或Itanium)以及在if-else块中具有足够简单主体的体系结构,您甚至可能不需要跳转。


对于C,您可以使用一个接受2个值的通用函数,然后针对每种情况使用lambda操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
void CompareAndAct<T>(T a, T b, Action fnEqualTo, Action fnLessThan, Action fnGreaterThan)  {

   var comparison = System.Collections.Generic.Comparer<T>.Default.Compare(a, b);
   if (comparison == 0) {
      fnEqualTo();
   }
   else if (comparison < 0) {
      fnLessThan();
   }
   else {  //A > B
      fnGreaterThan();
   }
}

然后你可以随心所欲地重复使用它:

1
CompareAndAct(a,b, () => Console.Writeline("Equal"),() => Console.WriteLine("Less Than", () => Console.WriteLine("Greater Than"));

我不能说我建议你这么做,但这是可行的。它不会更快(探测速度较慢),但我想有人会说它"更高级"。