文章目录
- 小数表示
- 练习1
- 练习2
 
- IEEE浮点表示
- 数字示例
- 练习1
- 练习2
- 练习3
 
- 舍人
- 练习1
- 练习2
- 练习3
 
- 浮点运算
- C语言中的浮点数
- 练习1
- 练习2
 
浮点数对形如 V = x ∗ 2 y V=x*2^y V=x∗2y的有理数进行编码。它对表示非常大的数( ∣ V ∣ > > 0 |V|>>0 ∣V∣>>0)、非常接近
0的数(
   
    
     
      
       ∣
      
      
       V
      
      
       ∣
      
      
       <
      
      
       <
      
      
       1
      
     
     
      |V|<<1
     
    
   ∣V∣<<1),以及实数的
近似运算是很有用的。
 
小数表示
十进制表示小数:
 
     
      
       
        
         
         
          
           
            
             
              d
             
             
              m
             
            
            
             
              d
             
             
              
               m
              
              
               −
              
              
               1
              
             
            
            
             .
            
            
             .
            
            
             .
            
            
             
              d
             
             
              1
             
            
            
             
              d
             
             
              0
             
            
            
             .
            
            
             
              d
             
             
              
               −
              
              
               1
              
             
            
            
             
              d
             
             
              
               −
              
              
               2
              
             
            
            
             .
            
            
             .
            
            
             .
            
            
             
              d
             
             
              
               −
              
              
               n
              
             
            
           
          
         
         
         
        
       
       
         \begin{align} d_md_{m-1}...d_1d_0.d_{-1}d_{-2}...d_{-n} \end{align} 
       
      
     dmdm−1...d1d0.d−1d−2...d−n
 其中每个十进制数字
    
     
      
       
        
         d
        
        
         i
        
       
      
      
       d_i
      
     
    di的取值范围是0 ~ 9,这个表达式所表示的值为:
 
     
      
       
        
         
         
          
           
            
             d
            
            
             =
            
            
             
              ∑
             
             
              
               i
              
              
               =
              
              
               −
              
              
               n
              
             
             
              m
             
            
            
             1
            
            
             
              0
             
             
              i
             
            
            
             ∗
            
            
             
              d
             
             
              i
             
            
           
          
         
         
         
        
       
       
         \begin{align} d=\sum_{i=-n}^{m}10^i*d_i \end{align} 
       
      
     d=i=−n∑m10i∗di
 小数点左边的数字表示正幂,得到整数值;小数点右边的数字表示负幂,得到小数值。
 小数点向左移动1位表示d被10除;小数点向右移动1位表示d乘以10。
类似地,二进制表示小数:
 
     
      
       
        
         
         
          
           
            
             
              b
             
             
              m
             
            
            
             
              b
             
             
              
               m
              
              
               −
              
              
               1
              
             
            
            
             .
            
            
             .
            
            
             .
            
            
             
              b
             
             
              1
             
            
            
             
              b
             
             
              0
             
            
            
             .
            
            
             
              b
             
             
              
               −
              
              
               1
              
             
            
            
             
              b
             
             
              
               −
              
              
               2
              
             
            
            
             .
            
            
             .
            
            
             .
            
            
             
              b
             
             
              
               −
              
              
               n
              
             
            
           
          
         
         
         
        
       
       
         \begin{align} b_mb_{m-1}...b_1b_0.b_{-1}b_{-2}...b_{-n} \end{align} 
       
      
     bmbm−1...b1b0.b−1b−2...b−n
 其中每个二进制数字(比特位)
    
     
      
       
        
         b
        
        
         i
        
       
      
      
       b_i
      
     
    bi的取值是0或1,这个表达式所表示的值为:
 
     
      
       
        
         
         
          
           
            
             b
            
            
             =
            
            
             
              ∑
             
             
              
               i
              
              
               =
              
              
               −
              
              
               n
              
             
             
              m
             
            
            
             
              2
             
             
              i
             
            
            
             ∗
            
            
             
              b
             
             
              i
             
            
           
          
         
         
         
        
       
       
         \begin{align} b=\sum_{i=-n}^{m}2^i*b_i \end{align} 
       
      
     b=i=−n∑m2i∗bi
 同理,小数点左边的数字表示正幂,得到整数值;小数点右边的数字表示负幂,得到小数值。
 小数点向左移动1位表示b被2除;小数点向右移动1位表示b乘以2。
