C++数据类型的属性与限制
时间:2010-11-26 来源:teiller2008
double d1=2., d2=3.; d1/=d2; // 2/3 if (d1*10==(20./d2)) //条件本应该是\"真\"的,但,哎! { //永远不可能执行到的代码 do_equal(); } |
花括号中的代码行永远也不可能执行,因为在 == 两边的表达式结果会有轻微的差别,d1*10的结果是6.6666666666666661,而20./d2的结果是6.6666666666666670,正是这种浮点算法的截断与近似值导致了此差异的发生。在此,可使用定标整数,但有时这并不是一个妥善的解决办法,试想有一张计算复数公式的电子表格--它必须使用浮点类型,在这种情况下,小正数(epsilon)常量这个问题就来了,小正数通常为可用给定数据类型的大于1的最小值与1之差来表示。举例来说,double类型的小正数为:
#include <iostream> #include <limits> using namespace std; cout << numeric_limits<double>::epsilon( ) << endl; //输出:2.22045e-016 |
为减少if语句中数字噪音带来的影响,可用一个检查两值粗略相等的表达式来代替 == 操作符。如:
if ( ((d1*10)-(20.0/d2)) <= numeric_limits<double>::epsilon()) { do_equal(); } |
如果double类型的(d1*10)-(20.0/d2)结果不大于小正数,那么它几乎为零,因此,两个子表达式结果相等,应用此技巧可有效降低错误的阀值。例如,如果十亿分之一或者更小的数值,对你的程序来说无关紧要,那么可试下以下的技巧:
const double BILLIONTH=1./1000000000; if ( ((d1*10)-(20.0/d2)) <= BILLIONTH) |
此处请记住,小正数是最小的偏差极限。
比double更好
选择一种浮点数据类型的标准,是它可以在精度无损的情况下最大存储的十进制位数。例如,假设你的程序必须支持到16位的十进制数,那么应该使用double、long double还是用户自定义类型呢?要解答此问题,可使用numeric_limits::digits10常量,它会告诉你在精度无损情况下某种类型可表示的最大十进制位数:
cout<<numeric_limits<double>::digits10<<endl;//输出:15 |
看起来double并不支持这种精度,那么long double呢?
cout<<numeric_limits<long double>::digits10<<endl; //输出:18 |
对了,它就可以。请注意,digits10对整型数也同样适用:
cout<<numeric_limits<long>::digits10<<endl; //输出:9 |
最大值与最小值
最大值与最小值即是对相应类型调用numeric_limits::max()和numeric_limits:min()所得到的值:
cout<<numeric_limits<int>::max()<<endl;// 2147483647 |
无限的<limits>
在IEC 559规范实现中,浮点数据类型可表示为\"不是一个数字\"或NaN。NaN是一种特殊的编码,其代表某种非法数字,可由非法指令产生,或意为指示一个不应被忽略的数值。如果出现在表达式中的NaN没有发出一个\"信号\",则其为\"安静\"状态;否则,其为一个发\"信号\"的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\"; |
无限在此是一种特殊的情况,其通常由被零除或其他操作产生。下例代码检查目标平台上是否定义了一种特殊的无限码,并把此值赋给一个变量:
float f=0; if(numeric_limits<float>::has_infinity) f=numeric_limits<float>::infinity(); else cerr<<\"infinity for float isn\'t supported\"; |