阅读 ‧ 电子书库 对C99的支持
在实现C99特性方面,编译器厂商有着不同的步伐和不同的优先选择。在编写本书第五版的时候,有些编译器还没有实现inttypes.h头文件和功能。
3.4.6 float、double和long double类型

多数软件开发项目使用各种整数类型就可以工作得很好了。然而,财务和数学计算程序经常使用的是浮点数。C语言中浮点数包括float、double和long double类型,它们对应于FORTRAN和Pascal语言中的real类型。我们已经提到过,浮点方法能够表示包括小数在内的更大范围的数。浮点数表示类似于科学记数法。

科学家们使用科学记数法表示很大和很小的数,这种记数法用十进制小数和10的幂的乘积来表示数字。表3.3是一些记数法的例子。

表3.3 一些记数法的例子

 

广告:个人专属 VPN,独立 IP,无限流量,多机房切换,还可以屏蔽广告和恶意软件,每月最低仅 5 美元

 

数学 科学记数法 指数记数法
1 000 000 000 =1.0×105 =1.0e9
123 000 =1.23×105 =1.23e5
322.56 =3.2256×102 =3.2256e2
0.000 056 =5.6×10-5 =5.6e-5

第一列是一般的记数法,第二列是科学记数法,第三列是指数记数法(或称为e-记数法),即科学记数法在计算机中的书写方式,其中e后面是10的指数。图3.7显示了更多的浮点数表示方法。

C标准规定,float类型必须至少能表示6位有效数字,取值范围至少为10-37到10+37。6位有效数字指浮点数至少应能精确表示像33.333 333这样的数字的前6位。取值范围的这一规定使您可以方便地表示诸如太阳的质量(2.0e30千克)、质子的电量(1.6e-19库仑)以及国家债务之类的数字。通常,系统使用32位存储一个浮点数。其中8位用于表示指数及其符号,24位用于表示非指数的部分(称为尾数或有效数字)及其符号。

C还提供一种称为double(意为双精度)的浮点类型。double类型和float类型具有相同的最小取值范围要求,但它必须至少能表示10位有效数字。一般地,double使用64位而不是32位长度。一些系统将多出的32位全部用于尾数部分,这增加了数值的精度并减小了舍入误差。其他的一些系统将其中的一些位分配给指数部分,以容纳更大的指数,从而增加了可以表示的数的范围。每种分配方法都使得数值至少具有13位有效数字,超出了C的最小标准规定。

C提供了第三种浮点类型long double类型,以满足比double类型更高的精度需求。不过,C只保证long double类型至少同double类型一样精确。

阅读 ‧ 电子书库

图3.7 一些浮点数

一、声明浮点变量

浮点变量的声明以及初始化方法同整型变量相同,下面是一些例子:

float noah, jonah;

double trouble;

float planck = 6.63e-34;

long double gnp;

二、浮点常量

书写浮点常量有很多种选择。一个浮点常量最基本的形式是:包含小数点的一个带符号的数字序列,接着是字母e或E,然后是代表10的指数的一个有符号值。下面是两个有效的浮点常量:

-1.56E+12

2.87e-3

可以省略正号。可以没有小数点(2E5)或指数部分(19.28),但是不能同时没有二者。可以省略纯小数部分(3.E16)或整数部分(.45E-6),但是二者不能同时省略(那样做会什么也不会剩下)。下面是更多的有效浮点常量:

3.14159

.2

4e16

.8E-5

100.

在浮点常量中不要使用空格。

错误 1.56 E+12

默认情况下,编译器将浮点常量当作double类型。例如,假设some是一个float变量,您有下面的语句:

some = 4.0 * 2.0;

那么4.0和2.0被存储为double类型,(通常)使用64位进行存储。乘积运算使用双精度,结果被截为正常的float长度。这能保证计算精度,但是会减慢程序的执行。

C使您可以通过f或F后缀使编译器把浮点常量当作float类型,比如2.3f和9.11E9F。1或L后缀使一个数字成为long double类型,比如54.31和4.32e4L。建议使用L后缀,因为字母l和数字1容易混淆。没有后缀的浮点常量为double类型。

C99为表示浮点常量新添加了一种十六进制格式。这种格式使用前缀0x或0X,接着是十六进制数字,然后是p或P(而不是e或E),最后是2的指数(而不是10的指数),如下所示:

0xa.1fp10

a是10, .If表示1/16加上15/256,p10表示210 (即1024)。整个数的十进制值为10364.0。

并非所有的C编译器都添加了对这一C99特性的支持。

三、打印浮点值

printf()函数使用%f格式说明符打印十进制记数法的float和double数字,用%e打印指数记数法的数字。如果系统支持C99的十六进制格式浮点数,您可以使用a或A代替e或E。打印long double类型需要%Lf、%Le和%La说明符。注意float和double类型的输出都使用%f、%e或%a说明符。这是由于当它们向那些未在原型中显式说明参数类型的函数(如printf())传递参数时,C自动将float类型的参数转换为double类型,程序清单3.7演示了这一特性。

程序清单3.7 showf_pt.c程序

阅读 ‧ 电子书库

输出结果如下:

32000.000000 can be written 3.200000e+04

2140000000.000000 can be written 2.140000e+09

0.000053 can be written 5.320000e-05

上例使用了默认输出效果。下一章将讨论通过设置字段宽度和小数位数来控制输出的外观。

四、浮点值的上溢和下溢

假设系统中最大的float值为3.4E38,并进行如下操作:

float toobig = 3.4E38 * 100.0f:

print (“%e\n”, toobig);

会发生什么?这是一个上溢(overflow)的例子。当计算结果是一个大得不能表达的数时,会发生上溢。对这种情况的反应原来没有规定,但是现在的C语言要求为toobig赋予一个代表无穷大的特殊值,printf()函数显示此值为inf或infinity(或这个含义的其他名称)。

当除以一个十分小的数时,情况更复杂一些。回忆一下,float数字被分为指数和尾数部分进行存储。有这样的一个数,它具有最小的指数,并且仍具有可以由全部可用位进行表示的最小的尾数值。这将是能用对浮点值可用的全部精度进行表示的最小数字。现在把此数除以2。通常这个操作将使指数部分减小,但是指数已经达到了最小值;所以计算机只好将尾数部分的位进行右移,空出首位二进制位,并丟弃最后一位二进制值。以十进制为例,把一个包含四位有效数字的数0.1234E-10除以10,将得到结果0.0123E-10,但是损失了一位有效数字。此过程称为下溢(underflow)。C将损失了类型精度的浮点值称为低于正常的(subnormal),所以把最小的正浮点数除以2将得到一个低于正常的值。如果除以一个足够大的值,将使所有的位都为0。现在C库提供了用于检查计算是否会产生低于正常的值的函数。

还有另外一个特殊的浮点值NaN(Not-a-Number)。例如asin()函数返回反正弦值,但是正弦值不能大于1,所以asin()函数的输入参数不能大于1,否则函数返回NaN值,printf()函数将此值显示为nan, NaN或类似形式。