形如 0.11... 1 2 0.11...1_2 0.11...12的二进制数表示无限接近
1的数。用 1.0 − ε 1.0 - \varepsilon 1.0−ε表示。
仅使用有限长度的编码,十进制表示法不能表示像 1 3 、 5 7 \frac{1}{3}、\frac{5}{7} 31、75这样的数,它只能表示那些能够被写成 x ∗ 1 0 y x*10^y x∗10y这样的数。同理,有限长度的二进制编码,只能表示那些能够被写成 x ∗ 2 y x*2^y x∗2y这样的数。其它的数只能被近似地表示,增加编码的长度可以提升精度。
练习1
填写下表中缺失的信息。
| 小数值 | 二进制表示 | 十进制表示 | 
|---|---|---|
| 1 8 \frac{1}{8} 81 | 0.001 | 0.125 | 
| 3 4 \frac{3}{4} 43 | 0.11 | 0.75 | 
| 25 16 \frac{25}{16} 1625 | 1.1001 | 1.5625 | 
| 42 16 \frac{42}{16} 1642 | 10.1011 | 2.6875 | 
| 9 8 \frac{9}{8} 89 | 1.001 | 1.125 | 
| 47 8 \frac{47}{8} 847 | 101.111 | 5.875 | 
| 55 16 \frac{55}{16} 1655 | 11.0011 | 3.1875 | 
练习2
十进制数0.1的二进制表示是一个无穷序列:
 
     
      
       
        
         
         
          
           
            
             0.000110011
            
            
             [
            
            
             0011
            
            
             ]
            
            
             .
            
            
             .
            
            
             
              .
             
             
              2
             
            
           
          
         
         
         
        
       
       
         \begin{align} 0.000110011[0011]..._2 \end{align} 
       
      
     0.000110011[0011]...2
 方括号里面的部分是无限重复的。
某系统内含一个时钟,类似一个计数器,每0.1秒加1。有一个变量x,该变量用24位二进制编码十进制数0.1,x = 0.00011001100110011001100。程序用x乘以这个计数器的值,来以秒为单位确定时间。
- 0.1 - x的二进制表示是什么?
 是 0.000000000000000000000001100 [ 1100 ] . . . 2 0.000000000000000000000001100[1100]..._2 0.000000000000000000000001100[1100]...2
- 0.1 - x的近似的十进制值是多少?
 可以观察到,- 0.1的二进制表示可以写成 0.0001100 [ 1100 ] . . . 2 0.0001100[1100]..._2 0.0001100[1100]...2,
 因此- 0.1 - x的近似值为 0.1 ∗ 2 − 20 0.1*2^{-20} 0.1∗2−20
- 计数器从0开始计数,实际时间100小时以后,程序计算出的时间和实际时间相差多少?
 实际时间100小时以后,计数器的值为:100 * 3600 * 10 = 3600000。
 因此,程序计算出的时间和实际时间相差: 3600000 ∗ 0.1 ∗ 2 − 20 = 0.343 3600000 * 0.1 * 2^{-20} = 0.343 3600000∗0.1∗2−20=0.343秒。
- 假设导弹的速率为2000米每秒,系统对导弹的位置预测偏差了多少?
 2000 * 0.343 = 687米。
IEEE浮点表示
前面谈到的定点表示法不能很有效地表示非常大的数。IEEE浮点标准用
    
     
      
       
        V
       
       
        =
       
       
        (
       
       
        −
       
       
        1
       
       
        
         )
        
        
         s
        
       
       
        ∗
       
       
        M
       
       
        ∗
       
       
        
         2
        
        
         E
        
       
      
      
       V=(-1)^s*M*2^E
      
     
    V=(−1)s∗M∗2E的形式表示一个数。
- 符号:s = 1表示负数,s = 0表示正数。
- 尾数:M是一个二进制小数,它的范围是 [ 1 , 2 − ε ] [1,2-\varepsilon] [1,2−ε],或者 [ 0 , 1 − ε ] [0, 1-\varepsilon] [0,1−ε]。 ε \varepsilon ε是很小的接近于0的正数。
- 阶数:E的作用是对浮点数加权,这个权重是2的E次幂(E可能是负数)。
将浮点数的位表示划分为三个部分,分别对这些值进行编码:
- 对符号位s的编码,占一个bit。
- k位的阶码字段 e x p = e k − 1 . . . e 1 e 0 exp=e_{k-1}...e_1e_0 exp=ek−1...e1e0编码阶数- E。
- n位的小数码字段 f r a c = f n − 1 . . . f 1 f 0 frac=f_{n-1}...f_1f_0 frac=fn−1...f1f0编码尾数- M。
注意数与码的区别和联系。码是数的二进制表示,码和数之间有一定的转换关系,这种关系是相关标准定义的。 数 → 码 数 \to 码 数→码是编码, 码 → 数 码 \to 数 码→数是解码。
使用阶码 e x p exp exp编码阶数E;使用小数码(或尾码) f r a c frac frac编码尾数M。
在单精度浮点格式(C语言float)中,s、exp和frac字段分别是1位、k = 8位和n = 23位,得到一个32位的表示。
 
 在双精度浮点格式(C语言double)中,s、exp和frac字段分别是1位、k = 11位和n = 52位,得到一个64位的表示。
 
 给定表示,根据exp的值,被编码的值可以分成3种不同的情况:
