C语言小数(float、double和long double)
小数分为整数部分和小数部分,它们由点号
此外,小数也可以采用指数形式,例如 7.25×102、0.0368×105、100.22×10-2、-27.36×10-3 等。任何小数都可以用指数形式来表示。
C语言同时支持以上两种形式的小数。但是在书写时,C语言中的指数形式和数学中的指数形式有所差异。
C语言中小数的指数形式为:
指数形式的小数举例:
C语言提供了 3 种小数类型,分别是 float、double 和 long double,前两种用的最多。float 称为单精度浮点型,double 称为双精度浮点型,long double 称为长双精度浮点型。
float 和 double 类型的长度是固定的,float 始终占用 4 个字节,double 始终占用 8 个字节。C语言只规定了 long double 的长度至少和 double 相同,实际测试的结果是,该类型在 Windows 环境中占用 8 个字节,在 64 位 Linux 环境中占用 16 个字节。
下面的代码演示了小数的表示以及输出:
a=128.100998
b=0.302000
c=123.000000
d=1.126400E+05
e=0.007623
f=1.230024
对代码的说明:
1) %f、%lf 和 %Lf 默认保留六位小数,不足六位以 0 补齐,超过六位按四舍五入截断。
2) 将整数赋值给浮点型变量时会变成小数。
3) 以指数形式输出小数时,输出结果为科学计数法;也就是说,尾数部分的取值为:0 ≤ 尾数 < 10。
4) a 的输出结果让人费解,才三位小数,为什么不能精确输出,而是输出一个近似值呢?这和小数在内存中的存储形式有关,很多简单的小数压根不能精确存储,所以也就不能精确输出,我们将在下节《小数在内存中是如何存储的,揭秘诺贝尔奖级别的设计(长篇神文)》中详细讲解。
另外,小数还有一种更加智能的输出方式,就是使用
%g 使用示例:
a=1e-05
b=3e+07
c=12.84
d=1.22934
对各个小数的分析:
读者需要注意的两点是:
总之,%g 要以最短的方式来输出小数,并且小数部分表现很自然,不会强加零,比 %f 和 %e 更有弹性,这在大部分情况下是符合用户习惯的。
除了 %g,还有 %lg、%Lg、%G、%lG、%LG:
如果不想让小数使用默认的类型,那么可以给小数加上后缀,手动指明类型:
请看下面的代码:
对于初学者,很少会用到数字的后缀,加不加往往没有什么区别,也不影响实际编程,但是既然学了C语言,还是要知道这个知识点的,万一看到别人的代码这么用了,而你却不明白怎么回事,那就尴尬了。
请看下面的代码:
f = 251.000000, w = 19, x = 92, y = 0, z = -87
由于将小数赋值给整数类型时会“失真”,所以编译器一般会给出警告,让大家引起注意。
.
分隔,例如 0.0、75.0、4.02、3.1415926、-1314.520、-0.27 等都是合法的小数,这是最常见的小数形式,我们将它称为十进制形式。此外,小数也可以采用指数形式,例如 7.25×102、0.0368×105、100.22×10-2、-27.36×10-3 等。任何小数都可以用指数形式来表示。
C语言同时支持以上两种形式的小数。但是在书写时,C语言中的指数形式和数学中的指数形式有所差异。
C语言中小数的指数形式为:
aEn 或 aen
a 为尾数部分,是一个十进制数;n 为指数部分,是一个十进制整数;E
或e
是固定的字符,用于分割尾数部分和指数部分。整个表达式等价于 a×10n。指数形式的小数举例:
- 2.1E5 = 2.1×105,其中 2.1 是尾数,5 是指数。
- 3.7E-2 = 3.7×10-2,其中 3.7 是尾数,-2 是指数。
- 0.5E7 = 0.5×107,其中 0.5 是尾数,7 是指数。
C语言提供了 3 种小数类型,分别是 float、double 和 long double,前两种用的最多。float 称为单精度浮点型,double 称为双精度浮点型,long double 称为长双精度浮点型。
float 和 double 类型的长度是固定的,float 始终占用 4 个字节,double 始终占用 8 个字节。C语言只规定了 long double 的长度至少和 double 相同,实际测试的结果是,该类型在 Windows 环境中占用 8 个字节,在 64 位 Linux 环境中占用 16 个字节。
小数的输出
小数也可以使用 printf 函数输出,包括十进制形式和指数形式,它们对应的格式控制符分别是:- %f 以十进制形式输出 float 类型;
- %lf 以十进制形式输出 double 类型;
- %Lf 以十进制形式输出 long double 类型;
- %e 以指数形式输出 float 类型,输出结果中的 e 小写;
- %E 以指数形式输出 float 类型,输出结果中的 E 大写;
- %le 以指数形式输出 double 类型,输出结果中的 e 小写;
- %lE 以指数形式输出 double 类型,输出结果中的 E 大写。
- %Le 以指数形式输出 long double 类型,输出结果中的 e 小写;
- %LE 以指数形式输出 long double 类型,输出结果中的 E 大写。
下面的代码演示了小数的表示以及输出:
#include <stdio.h> #include <stdlib.h> int main() { float a = 128.101; double b = 0.302; long double c = 123; float d = 112.64E3; double e = 0.7623e-2; long double f = 1.23002398; printf("a=%f \nb=%f \nc=%Lf \nd=%E \ne=%lf \nf=%Lf\n", a, b, c, d, e, f); return 0; }运行结果:
a=128.100998
b=0.302000
c=123.000000
d=1.126400E+05
e=0.007623
f=1.230024
对代码的说明:
1) %f、%lf 和 %Lf 默认保留六位小数,不足六位以 0 补齐,超过六位按四舍五入截断。
2) 将整数赋值给浮点型变量时会变成小数。
3) 以指数形式输出小数时,输出结果为科学计数法;也就是说,尾数部分的取值为:0 ≤ 尾数 < 10。
4) a 的输出结果让人费解,才三位小数,为什么不能精确输出,而是输出一个近似值呢?这和小数在内存中的存储形式有关,很多简单的小数压根不能精确存储,所以也就不能精确输出,我们将在下节《小数在内存中是如何存储的,揭秘诺贝尔奖级别的设计(长篇神文)》中详细讲解。
另外,小数还有一种更加智能的输出方式,就是使用
%g
。%g 会对比小数的十进制形式和指数形式,以最短的方式来输出小数,让输出结果更加简练。所谓最短,就是输出结果占用最少的字符。%g 使用示例:
#include <stdio.h> #include <stdlib.h> int main() { float a = 0.00001; float b = 30000000; float c = 12.84; float d = 1.229338455; printf("a=%g \nb=%g \nc=%g \nd=%g\n", a, b, c, d); return 0; }运行结果:
a=1e-05
b=3e+07
c=12.84
d=1.22934
对各个小数的分析:
- a 的十进制形式是 0.00001,占用七个字符的位置,a 的指数形式是 1e-05,占用五个字符的位置,指数形式较短,所以以指数的形式输出。
- b 的十进制形式是 30000000,占用八个字符的位置,b 的指数形式是 3e+07,占用五个字符的位置,指数形式较短,所以以指数的形式输出。
- c 的十进制形式是 12.84,占用五个字符的位置,c 的指数形式是 1.284e+01,占用九个字符的位置,十进制形式较短,所以以十进制的形式输出。
- d 的十进制形式是 1.22934,占用七个字符的位置,d 的指数形式是 1.22934e+00,占用十一个字符的位置,十进制形式较短,所以以十进制的形式输出。
读者需要注意的两点是:
- %g 默认最多保留六位有效数字,包括整数部分和小数部分;%f 和 %e 默认保留六位小数,只包括小数部分。
- %g 不会在最后强加 0 来凑够有效数字的位数,而 %f 和 %e 会在最后强加 0 来凑够小数部分的位数。
总之,%g 要以最短的方式来输出小数,并且小数部分表现很自然,不会强加零,比 %f 和 %e 更有弹性,这在大部分情况下是符合用户习惯的。
除了 %g,还有 %lg、%Lg、%G、%lG、%LG:
-
%g、%lg 和 %Lg 分别用来输出 float、double 和 long double 类型,并且当以指数形式输出时,
e
小写。 -
%G、%lG 和 %LG 分别用来输出 float、double 和 long double 类型,只是当以指数形式输出时,
E
大写。
小数的后缀
在 C 语言中,小数的类型默认是 double。请看下面的例子:float x = 52.55; double y = 18.6;52.55 和 18.6 这两个数字默认都是 double 类型的,将 52.55 赋值给 x,必须先从 double 类型转换为 float 类型,而将 18.6 赋值给 y 就不用转换了。
如果不想让小数使用默认的类型,那么可以给小数加上后缀,手动指明类型:
- 小数后面紧跟 f 或者 F(不区分大小写),表明它是 float 类型。
- 小数后面紧跟 l 或者 L(不区分大小写),表明它是 long double 类型。
请看下面的代码:
float x = 52.55f; double y = 18.6F; float z = 0.02;加上后缀,虽然小数的类型变了,但这并不意味着小数只能赋值给对应的类型,它仍然能够赋值给其他的类型,只要进行一下类型转换就可以了。
对于初学者,很少会用到数字的后缀,加不加往往没有什么区别,也不影响实际编程,但是既然学了C语言,还是要知道这个知识点的,万一看到别人的代码这么用了,而你却不明白怎么回事,那就尴尬了。
关于数据类型的转换,我们将在《C语言数据类型转换》一节中深入探讨。
小数和整数相互赋值
在C语言中,整数和小数之间可以相互赋值:- 将一个整数赋值给小数类型,在小数点后面加 0 就可以,加几个都无所谓。
- 将一个小数赋值给整数类型,就得把小数部分丢掉,只能取整数部分,这会改变数字本来的值。注意是直接丢掉小数部分,而不是按照四舍五入取近似值。
请看下面的代码:
#include <stdio.h> int main(){ float f = 251; int w = 19.427; int x = 92.78; int y = 0.52; int z = -87.27; printf("f = %f, w = %d, x = %d, y = %d, z = %d\n", f, w, x, y, z); return 0; }运行结果:
f = 251.000000, w = 19, x = 92, y = 0, z = -87
由于将小数赋值给整数类型时会“失真”,所以编译器一般会给出警告,让大家引起注意。