The C++ standard library(侯捷/孟巖 譯) 02--numeric limits/輔助函數(shù)及比較操作符

4. numeric limits/輔助函數(shù)/comparison operator

一般而言辈灼,數(shù)值型別(numeric types)的極值是與平臺有關(guān)的。

C++標(biāo)準(zhǔn)程序庫通過template numberic_limits提供這些極值罪佳,
    取代傳統(tǒng)C采用的預(yù)處理器常數(shù)(preprocessor constants)**,當(dāng)然二者都可使用。

整數(shù)常數(shù)定義在<climits>和<limits.h>。
浮點數(shù)定義于<cfloat>和<float.h>

新的極值概念有兩個優(yōu)點:提供了更好的型別安全型片效;可借此寫出一些template以核定(evaluate)這些極值。

note:C++ standard規(guī)定了各種型別必須保證的最小精度英古,如果能注意并運用這些價值就可寫出與平臺無關(guān)的程序。

p59_t4-1.png

4.1 class numeric_limits<>

使用template通常是為了對所有型別一次性的寫出一個通用解決方案昙读。但還可以在必要時以template為每個型別提供共同接口召调。
方法:不但提供通用性template,還提供其特化(specialization)版本,eg:numeric_limits

1. 通用性template,為所有型別提供缺省值:
namespace std
{
    /* general numeric limits as default for any type
    */
    template <class T>
    class numeric_limits
    {
    public:
        //no specialization for numeric limits exist
        static const bool is_specialized = false;
        //.. //other members that are meaningless for the general numeric limits
    };
}
這個通用性template將成員is_specialized設(shè)為false唠叛,意思是對于型別T只嚣,無所謂極值的存在。

2. 各個具體型別的極值艺沼,由特化版本(specialization)提供:
namespace std
{
    /* numeric limits for int
    * - implementation defined
    */
    template <> class numeric_limits<int>
    {
    public:
        //yes, a specialization for numeric limits of int does exist
        static const bool is_specialized = true;

        static T min() throw()
        {
            return -2147483648;
        }
        static T max() throw()
        {
            return 2147483647;
        }
        static const int digits = 31;
        //...
    };
}

通用性numeric_limits template及其特化版本都放在<limits>頭文件中册舞。
C++ standard所囊括的特化版本涵蓋了所有數(shù)值基本型別:
bool/char/signed char/unsigned char/wchar_t、
short/unsigned short/int/unsigned int/long/ float/double/long double

class numeric_limits<>所有成員及其意義如下圖


p62_t4-2-0.png
p62_t4-2-1.png

4.2 float型別數(shù)值限定模板特殊化的示例(page62)

namespace std
{
    template<> class numeric_limits<float>
    {
    public:
        //yes,a specialization for numeric limits for limits of float does exist
        static const bool is_specialized = true;
    
        inline static float min() throw()
        {
            return 1.17549435E-38F;
        }
        inline static float max() throw()
        {
            return 3.40282347E+38F;
        }

        static const int digits = 24;
        static const int digits10 = 6;
    
        static const bool is_signed = true;
        static const bool is_integer = false;
        static const bool is_exact = false;
        static const bool is_bounded = true;
        static const bool is_modulo = false;
        static const bool is_iec559 = true;

        static const int radix = 2;

        inline static float epsilon() throw()
        {
            return 1.19209290E-07F;
        }

        static const float_round_style round_style = round_to_nearest;
        inline static float round_error() throw()
        {
            return 0.5F;
        }

        static const int min_exponent = -125;
        static const int max_exponent = +128;
        static const int min_exponent10 = -37;
        static const int max_exponent10 = +38;

        static const bool has_infinity = true;
        inline static float infinity() throw() {         return ...;}
        static const bool has_quiet_NaN = true;
        inline static float quiet_NaN() throw() {         return ...;}
        static const bool has_signaling_NaN = true;
        inline static float signaling_NaN() throw() {         return ...;}
        static const bool has_denorm_loss = false;
        inline static float infinity() throw() {         return ...;}

        static const bool traps = true;
        static const bool tinyness_before = true;
    };
}

note:數(shù)據(jù)成員是const或static障般,如此其值便在編譯期確定调鲸;
      至于函數(shù)定義的成員,某些編譯器無法在編譯期間確定其值挽荡。
      故同一份代碼在不同處理器上執(zhí)行可能得出不同浮點數(shù)藐石。
p64.png

C++ standard保證,若denorm_absent為0則為false定拟,若denorm_present為1且denorm_indeterminate為-1則二者都為true于微。故可把has_denorm視為一個bool以判斷某型別是否允許"denormalized values"。

4.3 numeric_limits<> 使用范例(page64)

/* 此例用于展示 某些型別極值的可能運用(eg了解某型別的最大值或確定char是否有符號)
*/
#include <iostream>
#include <limits>
#include <string>
using namespace std;