情况1:规格化的值。
 exp字段既不是全0也不是全1。
阶码字段被解释为以偏置量形式表示的有符号整数。阶数E的值是E = exp - bias,其中exp是无符号数,bias等于
    
     
      
       
        
         2
        
        
         
          k
         
         
          −
         
         
          1
         
        
       
       
        −
       
       
        1
       
      
      
       2^{k-1}-1
      
     
    2k−1−1(对于单精度bias = 127,对于双精度bias = 1023)。由此产生E的取值范围,对于单精度是-126 ~ +127,对于双精度是-1022 ~ +1023。
 小数码字段frac描述小数值f,其中
    
     
      
       
        0
       
       
        ≤
       
       
        f
       
       
        <
       
       
        1
       
      
      
       0\le f <1
      
     
    0≤f<1,其二进制表示为
    
     
      
       
        0.
       
       
        
         f
        
        
         
          n
         
         
          −
         
         
          1
         
        
       
       
        .
       
       
        .
       
       
        .
       
       
        
         f
        
        
         1
        
       
       
        
         f
        
        
         0
        
       
      
      
       0.f_{n-1}...f_1f_0
      
     
    0.fn−1...f1f0。尾数M定义为M = 1 + f。
情况2:非规格化的值
 exp字段是全0。
 阶数E = 1 - bias,尾数M = f。
定义阶数为
1 - bias提供了一种从非规格化值平滑转换到规格化值的方法。
非规格化数有两个用途:
 1)表示数值0。符号位是0,阶码字段是0,小数码字段是0,表示+0.0;符号位是1,阶码字段是0,小数码字段是0,表示-0.0。值+0.0和-0.0在某些方面被认为是不同的,有些方面是相同的。
 2)表示非常接近0.0的数。通过逐渐溢出,可能的数值分布均匀地接近于0.0。
情况3:特殊值
 exp字段是全1。
 无穷大: frac字段是全0。当s = 0时是
    
     
      
       
        +
       
       
        ∞
       
      
      
       +\infty
      
     
    +∞,当s = 1时是
    
     
      
       
        −
       
       
        ∞
       
      
      
       -\infty
      
     
    −∞。无穷值表示计算溢出的结果,如两个很大的数相乘、除以零。
 NaN:frac字段不全是0。当一些运算的结果不能是实数或者无穷时,结果就是NaN。如
    
     
      
       
        
         
          −
         
         
          1
         
        
       
      
      
       \sqrt{-1}
      
     
    −1、
    
     
      
       
        ∞
       
       
        −
       
       
        ∞
       
      
      
       \infty - \infty
      
     
    ∞−∞。
NaN的意思是Not a Number。
数字示例
已知一种6位浮点格式:1位的符号位,k = 3位的阶码和n = 2位的小数码,偏置量
    
     
      
       
        
         2
        
        
         
          k
         
         
          −
         
         
          1
         
        
       
       
        −
       
       
        1
       
       
        =
       
       
        3
       
      
      
       2^{k-1}-1=3
      
     
    2k−1−1=3。
 下图展示了该浮点格式可表示的数的分布。规格化数值的最大绝对值是
    
     
      
       
        (
       
       
        1
       
       
        +
       
       
        
         2
        
        
         
          −
         
         
          1
         
        
       
       
        +
       
       
        
         2
        
        
         
          −
         
         
          2
         
        
       
       
        )
       
       
        ∗
       
       
        
         2
        
        
         
          6
         
         
          −
         
         
          3
         
        
       
       
        =
       
       
        14
       
      
      
       (1+2^{-1}+2^{-2})*2^{6-3}=14
      
     
    (1+2−1+2−2)∗26−3=14,规格化数值的最小绝对值是
    
     
      
       
        1
       
       
        ∗
       
       
        
         2
        
        
         
          1
         
         
          −
         
         
          3
         
        
       
       
        =
       
       
        0.25
       
      
      
       1*2^{1-3}=0.25
      
     
    1∗21−3=0.25。非规格化数聚集在0附近,+0.0和-0.0是特殊的非规格化数。那些可表示的数并不是均匀分布的,越靠近0越稠密。
 
 [-14, -0.25]和[0.25, 14]之间是规格化数,(-0.25, 0.25)之间是非规格化数。如果要表示绝对值大于14的数,就会溢出到
    
     
      
       
        ∞
       
      
      
       \infty
      
     
    ∞。
已知一种8位浮点格式:1位的符号位,k = 4位的阶码和n = 3位的小数码,偏置量
    
     
      
       
        
         2
        
        
         
          k
         
         
          −
         
         
          1
         
        
       
       
        −
       
       
        1
       
       
        =
       
       
        7
       
      
      
       2^{k-1}-1=7
      
     
    2k−1−1=7。下表所示它能表示的数值:
| 描述 | 位表示 | 指数 | 小数 | 值 | |||||
| e | E | 2^E | f | M | M*2^E | V | 十进制 | ||
| 0 | 0 0000 000 | 0 | -6 | 1/64 | 0 | 0 | 0 | 0 | 0.0 | 
| 最小的非零的 非规格化数 | 0 0000 001 | 0 | -6 | 1/64 | 1/8 | 1/8 | 1/512 | 1/512 | 0.001953 | 
| 0 0000 010 | 0 | -6 | 1/64 | 2/8 | 2/8 | 2/512 | 1/256 | 0.003906 | |
| 0 0000 011 | 0 | -6 | 1/64 | 3/8 | 3/8 | 3/512 | 3/512 | 0.005859 | |
| ... | |||||||||
| 最大的 非规格化数 | 0 0000 111 | 0 | -6 | 1/64 | 7/8 | 7/8 | 7/512 | 7/512 | 0.013672 | 
| 最小的 规格化数 | 0 0001 000 | 1 | -6 | 1/64 | 0 | 8/8 | 8/512 | 1/64 | 0.015625 | 
| 0 0001 001 | 1 | -6 | 1/64 | 1/8 | 9/8 | 9/512 | 9/512 | 0.017578 | |
| ... | |||||||||
| 0 0110 110 | 6 | -1 | 1/2 | 6/8 | 14/8 | 14/16 | 7/8 | 0.875 | |
| 0 0110 111 | 6 | -1 | 1/2 | 7/8 | 15/8 | 15/16 | 15/16 | 0.9375 | |
| 1 | 0 0111 000 | 7 | 0 | 1 | 0/8 | 8/8 | 8/8 | 1 | 1.0 | 
| 0 0111 001 | 7 | 0 | 1 | 1/8 | 9/8 | 9/8 | 9/8 | 1.125 | |
| 0 0111 010 | 7 | 0 | 1 | 2/8 | 10/8 | 10/8 | 5/4 | 1.25 | |
| ... | |||||||||
| 0 1110 110 | 14 | 7 | 128 | 6/8 | 14/8 | 1792/8 | 224 | 224.0 | |
| 最大的 规格化数 | 0 1110 111 | 14 | 7 | 128 | 7/8 | 15/8 | 1920/8 | 240 | 240.0 | 
| 无穷大 | 0 1111 000 | — | — | — | — | — | — | +∞ | — | 
可以观察到最大的非规格化数
    
     
      
       
        
         7
        
        
         512
        
       
      
      
       \frac{7}{512}
      
     
    5127和最小的规格化数
    
     
      
       
        
         8
        
        
         512
        
       
      
      
       \frac{8}{512}
      
     
    5128之间是平滑过渡的。
 当要表示的数值超过最大的规格化数的时候,会溢出到
    
     
      
       
        ∞
       
      
      
       \infty
      
     
    ∞。
