文章目录
- 一、基本介绍
- 二、IEEE 754标准浮点数
- 三、浮点数的运算
- 3.1 浮点数的加减法
- 3.2 浮点数的乘法
- 3.3 浮点数的除法
- 四、demo
- 参考
一、基本介绍
浮点数是与定点数相对的概念,计算机中的定点数约定小数点的位置不变。
由于计算机字长的限制,当需要表示的数据有很大的数值范围时,不能直接用定点小数或者定点整数表示。
浮点数由尾数 M M M和阶码 E E E构成。
基数为2的数
F
F
F的浮点数表示为:
F
=
2
E
×
M
F = 2^E \times M
F=2E×M
浮点数编码的规则:
- 尾数 M M M必须为小数,用 n + 1 n+1 n+1位有符号定点小数的形式表示,可以采用原码、补码
- 阶码 E E E必须为整数,用 k + 1 k+1 k+1位有符号定点整数表示,可以采用原码、补码、移码
- 浮点数的编码位数 m = ( n + 1 ) + ( k + 1 ) m=(n+1)+(k+1) m=(n+1)+(k+1)
浮点数的编码格式有多种,格式的选择可以由计算机设计人员决定,例如:
详细解释
- 阶码是整数,其位数 k + 1 k+1 k+1决定了浮点数表示的数值范围(小数点在数据中的真实位置)。阶符决定了阶码的正负。阶码越长,所能表示的范围越大。
- 尾数是小数,其位数 n + 1 n+1 n+1决定了浮点数的精度。尾数越长,所能表示的精度越高。
- 尾数的符号表示浮点数的正负。
二、IEEE 754标准浮点数
IEEE 754规定单精度浮点数的真值一般表示为:
N
=
(
−
1
)
s
×
2
e
−
127
×
1.
f
N = (-1)^s \times 2^{e-127} \times 1.f
N=(−1)s×2e−127×1.f
单精度浮点数的编码格式由3个字段构成
- 数符 s s s为1位,表示浮点数的正负
- 尾数编码 f f f为23位,采用原码表示
- 阶码 e e e编码为8位( 含1位阶符,采用移码表示,偏移量127 )
注意点:
- IEEE 754中的阶码采用移码来表示,但是对于单精度浮点数来说,移码的偏移量不是 2 7 2^7 27,而是 2 7 − 1 = 127 2^7-1 = 127 27−1=127, 因为IEEE 754 将移码编码的全0和全1作为了特殊标识。
- IEEE 754浮点数为规格化的浮点数,为了能够更多的表示尾数的有效位数,规定尾数真值的整数部分必须为1,尾数编码时整数1隐去,小数部分 f f f用原码表示。
IEEE 754阶码的规定
IEEE 754标准的32位浮点数格式为:
- 数符:0正,1负
- 阶码:阶码真值+127
- 尾数:23位,采用隐含尾数最高位1的表示方法,实际尾数24位,尾数真值=1+尾数
阶码e全0和全1时的特殊含义:
- 阶码全0,且尾数f不全为0时,表示表示该浮点数不是规格化浮点数。
- 阶码e全1,且尾数f全0时,则该浮点数表示正无穷大或者负无穷大,当数符s为1时,表示负无穷大,当数符s为0时,表示正无穷大。
- 阶码e全1,且尾数不全为0时,则该浮点数表示非数值数据(NaN)。
浮点数的舍入规则:
- 就近舍入
- 朝0舍入
- 朝无穷大舍入
- 朝负无穷舍入
三、浮点数的运算
3.1 浮点数的加减法
- 对阶:尾数右移,小阶对大阶,阶码小的尾数右移,阶码+1
- 尾数加减法运算:使用补码运算,减法也采用补码加法实现
- 规格化:尾数加减法运算后,结果可能是非规格化数,如果结果的真值 M M M不满足 1 2 < M < 1 \frac{1}{2} < M < 1 21<M<1,则是非规格化数需要进行规格化处理。
3.2 浮点数的乘法
- 两乘数一定是规格化数,若有一个乘数为0,则乘积一定为0。
- 求乘积的阶码: E z = E x + E y E_z = E_x + E_y Ez=Ex+Ey, 判断积的阶码是否溢出:上溢、下溢
- 求乘积的尾数:两乘数的尾数相乘。
- 规格化乘积的尾数
3.3 浮点数的除法
- 被除数、除数一定是规格化数,除数不等于0,若被除数为0,则商必为0
- 求商的阶码: E z = E x − E y E_z = E_x - E_y Ez=Ex−Ey, 判断商的阶码是否溢出:上溢、下溢
- 求商的尾数: M z = M x ÷ M y M_z = M_x \div M_y Mz=Mx÷My
- 规格化商的尾数
四、demo
展示C语言中单精度1.0和-1.0的表示
#include <stdio.h>
#include <stdlib.h>
/**
* float 31 30-23 22-0
* 符号位 阶码 尾数
*/
/**
* 大端模式(大端字节序):低字节内容存在高地址,高字节内容存在低地址。
* 小端模式(小端字节序):低字节内容存在低地址,高字节内容存在高地址。
*/
char if_big_endian(){
short endian = 1;
if( endian&0x01 == 1 ){
return 0;
}else {
return 1;
}
}
void print_byte( char*data){
for( int i=7;i>=0;i--){
printf("%d",((*data)>>i)&0x01);
}
}
void print_data( char *data, int byte_len){
for(int i=0;i<byte_len;i++){
if( if_big_endian() ){
print_byte(data+i) ;
} else {
print_byte(data+ byte_len -1 -i) ;
}
}
printf("\r\n");
}
void set_bit(char * data,int byte_len,int idx){
int byte_idx = idx/8;
int bit_idx = idx%8;
if( !if_big_endian() ){
*(data+byte_idx) |= 0x01 << bit_idx;
} else {
*(data+ byte_len -1 -byte_idx) |= 0x01 << bit_idx;
}
}
void reset_bit(char * data,int byte_len,int idx ){
int byte_idx = idx/8;
int bit_idx = idx%8;
if( !if_big_endian() ){
*(data+byte_idx) &= ~(0x01 << bit_idx);
} else {
*(data+ byte_len -1 -byte_idx) &= ~(0x01 << bit_idx);
}
}
int main(){
float num1 = 1;
char * p1 = ( char*)&num1;
printf("float 1: ");
print_data(p1,4);
float num2 = -1;
char * p2 = ( char*)&num2;
printf("float -1: ");
print_data(p2,4);
return 0;
}
- 数符: 0表示正数、1表示负数
- 数字1,阶码的真值为0,移码为0+127 = 127 = 01111111b
- 尾码为0
参考
https://blog.csdn.net/weixin_45863060/article/details/125054244