单精度浮点数与机器精度

1、单精度浮点数

先来简单了解一下浮点数在计算机中的存储方式。根据IEEE 754标准,单精度浮点数格式以下(全部位取0):编码

 

符号位spa

指数部分code

尾数orm

0blog

0ip

0ci

0get

0string

0it

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

 

各部分解释

单精度浮点数有32个二进制位,左侧是高位,右侧是低位。最高位被指定为符号位,0表明正数,1表明负数。指数部分将是2的幂次,其编码值(即上表指数部分对应的八个二进制位)规定为指数的实际值加上偏移值2^7-1=127,这是为了不负数,将[-127, 128]映射到[0, 255],这样指数部分编码就能够简单地编排为[00000000, 11111111]。例如指数部分为00001000,十进制为8。那么其所表明的实际指数是8-127=-119,即要乘上2-119。最后23位尾数是不包含整数位的实际有效小数位。规约数的整数位是1,非规约数的整数位是0。

 

规约形式的浮点数与非规约形式的浮点数

指数部分的编码值在[1, 2e-2]内,且尾数部分的整数位是1,这样的浮点数被称为规约形式浮点数。

指数部分的编码值为0,尾数非零,这样的浮点数被称为规约形式的浮点数。

规约浮点数的尾数∈[1, 2),而非规约浮点数的尾数∈(0, 1)。 须要注意,非规约数指数编码为00000000,但指数实际值是-126,而非-127。非规约浮点数被IEEE 754-1985标准采用是由于它的渐进式下溢出,而规约浮点数将致使忽然式下溢出,具体原理再也不展开。

 

实际计算

设符号位为s。sign(s)肯定正负:sign(0)=1,sign(1)=-1;指数部分为e;尾数部分为f。用(N)2表示二进制数N。

规约形式:sign(s)*2e-127*(1.f)2

非规约形式:sign(s)*2-126*(0.f)2

 

特殊值和极值

 

类别

符号位

指数部分

尾数

数值

正负零

0/1

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

±0

正负无穷

0/1

1

1

1

1

1

1

1

1

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

±∞

最大规约数

0/1

1

1

1

1

1

1

1

0

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

±(2−2-23) × 2127 ≈ ±3.40e38

最大非规约数

0/1

0

0

0

0

0

0

0

0

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

1

±(1−2−23) × 2-126 ≈ ±1.18e-38

最小规约数

0/1

0

0

0

0

0

0

0

1

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

±2−126 ≈ ±1.18e-38

最小非规约数

0/1

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

0

1

±2−23 × 2−126 = ±2−149 ≈ ±1.40e-45

NaN

0/1

1

1

1

1

1

1

1

1

非零

NaN

 

上下溢出值

由浮点数的存储方式能够看出计算机所能表示的浮点数是有限的,咱们把所能表示的最大正值称为上溢值,而把最接近0的正值称为下溢值。由表二咱们看到上溢值为±3.40e38,下溢值为±1.40e-45。

 

2、机器精度

Wikipedia上机器精度Machine Epsilon是这样描述的:“Machine epsilon gives an upper bound on the relative error due to rounding in floating point arithmetic”。由于浮点数是离散的,因此实数的表示存在着偏差。例如圆周率这样的无限不循环小数不可能精确地由某一个浮点数表示。

咱们须要一些具体的量去刻画这种偏差,以估计结果的准确性。机器精度即是其中之一:它是全部相对偏差的上限。相对偏差是绝对偏差与精确值的比值的绝对值。例如一个精确的实数x,全部单精度浮点数中与x距离最近的数为y,绝对偏差为|y-x|,相对偏差即\(|y-x| \over |x|\),而全部相对偏差的上限即是单精度浮点数的机器精度。

对于32位浮点数,指数8位,尾数为23位。对于两个指数实际值为E的相同的浮点数,若它们尾数部分相差(00000000000000000000001)2,即2-23,易见它们是相邻的。那么与它们指数相同的实数x与距x最近的浮点数y之间的距离|y-x|必定小于此相邻两浮点数的距离2-23 * 2E。能够取x=1.0(或者其余任何数),此时实际指数为0,因此机器精度是\(2^{-23} \times 2^{0} \over 1.0\)。

 

3、C++程序实现

利用库求值

标准库<limits>中的numeric_limits类中包含了许多算数特殊值:

  • 上溢值: std::numeric_limits<float>::max();
  • 规约下溢值: std::numeric_limits<float>::min();
  • 非规约下溢值: std::numeric_limits<float>::denorm_min();
  • 机器精度: std::numeric_limits<float>::epsilon();

其中numeric_limits<float>中float能够换成int,double等其它类型。

实际二进制存储值

std::string get_binary(float f)
{
    int index_byte, index_bit;
    unsigned int byte = 0;
    char ch, *p;
    std::string bin_f = "";
    p = (char *)(&f);
    for (index_byte = sizeof(float)-1; index_byte>=0; index_byte--) {
        ch = *(p+index_byte);    //从最高位开始取
        byte = ch;    //将地址中8个二进制位赋值成十进制数
        for (index_bit = 1; index_bit<=8; index_bit++) {
            if (byte >=128) bin_f += "1";
            else bin_f += "0";    //判断首位是1仍是0
            byte <<= 1;    //将当前位变成首位
            byte &= 255;    //确保始终8个二进制位
        }
    }
    return bin_f;
}
相关文章
相关标签/搜索