如果把浮点数中的位当作无符号整数编码看待,随着浮点数的增大,无符号数也是增大的。这么设计是为了使浮点数复用整数的比较和排序函数(对负数要特殊处理)。
单精度和双精度浮点数的表示范围如下表所示。
| 描述 | e x p exp exp | f r a c frac frac | 单精度 | 双精度 | 
|---|---|---|---|---|
| 0 | 00…00 | 0…00 | 0.0 | 0.0 | 
| 最小的非零的非规格化数 | 00…00 | 0…01 | 2 − 23 ∗ 2 − 126 = 1.4 ∗ 1 0 − 45 2^{-23}*2^{-126}=1.4*10^{-45} 2−23∗2−126=1.4∗10−45 | 2 − 52 ∗ 2 − 1022 = 4.9 ∗ 1 0 − 324 2^{-52}*2^{-1022}=4.9*10^{-324} 2−52∗2−1022=4.9∗10−324 | 
| 最大的非规格化数 | 00…00 | 1…11 | ( 1 − ε ) ∗ 2 − 126 = 1.2 ∗ 1 0 − 38 (1-\varepsilon)*2^{-126}=1.2*10^{-38} (1−ε)∗2−126=1.2∗10−38 | ( 1 − ε ) ∗ 2 − 1022 = 2.2 ∗ 1 0 − 308 (1-\varepsilon)*2^{-1022}=2.2*10^{-308} (1−ε)∗2−1022=2.2∗10−308 | 
| 最小的规格化数 | 00…01 | 0…00 | 1 ∗ 2 − 126 = 1.2 ∗ 1 0 − 38 1*2^{-126}=1.2*10^{-38} 1∗2−126=1.2∗10−38 | 1 ∗ 2 − 1022 = 2.2 ∗ 1 0 − 308 1*2^{-1022}=2.2*10^{-308} 1∗2−1022=2.2∗10−308 | 
| 1 | 01…11 | 0…00 | 1 ∗ 2 0 = 1.0 1*2^{0}=1.0 1∗20=1.0 | 1 ∗ 2 0 = 1.0 1*2^{0}=1.0 1∗20=1.0 | 
| 最大的规格化数 | 11…10 | 1…11 | ( 2 − ε ) ∗ 2 127 = 3.4 ∗ 1 0 38 (2-\varepsilon)*2^{127}=3.4*10^{38} (2−ε)∗2127=3.4∗1038 | ( 2 − ε ) ∗ 2 1023 = 1.8 ∗ 1 0 308 (2-\varepsilon)*2^{1023}=1.8*10^{308} (2−ε)∗21023=1.8∗10308 | 
练习把整数值转换成浮点格式对理解浮点表示很有用。
 如十进制数12345的二进制表示为[11000000111001],写作
    
     
      
       
        1.1000000111001
       
       
        ∗
       
       
        
         2
        
        
         13
        
       
      
      
       1.1000000111001*2^{13}
      
     
    1.1000000111001∗213,用单精度(k = 8、n = 23、bias = 127)的规格化数表示该值:
 尾数部分是1.1000000111001,去掉整数部分的1,再在低位补充0,得到小数码为[10000001110010000000000]。
 指数是13,加上偏置量,得到140,再在高位补充0,得到阶码为[10001100]。
 再加上符号位0,最终得到结果[0 10001100 10000001110010000000000]。
 可以看到,无符号编码结果除了最高位的1,其余均作为了浮点格式的小数码部分。
练习1
假设有一种基于IEEE浮点格式的5位浮点表示:1个符号位、k = 2个阶码位、n = 2个小数码位,偏置量bias = 1。
 e:假定阶码字段是一个无符号整数所表示的值。
 E:阶数。
 
    
     
      
       
        
         2
        
        
         E
        
       
      
      
       2^E
      
     
    2E:阶码的权重。
 f:小数码字段表示的值。
 M:尾数。
 
    
     
      
       
        M
       
       
        ∗
       
       
        
         2
        
        
         E
        
       
      
      
       M*2^E
      
     
    M∗2E:未归约的数值。
 V:归约后的数值。
 十进制:该数的十进制表示。
 填写下表中的空白项。
