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

字號:

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