int main()
{
    // use textual representation for bool
    cout << boolalpha;

    // print maximum of integral type
    cout << "max(short): " << numeric_limits<short>::max() << endl;
    cout << "max(int): " << numeric_limits<int>::max() << endl;
    cout << "max(long): " << numeric_limits<long>::max() << endl;
    cout << endl;

    // print maximum of floating-point types
    cout << "max(float): " << numeric_limits<float>::max() << endl;
    cout << "max(double): " << numeric_limits<double>::max() << endl;
    cout << "max(long double): " << numeric_limits<long double>::max() <<endl;

    // print whether char is signed
    cout << "is_signed(char): " << numeric_limits<char>::is_signed << endl;
    cout << endl;

    // print whether numeric limits for type string exist
    cout << "is_specialized(string): " << 
            numeric_limits<string>::is_specialized << endl;
}

程序輸出結(jié)果與執(zhí)行平臺有關(guān)青自,如下是一種可能:


limits.png

4.5 輔助函數(shù)/比較操作符(page66)

4.5.1 輔助函數(shù)

算法程序庫(定義于頭文件<algorithm>)內(nèi)含3個輔助函數(shù)株依,一個是兩值取大,一個是兩值取小延窜,第三個用于交換兩值恋腕。

1. 挑選較小值和較大值
namespace std
{
    template <class T>
    inline const T& min(const T& a, const T& b)
    {
        return b < a ? b : a;
    }
    template <class T>
    inline const T& max(const T& a, const T& b)
    {
        return a < b ? b : a;
    }
}
如果兩值相等,通常返回第一值(程序最好不要依賴這一點)需曾。

另一版本:接受額外的template參數(shù)作為“比較準(zhǔn)則”
namespace std
{
    template <class T , class Compare>
    inline const T& min (const T& a, const T& b,Compare comp)
    {
        return comp(b,a) ? b : a;
    }
    template <class T , class Compare>
    inline const T& max (const T& a, const T& b,Compare comp)
    {
        return comp(a,b) ? b : a;
    }
}
作為“比較準(zhǔn)則”的參數(shù)應(yīng)該是函數(shù)或仿函數(shù),接受兩參數(shù)并比較:
    在某指定規(guī)則下吗坚,判斷第一個參數(shù)是否小于第二參數(shù)并返回判斷結(jié)果。
eg,code:
#include <algorithm>
using namespace std;

/*function that compares two pointers by comparing the values to which they point
 */
bool int_ptr_less (int* a, int* b)
{
    return *a < *b;
}

int main()
{
    int x = 17;
    int y = 42;
    int* px = &x;
    int* py = &y;
    int* pmax;

    // call max() with sepcial comparison function
    pmax = max (px, py, int_ptr_lesss);
    //...
}

2. 兩值互換
函數(shù)swap()用于交換兩對象的值呆万。其泛型版定義于<algorithm>商源。
namespace std
{
    template <class>
    inline void swap(T& a, T& b)
    {
        T tmp(a);
        a = b;
        b = tmp;
    }
}

當(dāng)且僅當(dāng)swap()所依賴的copy構(gòu)造函數(shù)和assignment操作行為存在時,這個調(diào)用才可能有效谋减。
swap()的最大優(yōu)勢:

透過template specialization或function overloading牡彻,可以為更復(fù)雜的型別提供特殊的版本:
    可交換對象內(nèi)部成員而不是反復(fù)賦值,如此可節(jié)約時間出爹。
    標(biāo)準(zhǔn)程序庫中所有容器都用了這項技術(shù)庄吼。eg:
        一個容器僅含一個array和一個成員(用于指示元素數(shù)量),那么其特化版本的swap()可以是:
class MyContainer
{
private:
    int* elems;  // dynamic array of elements
    int* numElems;  // numbers of elements
public:
    //...
    // implementation of swap()
    void swap(MyContainer& x) 
    {  
        std::swap(elems, x.elems);
        std::swap(numElems, x.numElems);
    }
    //...
    
    //overloaded global swap() for this type
    inline void swap(MyContainer& c1, MyContainer& c2)
    {
        c1.swap(c2);  // calls implementation of swap()
    }
}; 
4.5.2 輔助操作符(Comparison Operators)(page69)

有四個template functions严就,分別定義了!= 总寻、>、<=梢为、>=比較操作符渐行,它們都是利用操作符== 和 <完成的轰坊。四個函數(shù)定義于<utility>。

namespace std
{
    namespace rel_ops
    {
        template <class T>
        inline bool operator!= (const T& x, const T& y)
        {
            return !(x == y);
        }

        template <class T>
        inline bool operator> (const T& x, const T& y)
        {
            return y < x;
        }

        template <class T>
        inline bool operator<= (const T& x, const T& y)
        {
            return !(y < x);
        }

