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中的
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这样的语言不允许你直接使用比较结果作为数值。在这种情况下,您可以使用
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")); |
我不能说我建议你这么做,但这是可行的。它不会更快(探测速度较慢),但我想有人会说它"更高级"。