| 位 | e | E | 2 E 2^E 2E | f | M | M ∗ 2 E M*2^E M∗2E | V | 十进制 | 
|---|---|---|---|---|---|---|---|---|
| 0 00 00 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0.0 | 
| 0 00 01 | 0 | 0 | 1 | 1 4 \frac{1}{4} 41 | 1 4 \frac{1}{4} 41 | 1 4 \frac{1}{4} 41 | 1 4 \frac{1}{4} 41 | 0.25 | 
| 0 00 10 | 0 | 0 | 1 | 1 2 \frac{1}{2} 21 | 1 2 \frac{1}{2} 21 | 1 2 \frac{1}{2} 21 | 1 2 \frac{1}{2} 21 | 0.5 | 
| 0 00 11 | 0 | 0 | 1 | 3 4 \frac{3}{4} 43 | 3 4 \frac{3}{4} 43 | 3 4 \frac{3}{4} 43 | 3 4 \frac{3}{4} 43 | 0.75 | 
| 0 01 00 | 1 | 0 | 1 | 0 | 4 4 \frac{4}{4} 44 | 4 4 \frac{4}{4} 44 | 4 4 \frac{4}{4} 44 | 1.0 | 
| 0 01 01 | 1 | 0 | 1 | 1 4 \frac{1}{4} 41 | 5 4 \frac{5}{4} 45 | 5 4 \frac{5}{4} 45 | 5 4 \frac{5}{4} 45 | 1.25 | 
| 0 01 10 | 1 | 0 | 1 | 1 2 \frac{1}{2} 21 | 3 2 \frac{3}{2} 23 | 3 2 \frac{3}{2} 23 | 3 2 \frac{3}{2} 23 | 1.5 | 
| 0 01 11 | 1 | 0 | 1 | 3 4 \frac{3}{4} 43 | 7 4 \frac{7}{4} 47 | 7 4 \frac{7}{4} 47 | 7 4 \frac{7}{4} 47 | 1.75 | 
| 0 10 00 | 2 | 1 | 2 | 0 | 1 | 2 | 2 | 2.0 | 
| 0 10 01 | 2 | 1 | 2 | 1 4 \frac{1}{4} 41 | 5 4 \frac{5}{4} 45 | 10 4 \frac{10}{4} 410 | 5 2 \frac{5}{2} 25 | 2.5 | 
| 0 10 10 | 2 | 1 | 2 | 1 2 \frac{1}{2} 21 | 3 2 \frac{3}{2} 23 | 6 2 \frac{6}{2} 26 | 3 | 3.0 | 
| 0 10 11 | 2 | 1 | 2 | 3 4 \frac{3}{4} 43 | 7 4 \frac{7}{4} 47 | 14 4 \frac{14}{4} 414 | 7 2 \frac{7}{2} 27 | 3.5 | 
| 0 11 00 | - | - | - | - | - | - | ∞ \infty ∞ | - | 
| 0 11 01 | - | - | - | - | - | - | NaN | - | 
| 0 11 10 | - | - | - | - | - | - | NaN | - | 
| 0 11 11 | - | - | - | - | - | - | NaN | - | 
练习2
整数3510593的十六进制表示为0x00359141,单精度浮点数3510593.0的十六进制表示为0x4A564504。推导出这个浮点表示,并解释整数和浮点数表示之间的关系。
单精度浮点数的阶码有k = 8位,小数码有n = 23位,偏置量是127。
 整数3510593的二进制表示为0000 0000 0011 0101 1001 0001 0100 0001,写作
    
     
      
       
        1.101011001000101000001
       
       
        ∗
       
       
        
         2
        
        
         21
        
       
      
      
       1.1 0101 1001 0001 0100 0001 *2^{21}
      
     
    1.101011001000101000001∗221。以单精度规格化数的表示方式,该数的小数码是1 0101 1001 0001 0100 0001 00。阶码是21 + 127 = 148的无符号二进制表示,即1001 0100。符号位是0。
因此单精度浮点数3510593.0的二进制表示为0 1001 0100 1 0101 1001 0001 0100 0001 00,即0100 1010 0101 0110 0100 0101 0000 0100,十六进制表示为0x4A564504。
整数的二进制表示中,除了最高位的1,其余部分与浮点数的小数码的有效位一一对应。
练习3
- 对于一种具有n位小数的浮点格式,给出不能准确描述的最小正整数的公式。假设阶码字段k足够大。
 正整数肯定是规格化数。
 n + 1位小数能表示的最小的小数码是0...01,1前面n个0,因此尾数 M = 1 + 2 − ( n + 1 ) M=1+2^{-(n+1)} M=1+2−(n+1),以此为尾数的最小正整数是 ( 1 + 2 − ( n + 1 ) ) ∗ 2 ( n + 1 ) = 2 ( n + 1 ) + 1 (1+2^{-(n+1)})*2^{(n+1)}=2^{(n+1)}+1 (1+2−(n+1))∗2(n+1)=2(n+1)+1。
- 对于单精度格式k = 23,这个整数的数值是多少?
 2 ( n + 1 ) + 1 = 2 ( 23 + 1 ) + 1 = 16 , 777 , 217 2^{(n+1)}+1=2^{(23+1)}+1=16,777,217 2(n+1)+1=2(23+1)+1=16,777,217。
舍人
因为表示方法限制了浮点数的范围和精度,所以浮点运算只能近似地表示实数运算。因此,对于值x,我们期待能够找到与它“最接近”的能用浮点形式表示的匹配值
    
     
      
       
        
         x
        
        
         ′
        
       
      
      
       x'
      
     
    x′,这就是舍入运算的任务。
IEEE浮点格式定义了4种不同的舍入方式:向偶数舍入,向零舍入,向下舍入,向上舍入。
 向偶数舍入也被称为向最接近的值舍入,是默认的方式。如果某个值距离向上舍入值和向下舍入值相等,它将向上或者向下舍入,使得结果的最低有效位数字是偶数。
 向零舍入把正数向下舍入,负数向上舍入。向下舍入得到
    
     
      
       
        
         x
        
        
         −
        
       
      
      
       x^-
      
     
    x−。向上舍入得到
    
     
      
       
        
         x
        
        
         +
        
       
      
      
       x^+
      
     
    x+。
