2013/02/02

不用條件指令,找出兩數中的較大者

這是一個動腦用的程式設計題目,網路上有不少問答。我發現有不少人誤解「不用條件指令 (without conditional operator)」,這部份要用 assembly 的觀點來看比較清楚。簡單說,指令執行時不能有 branch 的動作,但 compare 是允許的。

錯的答案:
larger = max(a, b);
回答的人可能在搞笑。若 max() 符合要求,這個問題就是要問怎麼作到的。
larger = (a + b + abs(a - b)) / 2;
這個答案看起來有點學問,但本質跟前一個答案一樣,要依賴 abs() 的實作方法。另外,(a-b) 也有 overflow 的問題。
larger = (a > b) ? a : b;
這個不用解釋吧?這只是 if else 的變形,一樣是條件指令。
larger = a;
(void)((a < b) && (larger = b));
這個答案利用 short-circuit and 來決定是否令 larger = b,骨子裡一樣需要條件指令。
#include
unsigned d = b - a;
m = -(d >> (sizeof(int) * CHAR_BIT - 1));
larger = (a & m) | (b & ~m);
這個答案很用心,考慮到可攜性。但用到 b - a,就會有 overflow 的問題。

對的答案:
m = -(a > b);
larger = (a & m) | (b & ~m);
這個方法跟前一個接近,但不會有 overflow 的問題,看起來也清爽多了。小瑕疵是有前提:此計算機系統必須採用二的補數 (2's complement) 來表示有號數。但這個假設,目前「幾乎」都會成立。
larger = ((a ^ b) & -(a > b)) ^ b;
這個方法是前一個的再簡化版本,不是一眼可以懂,但乾淨俐落。同樣也有相同的前提。
larger = (a > b) * a + (a <= b) * b;
這個方法不需任何前提,但我不喜歡那兩個乘法。不知有誰可以改掉?
int p[] = { a, b };
larger = p[a < b];
這個方法除了需複製變數之外,其他都很完美。

沒有留言: