IEEE 754 浮点表示
IEEE 754 定义了计算机如何表示和存储非整数的数据, 如: 12.084
, 0.3
, -0.0043
. 对于整数, 我们只要把十进制的整数转换成二进制, 并且在最前面设置它的正数/负数的符号, 就很容易的存储.
浮点数转成二进制
浮点数转成二进制分成2部份: 整数部分和小数部份.
- 对于整数部分, 直接转成二进制, 比如
12
(十进制) =1100
(二进制). - 对于小数部份,
0.5
(十进制) =0.1
(二进制),0.25
(十进制) =0.01
(二进制),0.125
(十进制) =0.001
(二进制), 所以可以看到对于小数部份是通过把1整除的方式获得的. 所以0.375
(十进制) =1/4 + 1/8
=0.25 + 0.125
=0.01
(二进制) +0.001
(二进制) =0.011
(二进制).
所以:
12.125
12 = 8 + 4 = 1100
0.125 = 1/8 = 0.001
12.125 = 1100.001
科学计数法
科学记数法是一种记数的方法。 把一个数表示成a与10的n次幂相乘的形式(1≤|a|<10,a不为分数形式,n为整数),这种记数法叫做科学记数法。
例如:12.125
= 1.2125×10^1
, 19971400000000
=1.99714×10^13
, 0.00345
= 3.45×10^-3
.
所以它把一个数分成大于等于1小于10的科学计数部份和指数部分.
对于二进制, 同样适用科学计数法, 只不过二进制表示成科学计数法整数部分除了0之外, 只能有1. 比如:
12.125 = 1100.001 = 1.100001×2^3
0.375 = 0.011 = 1.1×2^-2
IEEE754 浮点表示
IEEE754 规定了单精度(32位)浮点数和双精度(64位)浮点数以及其他浮点数. 我们这里主要看单精度, 其它原理类似.
对于32位的浮点数, 32位分成 1位符号位(正负) + 8位指数 + 23位 科学计数数值.
符号位 0 表示正, 1 表示负.
比如: 12.125 = 1100.001 = 1.100001×2^3
, 它的符号位0
(正数), 指数部分是3
(二进制11), 科学计数数值是1.100001
(二进制). -0.375 = 0.011 = 1.1×2^-2
, 它的符号位数1
(负数), 指数部分是-2
(-10
二进制), 科学计数数值是1.1
(二进制).
需要进一步明确的地方:
- 8位指数从 00000000 ~ 11111111, 即0 ~ 255, 但是这样对于是负数的指数无法表示, 所以需要调整这个值从
0 ~ 255
表示成-127 ~ 128
. 即0
表示0-127 = -127
(指数),127 - 127 = 0
(指数为0
),255 - 127 = 128
. 但实际使用的时候,-127
和128
被用作特殊值处理, 实际可能的值只能是-126 ~ 127
. - 对于数值部分, 因为是科学计数法, 所以除了0之外, 其它时候都是1, 所以这个1可以去掉, 所以23位全部用来表示点之后的部份. 即
1.001101
只要使用001101
它,1.101
只要使用101
. 0表示成 23个0.
所以:12.125 = 1100.001 = 1.100001×2^3
-> 符号是0
, 指数部分原本是3
,转成127+3=130
,即二进制 10000010
, 科学计数部分去掉点之前的1
, 即是100001
. -0.375 = 0.011 = 1.1×2^-2
-> 符号是1
, 指数部分是-2
, 转成127-2=125
, 即二进制 1111101
, 科学计数部分去掉点之前的1
, 即是 1
.
对于指数部分不够8位只要前面补0, 对于科学计数部分, 由于是小数点后的, 所以后面补0. 于是: 12.125 = 1100.001 = 1.100001×2^3 =>
0 10000010 10000100000000000000000`. -0.375 = 0.11 = 1.1×2^-1
=> 1 01111101 1000000000000000000000
验证
让AI写了一段 C 代码, 来验证一把:
#include <stdio.h>
int main() {
float num1 = 12.125f;
float num2 = -0.375f;
// 将浮点数的二进制表示转换为字节表示
unsigned char *bytePtr1 = (unsigned char *)&num1;
unsigned char *bytePtr2 = (unsigned char *)&num2;
printf("12.125 的二进制表示为:\n");
for (int i = sizeof(float) - 1; i >= 0; i--) {
for (int j = 7; j >= 0; j--) {
printf("%d", (bytePtr1[i] >> j) & 1);
}
printf(" ");
}
printf("\n");
printf("-0.375 的二进制表示为:\n");
for (int i = sizeof(float) - 1; i >= 0; i--) {
for (int j = 7; j >= 0; j--) {
printf("%d", (bytePtr2[i] >> j) & 1);
}
printf(" ");
}
printf("\n");
return 0;
}
跑一台机器
12.125 的二进制表示为:
01000001 01000010 00000000 00000000
-0.375 的二进制表示为:
10111110 11000000 00000000 00000000