C++數(shù)據(jù)類(lèi)型的屬性與限制

字號(hào):

在C++中,每一種內(nèi)置的數(shù)據(jù)類(lèi)型都擁有不同的屬性,其中包含的信息對(duì)設(shè)計(jì)程序來(lái)說(shuō)是非常重要的,下面來(lái)看一下,庫(kù)是怎樣有助于訪問(wèn)這些信息的。
    C++中約有10種截然不同的整數(shù)類(lèi)型及超過(guò)3種的浮點(diǎn)類(lèi)型,而每種數(shù)據(jù)類(lèi)型都有不同的數(shù)值屬性,如數(shù)值范圍、能表示的位數(shù)、或各自的精度等等,這些屬性對(duì)金融、科學(xué)、圖形、數(shù)字信號(hào)處理等程序來(lái)說(shuō)是極其重要的。本文討論使用庫(kù),怎樣在程序中獲得這些基本數(shù)據(jù)類(lèi)型的數(shù)值屬性。
    "一個(gè)double類(lèi)型中能存儲(chǔ)多少位?","signed long能表示的正數(shù)是多少?"如果這些問(wèn)題的答案對(duì)你的程序很重要,那么你怎樣以一種方便、且系統(tǒng)的方法來(lái)得到答案呢?答案就是:使用標(biāo)準(zhǔn)庫(kù)。
    浮點(diǎn)的樂(lè)章
    C++中浮點(diǎn)數(shù)據(jù)類(lèi)型精度是有限的,某些與硬件有關(guān)的特性導(dǎo)致了浮點(diǎn)數(shù)據(jù)類(lèi)型的截?cái)嗯c取整?,F(xiàn)在,你就明白為什么2.0/3.0的結(jié)果大概是0.66666666666666663了吧,"數(shù)字噪音"通常是大多數(shù)bug的源頭,請(qǐng)看如下例子:
    double d1=2., d2=3.;
    d1/=d2; // 2/3
    if (d1*10==(20./d2)) //條件本應(yīng)該是"真"的,但,哎!
    {
    //永遠(yuǎn)不可能執(zhí)行到的代碼
    do_equal();
    }
    花括號(hào)中的代碼行永遠(yuǎn)也不可能執(zhí)行,因?yàn)樵?== 兩邊的表達(dá)式結(jié)果會(huì)有輕微的差別,d1*10的結(jié)果是6.6666666666666661,而20./d2的結(jié)果是6.6666666666666670,正是這種浮點(diǎn)算法的截?cái)嗯c近似值導(dǎo)致了此差異的發(fā)生。在此,可使用定標(biāo)整數(shù),但有時(shí)這并不是一個(gè)妥善的解決辦法,試想有一張計(jì)算復(fù)數(shù)公式的電子表格--它必須使用浮點(diǎn)類(lèi)型,在這種情況下,小正數(shù)(epsilon)常量這個(gè)問(wèn)題就來(lái)了,小正數(shù)通常為可用給定數(shù)據(jù)類(lèi)型的大于1的最小值與1之差來(lái)表示。舉例來(lái)說(shuō),double類(lèi)型的小正數(shù)為:
    #include
    #include
    using namespace std;
    cout << numeric_limits::epsilon( ) << endl; //輸出:2.22045e-016
    為減少if語(yǔ)句中數(shù)字噪音帶來(lái)的影響,可用一個(gè)檢查兩值粗略相等的表達(dá)式來(lái)代替 == 操作符。如:
    if ( ((d1*10)-(20.0/d2)) <= numeric_limits::epsilon())
    {
    do_equal();
    }
    如果double類(lèi)型的(d1*10)-(20.0/d2)結(jié)果不大于小正數(shù),那么它幾乎為零,因此,兩個(gè)子表達(dá)式結(jié)果相等,應(yīng)用此技巧可有效降低錯(cuò)誤的閥值。例如,如果十億分之一或者更小的數(shù)值,對(duì)你的程序來(lái)說(shuō)無(wú)關(guān)緊要,那么可試下以下的技巧:
    const double BILLIONTH=1./1000000000;
    if ( ((d1*10)-(20.0/d2)) <= BILLIONTH)
    此處請(qǐng)記住,小正數(shù)是最小的偏差極限。
    比double更好
    選擇一種浮點(diǎn)數(shù)據(jù)類(lèi)型的標(biāo)準(zhǔn),是它可以在精度無(wú)損的情況下存儲(chǔ)的十進(jìn)制位數(shù)。例如,假設(shè)你的程序必須支持到16位的十進(jìn)制數(shù),那么應(yīng)該使用double、long double還是用戶(hù)自定義類(lèi)型呢?要解答此問(wèn)題,可使用numeric_limits::digits10常量,它會(huì)告訴你在精度無(wú)損情況下某種類(lèi)型可表示的十進(jìn)制位數(shù):
    cout<::digits10<    看起來(lái)double并不支持這種精度,那么long double呢?
    cout<::digits10<    對(duì)了,它就可以。請(qǐng)注意,digits10對(duì)整型數(shù)也同樣適用:
    cout<::digits10<    值與最小值
    值與最小值即是對(duì)相應(yīng)類(lèi)型調(diào)用numeric_limits::max()和numeric_limits:min()所得到的值:
    cout<::max()<    無(wú)限的
    在IEC 559規(guī)范實(shí)現(xiàn)中,浮點(diǎn)數(shù)據(jù)類(lèi)型可表示為"不是一個(gè)數(shù)字"或NaN。NaN是一種特殊的編碼,其代表某種非法數(shù)字,可由非法指令產(chǎn)生,或意為指示一個(gè)不應(yīng)被忽略的數(shù)值。如果出現(xiàn)在表達(dá)式中的NaN沒(méi)有發(fā)出一個(gè)"信號(hào)",則其為"安靜"狀態(tài);否則,其為一個(gè)發(fā)"信號(hào)"的NaN。下面的例子檢查在目標(biāo)平臺(tái)上支持哪種NaN類(lèi)型,并把NaN的值賦給一個(gè)變量:
    double d=0;
    if(numeric_limits::has_quiet_NaN)
    d=numeric_limits::quiet_NaN();
    else if (numeric_limits::has_signaling_NaN)
    d=numeric_limits::signaling_NaN();
    else cerr<<"NaN for double isn't supported";
    無(wú)限在此是一種特殊的情況,其通常由被零除或其他操作產(chǎn)生。下例代碼檢查目標(biāo)平臺(tái)上是否定義了一種特殊的無(wú)限碼,并把此值賦給一個(gè)變量:
    float f=0;
    if(numeric_limits::has_infinity)
    f=numeric_limits::infinity();
    else cerr<<"infinity for float isn't supported";