        template <class T>
        inline bool operator>= (const T& x, const T& y)
        {
            return !(x < y);
        }
    }
}

只要加上using namespace std::rel_pos上述四個比較操作符就自動獲得了定義祟印。

4.6 頭文件<cstddef>和<cstdlib> (page71)

4.6.1 <cstddef>各種含義
p71_t4-6.png
NULL通常表一個不指向任何對象的指針肴沫,即0(型別是int或long),但C中NULL常定義為(void*)0蕴忆。
C++ 中沒定義從 void*到任何其他型別的自動轉(zhuǎn)型操作颤芬。
NULL也定義于頭文件<cstdio>/<cstdlib>/<cstring>/<ctime>/<cwchar>/<clocale>。
4.6.2 <cstdlib>內(nèi)各種含義
p72_t4-7.png
常數(shù)EXIT_SUCCESS和EXIT_FAILURE用于作exit()的參數(shù)或main()的返回值套鹅。

經(jīng)由atexit()注冊的函數(shù)站蝠,在程序正常退出是會依注冊的相反次序被一一調(diào)用,
    無論是通過exit()退出或main()尾部退出芋哭,都是如此沉衣,不傳遞任何參數(shù)。

exit()和abort()可在任意處終止程序運行减牺,無需返回main()豌习。

exit()會銷毀所有static對象,將所有緩沖區(qū)buffer清空拔疚,關(guān)閉所有I/O通道channels,
    然后終止程序(之前會先調(diào)用由atexit()注冊的函數(shù))肥隆,
      若atexit()注冊的函數(shù)拋出異常則會調(diào)用terminate()。

abort()會立刻終止函數(shù)且不做任何清理clean up工作稚失。

note:這兩個函數(shù)都不會銷毀局部對象local objects栋艳,
    因為堆棧 輾轉(zhuǎn)開展動作stack inwinding 不會被執(zhí)行。
    為確保所有局部對象的析構(gòu)函數(shù)被調(diào)用句各,應(yīng)用異常exceptions或正常返回機(jī)制吸占,再由main()離開。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末凿宾,一起剝皮案震驚了整個濱河市矾屯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌初厚,老刑警劉巖件蚕,帶你破解...
    沈念sama閱讀 219,589評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異产禾,居然都是意外死亡排作,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,615評論 3 396
  • 文/潘曉璐 我一進(jìn)店門亚情,熙熙樓的掌柜王于貴愁眉苦臉地迎上來妄痪,“玉大人,你說我怎么就攤上這事楞件“柘模” “怎么了僧著?”我有些...
    開封第一講書人閱讀 165,933評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長障簿。 經(jīng)常有香客問我,道長栅迄,這世上最難降的妖魔是什么站故? 我笑而不...
    開封第一講書人閱讀 58,976評論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮毅舆,結(jié)果婚禮上西篓,老公的妹妹穿的比我還像新娘。我一直安慰自己憋活,他們只是感情好岂津,可當(dāng)我...
    茶點故事閱讀 67,999評論 6 393
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著悦即,像睡著了一般吮成。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上辜梳,一...
    開封第一講書人閱讀 51,775評論 1 307
  • 那天粱甫,我揣著相機(jī)與錄音,去河邊找鬼作瞄。 笑死茶宵,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的宗挥。 我是一名探鬼主播乌庶,決...
    沈念sama閱讀 40,474評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼契耿!你這毒婦竟也來了瞒大?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,359評論 0 276
  • 序言:老撾萬榮一對情侶失蹤宵喂,失蹤者是張志新(化名)和其女友劉穎糠赦,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體锅棕,經(jīng)...
    沈念sama閱讀 45,854評論 1 317
  • 正文 獨居荒郊野嶺守林人離奇死亡拙泽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,007評論 3 338
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了裸燎。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片顾瞻。...
    茶點故事閱讀 40,146評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖德绿,靈堂內(nèi)的尸體忽然破棺而出荷荤,到底是詐尸還是另有隱情退渗,我是刑警寧澤,帶...
    沈念sama閱讀 35,826評論 5 346
  • 正文 年R本政府宣布蕴纳,位于F島的核電站会油,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏古毛。R本人自食惡果不足惜翻翩,卻給世界環(huán)境...
    茶點故事閱讀 41,484評論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望稻薇。 院中可真熱鬧嫂冻,春花似錦、人聲如沸塞椎。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,029評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽案狠。三九已至服傍,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間莺戒,已是汗流浹背伴嗡。 一陣腳步聲響...
    開封第一講書人閱讀 33,153評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留从铲,地道東北人瘪校。 一個月前我還...
    沈念sama閱讀 48,420評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像名段,于是被迫代替她去往敵國和親阱扬。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 45,107評論 2 356

推薦閱讀更多精彩內(nèi)容