IEEE 二进制浮点数的表示

本文介绍了IEEE二进制浮点数的表示方法,包括符号、指数和尾数的概念,并通过一个具体的例子展示了如何将十进制数转换为IEEE单精度浮点数格式。

        今天,我来将 IEEE 二进制浮点数的表示方式进行一个简单的介绍。


浮点数

在 C 语言中,有两种存储浮点数的方式,分别是 float 和 double ,当然了还有long double。这几种浮点型所容纳的长度不同,当然它们存储的精度也就不同了。

对于整形而言,比如 int 、short 、char 之类的,在内存中的存储方式都是用 补码 进行表示。而浮点数在内存中并没有使用补码进行表示。浮点数在内存中存储的方式使用了 IEEE 的编码表示方式,即使用 符号指数 和 尾数 的形式进行存储的。

IEEE浮点数表示

用 IEEE 编码表示浮点数,需要 3 部分进行表示,分别是 符号、指数 和 尾数。符号位占用 1 位,0 表示正数,1 表示负数。指数 和 尾数 根据 float 和 double 类型的不同而长度不同。

IEEE 二进制浮点数的表示:

位数  符号位  指数位  尾数位
32     1       8         23     单精度(float)
64     1       11        52     双精度(double)

编码转换

以单精度为例:把 3.75 用 IEEE 表示法表示

1、把 10 进制转换为 2 进制:

3.75D = 11.11B

2、 尾数正规化

1.111 * 2 ^ 1

3、 修正指数

1 + 127 = 128 1000 0000

4、 符号

0 表示正,1 表示负

5、 IEEE表示

0 1000 0000 1110 0000 0000 0000 0000 000
(0)    (1000 0000) (1110 0000 0000 0000 0000 000)
符号位  指数        尾数 

6、 转换为16进制: 

0100 0000 0111 0000 0000 0000 0000 0000  
   4    0    7    0    0    0    0    0 

用 C 程序进行验证

  写一个简单的 C 程序来验证上面的转换,代码如下:

#include <stdio.h>

int main()
{
    float f = 3.75f;

    printf("%f \r\n", f);

    return 0;
}

以上代码用 VS 2015 编译,调试运行查看内存,如下图所示。

图中的 00 00 70 40 是以小尾方式存储的,其值为 40 70 00 00,与我们手动转换的值相同。关于小尾和大尾存储方式就是另外的话题了,这里就不再讨论。

关于 double 的存储方式与之类似,这里也就不进行介绍了。

二进制浮点数有多种表示方法,包括半精度、单精度、双精度浮点数等,还有基于IEEE745标准的32浮点数表示法,以及一般的二进制表示浮点数方法。 在一般的二进制表示浮点数中,以0为原点向左移是2的整数次幂,向右移是逐级除2 ,类似8 4 2 1 0 0.5 0.25 0.125 … ,例如0.625的二进制码是(0.101)。可以使用消1法来将浮点数转换为二进制,即把输入的浮点数2;如果大于1,就减去1,且在小数点后一次输出一个1;如果小于1,则不减,在小数点后一次输出一个0。不过,二进制表示浮点数有限,像0.3就无法精确表述,如果运算超过一定次数就输出ERROR返回 [^2]。 IEEE745制的32浮点数由三部分组成:符号位1位,0为正,1为负;指数2 - 9位,类比十进制的科学计数法,此处以2为底,指数位为幂,还需要加上127的偏移量;尾数位10 - 32位,省略了1,实际为1.(尾数位),类似小数的二进制写法 [^4]。 float和double类型的浮点数在内存中按科学计数法存储,其整数部分始终隐含着“1”。float类型为1bit(符号位)+8bits(指数位)+23bits(尾数位),精度为6 - 7位有效数字;double类型为1bit(符号位)+ 11bits(指数位)+ 52bits(尾数位),精度为15 - 16位有效数字 [^5]。 以下是一个十进制浮点数二进制浮点数的算法代码示例: ```c #include <stdio.h> #include <math.h> void float10to2(float val) { char res[128]; // 存储二进制数据的字符数组 int startPos = 0; // 二进制数据在数组开始的位置 float absVal = fabsf(val); // 获取绝对值 int intP = floor(absVal); // 获取整数部分 float floatP = absVal - intP; // 获取小数部分 int index = 63; // 初始数组的位置 // 获取整数部分二进制数据 while (true) { res[index--] = intP % 2 == 0 ? '0' : '1'; intP /= 2; if (intP == 0) { break; } } // 获取符号 if (val < 0) { startPos = index; res[startPos] = '-'; } else { startPos = index + 1; } // 添加小数点 res[64] = '.'; index = 65; int eVal = 0; intP = floor(absVal); // 获取小数部分 while (floatP != 0 && index < 127) { floatP *= 2; if (floatP >= 1) { res[index++] = '1'; floatP -= 1; } else { if (intP > 0 || index > 65) { res[index++] = '0'; } else { eVal--; } } } res[index] = '\0'; printf("result = %s", res + startPos); if (eVal < 0) { printf(" * 2^%d\n", eVal); } else { printf("\n"); } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农UP2U

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值