1 浮点数的一般表示

J f J_f Jf J 1 J 2 … J m J_1J_2\dots J_m J1J2Jm S f S_f Sf S 1 S 2 … S n S_1S_2\dots S_n S1S2Sn
阶符阶码数符尾数

阶码的位数决定了浮点数的表示范围的大小,尾数的位数决定了浮点数的表示精度

  • 阶符:阶码的符号位。1为负;0为正
  • 阶码:即幂的大小。设幂 e = ( J 1 J 2 … J m ) 2 e=(J_1J_2\dots J_m)_2 e=(J1J2Jm)2
  • 数符:尾数的符号位。1为负;0为正
  • 尾数:尾数的大小。设尾数 M = ( S 1 S 2 … S n ) 2 M=(S_1S_2\dots S_n)_2 M=(S1S2Sn)2

一般基数 r = 2 r=2 r=2,则浮点数真值 N = ( − 1 ) J f ∗ r e ∗ ( − 1 ) S f ∗ M N=(-1)^{J_f}*r^e*(-1)^{S_f}*M N=(1)Jfre(1)SfM

2 IEEE 754标准的浮点数

2.1 浮点数的格式

m s m_s ms E E E M M M
数符阶码,用移码表示尾数,用原码表示
类型数符阶码尾数总位数阶码偏置值(十进制)指数范围(真值表示)指数范围(移码表示)
短浮点数182332127[-126,+127][+1,+254]
长浮点数11152641023[-1022,+1023][+1,+2046]
临时浮点数115648016383[-16382,+16383][+1,+32766]