| 方式 | 1.40 | 1.60 | 1.50 | 2.50 | -1.50 | 
|---|---|---|---|---|---|
| 向偶数舍入 | 1 | 2 | 2 | 2 | -2 | 
| 向零舍入 | 1 | 1 | 1 | 2 | -1 | 
| 向下舍入 | 1 | 1 | 1 | 2 | -2 | 
| 向上舍入 | 2 | 2 | 2 | 3 | -1 | 
相比于其他
3种舍入方式,向偶数舍入可以优化对大量数据的统计偏差:当某些值距离其向上舍入值和向下舍入值相等,理论上会有50%的数据向上舍入,50%的数据向下舍入。
练习1
将下列2进制小数舍入到最接近的二分之一(小数点后一位)。
- 
     
      
       
        
         10.01
        
        
         
          0
         
         
          2
         
        
       
       
        10.010_2
       
      
     10.0102
 10. 0 2 10.0_2 10.02
- 
     
      
       
        
         10.01
        
        
         
          1
         
         
          2
         
        
       
       
        10.011_2
       
      
     10.0112
 10. 1 2 10.1_2 10.12
- 
     
      
       
        
         10.11
        
        
         
          0
         
         
          2
         
        
       
       
        10.110_2
       
      
     10.1102
 11. 0 2 11.0_2 11.02
- 
     
      
       
        
         11.00
        
        
         
          1
         
         
          2
         
        
       
       
        11.001_2
       
      
     11.0012
 11. 0 2 11.0_2 11.02
练习2
飞毛腿导弹软件把0.1的近似表示为
    
     
      
       
        0.0001100110011001100110
       
       
        
         0
        
        
         2
        
       
      
      
       0.00011001100110011001100_2
      
     
    0.000110011001100110011002,假设使用IEEE舍入到偶数方式来确定0.1的二进制小数点右边23位的近似表示
    
     
      
       
        
         x
        
        
         ′
        
       
      
      
       x'
      
     
    x′。
- 
     
      
       
        
         
          x
         
         
          ′
         
        
       
       
        x'
       
      
     x′的二进制表示是什么?
 0.0001100110011001100110 1 2 0.00011001100110011001101_2 0.000110011001100110011012
- 
     
      
       
        
         
          x
         
         
          ′
         
        
        
         −
        
        
         0.1
        
       
       
        x'-0.1
       
      
     x′−0.1的十进制表示的近似值是什么?
 0.1的二进制表示是 0.0001100 [ 1100 ] . . . 2 0.0001100[1100]..._2 0.0001100[1100]...2,因此 x ′ − 0.1 x'-0.1 x′−0.1的二进制表示是 0.00000000000000000000000001100 [ 1100 ] 2 0.00000000000000000000000001100[1100]_2 0.00000000000000000000000001100[1100]2,其值为 0.1 ∗ 2 − 22 0.1*2^{-22} 0.1∗2−22。
- 运行100小时后,计算时钟会有多少偏差?
 100 ∗ 3600 ∗ 10 ∗ 0.1 ∗ 2 − 22 = 0.0858306884765625 100 * 3600 * 10 *0.1*2^{-22}=0.0858306884765625 100∗3600∗10∗0.1∗2−22=0.0858306884765625秒
- 该程序对导弹位置的预测有多大偏差?
 0.0858306884765625 ∗ 2000 = 171.661376953125 0.0858306884765625*2000=171.661376953125 0.0858306884765625∗2000=171.661376953125米
练习3
考虑下列基于IEEE浮点格式的7位浮点表示,均没有符号位。
- 格式A
 有k=3个阶码位,阶码的偏置量是3。
 有n=4个小数位。
- 格式B
 有k=4个阶码位,阶码的偏置量是7。
 有n=3个小数位。
