這些天恰好要用到一個絕對值的函數。好吧,你會說這個直接用std::abs不就行了嗎?對的,一開始我也是這樣用的。但是如果去求最小的那個int的值的絕對值,就會導致輸出不正確。如:
[cpp]
int min_int = -2147483648;
cout<<std::abs(min_int)<<endl;
得到的結果仍然是-2147483648!恰好我的程序有可能出現這樣的情況。所以需要自己去完成一個。
1、第一個版本:
[cpp]
unsigned int __abs(int value)
{
return (value >= 0) ? value : -value;
}
仍然是std::abs的老路,不可取!
2、第二個版本:
[cpp]
#include <limits>
unsigned int __abs(int value)
{
return (std::numeric_limits<int>::min() == value || value >= 0) ? value : -value;
}
這個版本比較簡潔,可移植性也很高。std::numeric_limits<int>::min()返回當前系統下int值的最小值,能夠自適應int的內存寬度返回准確的值。當value和最小的int值相等或者value不為負數時,我們直接進行位對位的拷貝——因為unsigned int沒有符號位,所以完全可行的。當value為除最小值外的負數時,直接取相反數即可。
但這個版本需要用到兩次條件判斷,能不能再優化一下呢?所以出現了:
3、第三個版本:
[cpp]
unsigned int __abs(int value)
{
unsigned int copyed_value = value;
return (copyed_value > 0x80000000) ? -value : copyed_value;
}
因為32位下最小的int值為0x80000000——最高位符號位為1。當位對位拷貝到unsigned int中時,仍然是這個值。但其他的負數除了最高位為1外,其余位置也有值,比如-1的16進制表示為:0x80000001。所以,我們先執行位對位的拷貝,到copyed_value中。所以出現了判斷情況:
(1)如果copyed_value是大於0x80000000的,說明value是負數,所以我們直接取相反數(-value);
(2)如果copyed_value是等於0x80000000的,說明value恰好是最小的那個負數,執行位對位拷貝後,copyed_value中存放的就是value的絕對值,所以返回copyed_value;
(3)如果copyed_value是小於0x80000000,說明value為正數。直接去alue或者copyed_value即可。
通過分析,我們將(2)和(3)合並到一起,返回copyed_value。所以,采取第三種方案,就只有一次比較操作。比第二種方案省一次。但是這種方案第一眼看去可能易讀性上不是很好。
權衡三種方案,應該說各有利弊。三種情況各有適用的地方。如果你的函數不考慮最小int值的絕對值,可以采用std::abs即可;如果需要考慮但不必擔心性能問題,那麼第二種方案是你最好的選擇!但如果你既要考慮最小int值的絕對值問題,又要考慮性能問題,建議采用第三個方案。
這個問題雖然簡單,但裡面透射出來的東西可真不少。其實我們在編程工作中,從細節出抓起,往往能夠獲得很多收獲。