由C++絕對值函數想到的

       這些天恰好要用到一個絕對值的函數。好吧,你會說這個直接用std::abs不就行了嗎?對的,一開始我也是這樣用的。但是如果去求最小的那個int的值的絕對值,就會導致輸出不正確。如:

int min_int = -2147483648;
cout<<std::abs(min_int)<<endl;
       得到的結果仍然是-2147483648!恰好我的程序有可能出現這樣的情況。所以需要自己去完成一個。


1、第一個版本:

unsigned int __abs(int value)
{
    return (value >= 0) ? value : -value;
}
       仍然是std::abs的老路,不可取!


2、第二個版本:

#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、第三個版本:

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值的絕對值問題,又要考慮性能問題,建議採用第三個方案。


       這個問題雖然簡單,但裏面透射出來的東西可真不少。其實我們在編程工作中,從細節出抓起,往往能夠獲得很多收穫。







       【轉載請註明出處】


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章