从上表可以看出,IEEE 754标准的浮点数有短浮点数(单精度、float型)、长浮点数(双精度、double型)、临时浮点数三种,且数据由三部分组成:

  • 数符:尾数的符号位。1表示负;0表示正
  • 阶码:表示数的幂,基为2,用移码表示
  • 尾数:表示数的小数部分,基为2,用原码表示。且隐藏了一位1,这样是为了多表示一位有效位(临时浮点数无隐含的1

因此可知,一个IEEE 754标准的浮点数的值为 N = ( − 1 ) m s ∗ 2 E ∗ ( 1. M ) 2 N=(-1)^{m_s}*2^E*(1.M)_2 N=(1)ms2E(1.M)2


两点说明

1、关于阶码

1.1、为什么用移码表示
补码不能直观的表示数据的大小,比如一个8位的数据:用补码表示 ( − 1 ) 10 = ( 11111111 ) 2 = F F H , ( 8 ) 10 = ( 00001000 ) 2 = 08 H (-1)_{10}=(11111111)_2=FFH,(8)_{10}=(00001000)_2=08H (1)10=(11111111)2=FFH(8)10=(00001000)2=08H,8是大于-1的,但是补码的话 FFH > 08H,这与实际结果正好相反;而移码通过加上一个偏置值(若数据为 n 位,则通常取偏置值为 2 n − 1 2^{n-1} 2n1,将符号位取反即可),能够反映数据之间的实际大小关系,移码表示 ( − 1 ) 10 = ( 01111111 ) 2 = 7 F H , ( 8 ) 10 = ( 10001000 ) 2 = 88 H (-1)_{10}=(01111111)_2=7FH,(8)_{10}=(10001000)_2=88H (1)10=(01111111)2=7FH(8)10=(10001000)2=88H,88H > 7FH,这与预期结果相符合

1.2、阶码的偏置值
阶码部分用移码表示,假设阶码为 n 位,则规定阶码偏置值取 2 n − 1 − 1 2^{n-1}-1 2n11,因此短浮点数、长浮点数、临时浮点数阶码偏置值为 2 8 − 1 − 1 = 127 、 2 11 − 1 − 1 = 1023 、 2 15 − 1 − 1 = 16383 2^{8-1}-1=127、2^{11-1}-1=1023、2^{15-1}-1=16383 2811=12721111=102321511=16383。移码偏置值不是 2 n − 1 2^{n-1} 2n1吗,这里为什么取 2 n − 1 − 1 2^{n-1}-1 2n11,因为阶码全1是用来表示特殊用途的数,1.3条有详细解释,不理解的话直接将这当作一个规定记住即可

1.3、阶码的取值范围
假设阶码为 n 位,则可表示的范围为 0 到 2 n − 1 0到2^{n}-1 02n1,,因此短浮点数、长浮点数的阶码取值范围为 0到255、0到2047。又因为当阶码全0、阶码全1时有特殊用途,所以阶码E的实际取值范围为 1到254、1到2046、1到32766(去掉阶码全0和全1)。当阶码E为全0或全1时,要综合考虑尾数M的值,它们用来表示一些特殊的数:

  • 0:当E全0,M为0时用来表示0值,至于是+0/-0,则取决于符号位是0还是1。
  • subnormal:当E全0,M非0时,用来表示subnormal(中文译为非规则浮点数)。它表示那些比规格化浮点数能表示的最小量级的数还小的数,例如短浮点格式的一个数 1.11 ∗ 2 − 128 1.11*2^{-128} 1.112128,这已经超出了规格化形式能表示的范围,如果变成subnormal的话就是 0.0111 ∗ 2 − 126 0.0111*2^{-126} 0.01112126,前面说到,规格化浮点数的隐含位为1,而subnormals的隐含位可以看成0,这就是非规格化的含义所在。并且subnormals的尾数部分有若干前导0组成,因为它已经超出了规格化形式的范围,一个数越小,它的前导0越多,否则指数部分就不符合要求。
  • 无穷大:当E全1,M为0时表示无穷大,至于是 + ∞ / − ∞ +\infty/-\infty +∞/,则取决于符号位是0还是1。
  • NaN(Not a Number):当E全1,M非0时,表示NaN。在IEEE浮点数格式中,NaN表示那些不是实数(real number)的值,例如 0 0 \frac{0}{0} 00。具体细分,有两类NaN,quiet NaNs(QNaNs)signaling NaNs(SNaNs),QNaNs表示一个不确定的值,例如一个数除以无穷大或者无穷大乘0的结果;SNaNs则用于无效的操作,以表示浮点硬件异常。

1.4、阶码的实际大小
阶码采用移码的形式表示,阶码的实际大小需要减去对应的偏置值,通过这种方式来表示阶码的正负值。所以短浮点数、长浮点数的阶码实际大小为 E − 偏置值 E-偏置值 E偏置值,即 1 − 127 = − 126 到 254 − 127 = 127 、 1 − 1023 = − 1022 到 2046 − 1023 = 1023 1-127=-126到254-127=127、1-1023=-1022到2046-1023=1023 1127=126254127=12711023=102220461023=1023

2、关于尾数

假设尾数位数为 m 位,因为尾数部分隐含了一位整数1,所以尾数的实际位数为 m+1 位,因此短浮点数、长浮点数尾数实际有效位数为24、53,真值为 1. M 1.M 1.M,故:

短浮点数的真值为
( − 1 ) m s ∗ ( 1. M ) ∗ 2 E − 127 (-1)^{m_s}*(1.M)*2^{E-127} (1)ms(1.M)2E127
长浮点数的真值为
( − 1 ) m s ∗ ( 1. M ) ∗ 2 E − 1023 (-1)^{m_s}*(1.M)*2^{E-1023} (1)ms(1.M)2E1023

2.2 浮点数的取值范围

以短浮点正数为例:

当阶码和尾数都取最小时(E为0000 0001,M为0),表示的数值最小,阶码部分为 1 − 127 = − 126 1-127=-126 1127=126,尾数部分为 隐含的1加上其余的23位0;

当阶码和尾数都取最大时(E为1111 11110,M全1),表示的数值最大,阶码部分为 254 − 127 = 127 254-127=127 254127=127,尾数部分为 隐含的1加上其余的23位1;

所以取值范围为 1.0 × 2 − 126 1.0\times 2^{-126} 1.0×2126 24 个 1 1.11 … 1 ⏞ × 2 127 \begin{matrix} 24个1 \\ \overbrace{ 1.11\dots 1 } \times 2^{127}\end{matrix} 2411.111 ×2127,即

格式正数负数
单精度 2 − 126 到 ( 2 − 2 − 23 ) × 2 127 2^{-126}到(2-2^{-23})\times 2^{127} 2126(2223)×2127 − 2 − 126 到 − ( 2 − 2 − 23 ) × 2 127 -2^{-126}到-(2-2^{-23})\times 2^{127} 2126(2223)×2127
双精度 2 − 1022 到 ( 2 − 2 − 52 ) × 2 1023 2^{-1022}到(2-2^{-52})\times 2^{1023} 21022(2252)×21023 − 2 − 1022 到 − ( 2 − 2 − 52 ) × 2 1023 -2^{-1022}到-(2-2^{-52})\times 2^{1023} 21022(2252)×21023

在这里插入图片描述

2.3 类型转换时的精度损失和溢出

这里以C语言为例。C语言中的float、double型分别对应IEEE 754标准的单精度和双精度浮点数,一个int型数据占4个字节、float占4字节、double占8字节。

1 溢出

  • 当float、double向int转换时可能会发生溢出,比如有符号int型表示的数据范围为 2 − 31 到 2 31 − 1 2^{-31}到2^{31}-1 2312311,而float、double类型的数据的表示范围超过了int类型
  • 当double向float、int转换时可能会发生溢出、float向int转换时也可能会溢出

2.精度损失

  • 当int向float转换时可能会产生精度损失,因为int类型共四字节32位,而float尾数的有效位数为24位(包括隐含的1),当int型数据的有效位数超过24的话就会发生精度损失。比如
    u n s i g n e d i n t m = F F F F F F F F H 即( 2 − 2 − 31 ) × 2 31 unsigned \quad int\quad m = FFFF \quad FFFFH\\ 即(2-2^{-31})\times 2^{31} unsignedintm=FFFFFFFFH即(2231)×231
    因为 m 的二进制表示为32位1,超过了float的24位,超出的1会被舍掉,所以就会产生精度损失。
  • 当double向float、int转换时可能会有精度损失,因为double类型尾数的有效位数位53,超过了float的24;而且浮点数向整数转换时,若是小数部分不为0,一定会有精度损失,因为整数没有小数部分

例: 将十进制小数转换成IEEE 754标准的浮点数

例:现有一个十进制小数43.875,请将其转换成IEEE 754类型的短浮点数(即float类型),并将最终结果用二进制或十六进制表示。

分析:
IEEE 754标准的短浮点数要符合如下几个标准

  1. 阶码用移码表示,占8位。其值为阶码真值加偏置值127
  2. 尾数用原码表示,占23位。另有一位隐含的整数1
  3. 最高位为数符,占1位。0表示正数、1表示负数

解答:
第一步 将十进制小数转换成二进制表示
一定要转换成 1.M 的形式,其中 M 为尾数, ( 43.875 ) 10 = ( 101011.111 ) 2 = ( 1.01011111 ) × 2 5 (43.875)_{10}=(101011.111)_{2}=(1.01011111)\times 2^5 (43.875)10=(101011.111)2=(1.01011111)×25

第二步 求出数符、阶码、尾数的二进制表示
由题意知:数符 m s = 0 m_s=0 ms=0
由第一步知:阶码 E = 5 = ( 101 ) 2 E=5=(101)_{2} E=5=(101)2,尾数 M = ( 01011111 ) 2 M=(01011111)_2 M=(01011111)2
因此:

  • 1位数符为 0
  • 8位阶码为(移码表示) 5 + 127 = 132 = ( 1000 0100 ) 2 5+127=132=(1000\quad 0100)_2 5+127=132=(10000100)2
  • 23位尾数为(原码表示) ( 010 1111 1000 0000 0000 0000 ) 2 (010\quad 1111\quad 1000\quad 0000\quad 0000\quad 0000)_2 (01011111000000000000000)2

第三步 整理结果

数符阶码尾数
01000 0100010 1111 1000 0000 0000 0000
43.875 = 0100 0010 0010 1111 1000 0000 0000 0000 = 422 F 8000 H 43.875=0100\quad 0010\quad 0010\quad 1111\quad 1000\quad 0000\quad 0000\quad 0000=422F\quad 8000H 43.875=01000010001011111000000000000000=422F8000H
public class Main {

    public static void main(String[] args) {
        float f = 43.875f;
        // 输出浮点数的 二进制表示
        System.out.println(Integer.toBinaryString(Float.floatToIntBits(f)));
        // 输出浮点数的 十六进制表示♑
        System.out.println(Integer.toHexString(Float.floatToIntBits(f)));
    }
}

在这里插入图片描述

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