填写下表,必要时使用向偶数舍入的原则。
| 格式A | 格式B | ||
| 位 | 值 | 位 | 值 | 
| 011 0000 | 1 | 0111 000 | 1 | 
| 101 1110 | 15/2 | 1001 111 | 15/2 | 
| 010 1001 | 25/32 | 0110 100 | 3/4 | 
| 110 1111 | 31/2 | 1011 000 | 16 | 
| 000 0001 | 1/64 | 0001 000 | 1/64 | 
浮点运算
对于实数x和y,我们定义
    
     
      
       
        x
       
       
        
         +
        
        
         f
        
       
       
        y
       
       
        =
       
       
        R
       
       
        o
       
       
        u
       
       
        n
       
       
        d
       
       
        (
       
       
        x
       
       
        +
       
       
        y
       
       
        )
       
      
      
       x+^fy=Round(x+y)
      
     
    x+fy=Round(x+y),Round是舍入的意思。
 大多数值在浮点加法下都有逆元:
    
     
      
       
        x
       
       
        
         +
        
        
         f
        
       
       
        −
       
       
        x
       
       
        =
       
       
        0
       
      
      
       x+^f-x=0
      
     
    x+f−x=0。浮点加法满足交换律,
    
     
      
       
        x
       
       
        
         +
        
        
         f
        
       
       
        y
       
       
        =
       
       
        y
       
       
        
         +
        
        
         f
        
       
       
        x
       
      
      
       x+^fy=y+^fx
      
     
    x+fy=y+fx;但不满足结合律,
    
     
      
       
        (
       
       
        3.14
       
       
        +
       
       
        1
       
       
        e
       
       
        10
       
       
        )
       
       
        −
       
       
        1
       
       
        e
       
       
        10
       
       
        =
       
       
        0
       
      
      
       (3.14+1e10)-1e10=0
      
     
    (3.14+1e10)−1e10=0但
    
     
      
       
        3.14
       
       
        +
       
       
        (
       
       
        1
       
       
        e
       
       
        10
       
       
        −
       
       
        1
       
       
        e
       
       
        10
       
       
        )
       
       
        =
       
       
        3.14
       
      
      
       3.14+(1e10-1e10)=3.14
      
     
    3.14+(1e10−1e10)=3.14。浮点加法满足单调性:对于任何的a、b、x(除了NaN),如果
    
     
      
       
        a
       
       
        ≥
       
       
        b
       
      
      
       a\ge b
      
     
    a≥b,那么
    
     
      
       
        a
       
       
        +
       
       
        x
       
       
        ≥
       
       
        b
       
       
        +
       
       
        x
       
      
      
       a+x\ge b+x
      
     
    a+x≥b+x,无符号和补码加法没有这个属性。
浮点乘法满足交换律、单调性;不满足结合律、分配律。
编译器优化代码时,倾向于保守,避免任何对功能产生影响的优化,即使是很轻微的影响。
C语言中的浮点数
所有的C语言版本提供了2种不同的浮点数据类型:单精度的float、双精度的double。使用向偶数舍入的舍入方式。
C语言标准不要求机器使用IEEE浮点,所以没有标准的方法改变舍入方式,得到-0、无穷大值、NaN之类的特殊值。GNU编译器GCC在头文件math.h里定义了程序常数INFINITY表示
    
     
      
       
        +
       
       
        ∞
       
      
      
       +\infty
      
     
    +∞,定义了NaN表示非数值。
双精度所能表示的最大的有限数,大约是 1.8 ∗ 1 0 308 1.8*10^{308} 1.8∗10308。
当在int(4字节)、float(4字节)、double(8字节)格式之间进行强制类型转换时,原则如下:
- 从int转换成float,不会溢出,但可能被舍入。
- 从int或float转成double,因为double有更大的表示范围和表示精度,所以能保留精确的数值。
- 从double转成float,可能被溢出,也可能被舍入。
- 从float或double转成int,值会向零舍入,也可能溢出,溢出值依系统架构而不同。
练习1
完成下列宏定义。
- #define POS_INFINITY
 #define POS_INFINITY INFINITY
- #define NEG_INFINITY
 #define NEG_INFINITY -POS_INFINITY
- #define NEG_ZERO
 #define NEG_ZERO (-1.0 / POS_INFINITY)
练习2
假定变量x、f和d的类型分别是int、float和double。除了f和d都不能等于
    
     
      
       
        −
       
       
        ∞
       
      
      
       -\infty
      
     
    −∞、
    
     
      
       
        +
       
       
        ∞
       
      
      
       +\infty
      
     
    +∞或者NaN,它们的值是任意的。对于下面的每个C表达式,证明它总是真,或者给出它为假的情况。
- x == (int)(double)x
 真。double能准确表示int。
- x == (int)(float)x
 x的有效位大于24时,结果为假。
- d == (double)(float)d
 d的小数码位大于23时,float就不能准确地表示d。
- f == (float)(double)f
 真。double能准确表示float。
- f == -(-f)
 真。只有符号位变动,没有阶码和小数码变动。
- 1.0 / 2 == 1 / 2.0
 真。都是double类型。
- d * d >= 0.0
 真。即便结果是 + ∞ +\infty +∞,只要 d ≠ N a N d\ne NaN d=NaN,就一定存在 d ∗ d > = 0.0 d * d>= 0.0 d∗d>=0.0。
- (f + d) - f == d
 左边可能溢出,表达式为假。
由于编码的长度有限,与真实的整数和实数运算相比,计算机运算具有非常不同的属性。当超出表示范围时,会引起数值的截断或溢出。



















