原文form
当我们需要存储很大的数值,或有些数字具有小数部分时,可以使用浮点型。一个浮点型的变量能够存储一个实数,如4.0,2.5,3.33,0.1226。有三种不同的浮点数类型:float,double,long double。fload有4个字节,double有8个字节,这些并不是严格不变的。long double是在后来的版本中加入进去的。但是通常上来讲,它也是8个字节大小。浮点型数总是有符号的。
下面是一些声明
1: float fValue;
2: double dValue;
3: long double dValue2;
浮点型之所以浮点之称,因为小数部分的位数会发生变化,2.5有一个小数位,而0.1226有4个小数位。
当我们把一个值赋值给浮点型时,至少使用一个小数位。这样能够更好的区别浮点型和整型。
1: int nValue = 5; // 5 means integer
2: float fValue = 5.0; // 5.0 means floating point
一个浮点型变量如何储存信息超出了这个教程的范围,但是与将一个数字写成科学计数法很相似。科学计数法是将一个很长的数据用简单的方式书写的很有用的方法。在科学计数法中,一个数值有两个部分:有效数字和指数部分。用字母‘e’,‘E'来隔离这两部分。如,5e2,与5*10^2,或者500相等。
事实上,我们可以用科学计数法将一个值赋值给浮点型变量。
1: double dValue1 = 500.0;
2: double dValue2 = 5e2; // another way to assign 500
3:
4: double dValue3 = 0.05;
5: double dValue4 = 5e-2; // another way to assign 0.05
而且,当我们想要输出的数字足够大,或是有足够多的小数部分,它将以科学计数法的方式被输出。
1: #include
2: int main()
3: {
4: using namespace std;
5:
6: double dValue = 1000000.0;
7: cout << dValue << endl;
8: dValue = 0.00001;
9: cout << dValue << endl;
10: return 0;
11: }
结果:
1e+0061e-005
精度
来看一个数字,1/3,用小数表示为0.33333333333333…,有无限个3.无限长的数据会占据无限的内存,而我们只有4个或8个字节的存储空间。浮点型数值只能存储一定数量的数字,其余部分将被丢失。
当输出浮点型数值时,cout的默认精度是6,它假设所有的变量都仅仅有6个有效数字,超出的部分都将被丢弃。
1: #include
2: int main()
3: {
4: using namespace std;
5: float fValue;
6: fValue = 1.222222222222222f;
7: cout << fValue << endl;
8: fValue = 111.22222222222222f;
9: cout << fValue << endl;
10: fValue = 111111.222222222222f;
11: cout << fValue << endl;
12: }
结果如下
1.22222111.222111111
但是我们可以重设默认的精度,通过函数setprecision(),它在头文件 iomanip 中被定义。
1: #include
2: #include// for setprecision()
3: int main()
4: {
5: using namespace std;
6:
7: cout << setprecision(16); // show 16 digits
8: float fValue = 3.33333333333333333333333333333333333333f;
9: cout << fValue << endl;
10: double dValue = 3.3333333333333333333333333333333333333;
11: cout << dValue << endl;
12: }
结果为:
3.3333332538604743.333333333333334
我们将精度设为16个数字,上面的两个结果都有16个数字,但是,这些数字确实不是精确到16个数字的。
float类型的变量通常只有7个有效数字(这是为什么,后面的结果输出的不是3)。double类型的数字通常有16位有效数字。
现在让我们看一数值非常大时:
1: #include
2:
3: int main()
4: {
5: using namespace std;
6: float fValue = 123456789.0f;
7: cout << fValue << endl;
8: return 0;
9: }
结果:
1.23457e+008
它的值为123457000.也就是说在这里我们的精度有损失。
因此,当使用浮点型数值的时候,需要比变量能够拥有的更多的精度时,应该小心谨慎。
凑整的错误(rounding error)
浮点型值可能棘手的一个原因是二进制数和以十进制为基准的小数没有明显的变化。正常的小数,1/3是无限小数:0.333333…类似的,1/10。被解释为0.1,我们会认为0.1是一个能够本容易被解释的数字。但是,在二进制里,0.1被解释成无限的序列:
0.00011001100110011…
看一下下面的代码:
1: #include
2: int main()
3: {
4: using namespace std;
5: cout << setprecision(17);
6: double dValue = 0.1;
7: cout << dValue << endl;
8: }
结果:
0.10000000000000001
并不等于0.1。因为double类型由于内存的限制,将超出部分进行了截断,这导致了最后结果并不等于0.1.这被称为凑整的错误(rounding error)
rounding error在数值计算含量较大的程序里会带来巨大破坏。数学上的操作通常混合着错误。下面的程序我们使用了9个加号。
1: #include
2: #include
3: int main()
4: {
5: using namespace std;
6: cout << setprecision(17);
7: double dValue;
8: dValue = 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1;
9: cout << dValue << endl;
10: }
这个输出结果应该是1,但是:
0.99999999999999989
注意不像0.10000000000000001这个结果中,误差出现在最后一个数字。它出现在最后第二个数字。当你继续数学操作计算时,这个误差能够进一步传的更远,导致实际的数字比用户想要的差异的越来越远。
浮点型数值之间的比较
程序员通常对数字或变量要做的事情有查看两个数之间是否相等。C++提供了==操作符。如:
1: int x = 5; // integers have no precision issues
2: if (x==5)
3: cout << "x is 5" << endl;
4: else
5: cout << "x is not 5" << endl;
输出的结果是x is 5
但是当浮点型数据进行比较时,你可能得到意外的结果。
1: float fValue1 = 1.345f;
2: float fValue2 = 1.123f;
3: float fTotal = fValue1 + fValue2; // should be 2.468
4:
5: if (fTotal == 2.468)
6: cout << "fTotal is 2.468";
7: else
8: cout << "fTotal is not 2.468";
程序输出的是
fTotal is not 2.468
这个结果导致的原因是rounding error。fTotal确切的是存储为2.4679999,它并不等于2.468.
作为同一个原因,用比较操作符 >, >=, <和<=时,当两个浮点型数据很接近是会产生错误。
结论
总结,关于浮点型数值,应该记住两件事情:
1) 浮点型数据提供有限的精度。float型通常提供7个有效数值的精度,double提供16个有效数字的精度。如果想使用更多的有效数字,就会使精度损失。(注意:占位符0,并不被当作有效数字,22,000,000,000, or 0.00000033 都只有两个有效数字。
2) 浮点型数据通常有小的rounding error。很多时候这并不被注意,因为它们实在是太小了,还因为在误差传播到这个部分前截断的数据用作输出的部分并没有发生截断现象。当两个数接近的时候,两者之间的比较可能产生意料外的结果。
在相关操作符一节中,我们会讨论更多的关于浮点型数值比较的内容。
转载请注明来自: