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