任何有小数点的数值,都会被编译器解释为浮点数,也叫实数。
1.浮点数的储存
为了存储浮点数,计算机将分配 4 字节(32 位)内存。
- 1 位用于符号
- 8 位用于指数部分
- 23 位为底数部分(小数部分)
我们一步一步说明计算机如何存储浮点数。
- 将浮点数转换为二进制数,我们把 10.75 转化成浮点数 (1010.11) 2;
- 使转换后的二进制数转化成标准形式
- 把浮点数统一以下列形式 1.小数位 bit * 2^指数1010.11 转换成标准形式:1.01011 * 2 3
-
- 在指数位增加一个偏移值 (偏置值)
在浮点数中存储中,不利用 2 的补码来存储负数。 但为了克服没有减法器问题,引入了偏移的概念,这样可以把浮点数的负数转变成正值并参与运算。这样,无论浮点数是负值还是正值,它们都会将偏移值添加到指数值以降低实现复杂性。
计算偏移值的公式是 : biasn = 2n-1 – 1;
8比特位的偏移值就是:2 7 – 1 = 127
因此,归一化指数值将是,实际指数 + 偏差值为 130 (3 + 127) – 130 的二进制形式是 10000010
10.75 的二进制储存如下图所示:
符号位为0代表该数是正数。
指数部分是130(二进制 10000010)
底数数值是 1.01011,这里我们可以消除点 (.) 之前 1和(.) ,因为无论数字是多少,我们总是要归一化为 1.something。 因此,无需存储 1和(.)。只需在 (.) 后面 01011 取位即可。
浮点数的类型声明使用float关键字,可以用来声明浮点数变量。
2.浮点变量 (实型变量)
任何有小数点的数值,都会被编译器解释为浮点数。所谓“浮点数”就是使用 m * be 的形式,存储一个数值,m
是小数部分,b
是基数(通常是2
),e
是指数部分。这种形式是精度和数值范围的一种结合,可以表示非常大或者非常小的数。
单精度(float型)、双精度(double型)和长双精度(long double型)三类。
单精度型占4个字节(32位)内存空间,其数值范围为3.4E-38~3.4E+38,只能提供七位有效数字。双精度型占8 个字节(64位)内存空间,其数值范围为1.7E-308~1.7E+308,可提供16位有效数字。
实型变量定义的格式和书写规则与整型相同。例如:
1 2 3 4 |
float c = 10.5; double a,b,c; // a,b,c为双精度实型量 |
上面示例中,变量c的就是浮点数类型。
float类型占用4个字节(32位),其中8位存放指数的值和符号,剩下24位存放小数的值和符号。float类型至少能够提供(十进制的)6位有效数字,指数部分的范围为(十进制的)-37到37,即数值范围为10-37到1037。
有时候,32位浮点数提供的精度或者数值范围还不够,C 语言又提供了另外两种更大的浮点数类型。
- double:占用8个字节(64位),至少提供13位有效数字。
- long double:通常占用16个字节。
注意,由于存在精度限制,浮点数只是一个近似值,它的计算是不精确的,比如 C 语言里面0.1 + 0.2并不等于0.3,而是有一个很小的误差。
1 |
if (0.1 + 0.2 == 0.3) // false |
C 语言允许使用科学计数法表示浮点数,使用字母e
来分隔小数部分和指数部分。
1 2 3 |
double x = 123.456e+3; // 123.456 x 10^3 // 等同于 double x = 123.456e3; |
上面示例中,e后面如果是加号+,加号可以省略。注意,科学计数法里面e的前后,不能存在空格。
另外,科学计数法的小数部分如果是0.x或x.0的形式,那么0可以省略。
1 2 3 4 5 6 |
0.3E6 // 等同于 .3E6 3.0E6 // 等同于 3.E6 |
例1.浮点数精度显示
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
#include <stdio.h> int main() { int a = 1; char b = 'G'; double c = 3.14; printf("Hello World!\n"); // printing the variables defined // above along with their sizes printf("Hello! I am a character. My value is %c and " "my size is %lu byte.\n", b, sizeof(char)); // can use sizeof(b) above as well printf("Hello! I am an integer. My value is %d and " "my size is %lu bytes.\n", a, sizeof(int)); // can use sizeof(a) above as well printf("Hello! I am a double floating point variable." " My value is %lf and my size is %lu bytes.\n", c, sizeof(double)); // can use sizeof(c) above as well printf("Bye! See you soon. :)\n"); return 0; } |
结果
1 2 3 4 5 6 7 8 |
Hello World! Hello! I am a character. My value is G and my size is 1 byte. Hello! I am an integer. My value is 1 and my size is 4 bytes. Hello! I am a double floating point variable. My value is 3.140000 and my size is 8 bytes. Bye! See you soon. :) Process returned 0 (0x0) execution time : 0.871 s Press any key to continue. |
例2. 浮点数的精度显示
1 2 3 4 5 6 7 8 9 10 |
#include int main(void) { float a; double b; a=33333.33333; b=33333.33333333333333; printf("a=%f\nb=%f\n",a,b); return 0; } |
1 2 3 4 5 |
a=33333.332031 b=33333.333333 Process returned 0 (0x0) execution time : 0.851 s Press any key to continue. |