c++ 无穷大怎么表示_Introduction to CSAPP(六)浮点数表示

引子

有一个C程序的例子:

#include <stdio.h>

int main(){
    float a = 16777217.0f;
    if(a == 16777216.0f) // 这里判断应该为假?
        printf("value is %.10fn", a);

    if(0.1 + 0.2 == 0.3) // 这里判断应该为真?
        printf("you will see: 0.1 + 0.2 == 0.3n");

    int x = 65535;
    int y = x*x;
    printf("x * x = %dn", y); // 这里应该打印4294836225?

    x = -2147483648;
    // 这里应该打印true?
    printf("x: %d and y: %d; (x>y) == (-x<-y) is %sn", -2147483648, 1, (x>1) == (-x<-1)?"true": "false");
    return 0;
}

实验结果是:

value is 16777216.0000000000
x * x = -131071
x: -2147483648 and y: 1; (x>y) == (-x<-y) is false

要理解为什么输出结果与我们预期的不符应该理解本节所讲的内容。


定点表示法没有办法有效地表示一个很大的数。5*2^100的二进制表示方式是10100...0(Binary103位),而显然我们不希望这样表示一个很大的数。因此我们使用IEEE浮点标准来表示大的数字或者小数。

IEEE浮点标准使用类似科学计数法的方式来定义:

  • s 表示符号(sign),决定了这个数是不是整数
  • M表示尾数(mantissa),是一个二进制小数
  • E 表示阶码(exponent),表示对浮点数的加权平均,权重是2的E次幂,可以是负数。

14cb3a4232abd520d63edaa9fa629921.png

一般计算机用IEEE 754来表示小数。

规格化数

d884cb3a28439948e08a21c262a0a45f.png
机器码不同位表示含义
  • 规格化数
    在二进制小数中,若将其表示为类似科学计数法的形式,尾数部分的第一个有效位一定为1,为了尽可能多的表示数字,我们规定单精度的Significand部分表示1.xxxxxx尾数的xxxx部分。
  • 符号
    1 represents negative and 0 represents positive
  • 阶数
    • 范围从0000 0001(该阶码的值为:-126) ~ 1111 1110(127)
    • 全0和全1表示特殊的数
    • 单精度(single precision)偏置常数127(不是标准的偏置常数)
    • 双精度(double precision)偏置常数1023(2^10 - 1)
使用127与1023而非128&1024的原因是:
1. 阶码的上界可以更大,表示的范围更广,而实际上选哪个都是可以的。
2. 后面计算最大 非规格化数与最小 规格化数时可以发现,这样设置偏置常数有利于这两个连续数字的 平滑转变(相邻两个数在数轴上的距离不会太远)
两个概念:
阶是用移码表示的,里面有几个值需要说明:
1. 阶码: 0000 0001B = 1
2. 阶码的值: 1 - 127 = -126 阶码表示机器保存的数字,按原码读法读出来的值 阶码的值表示这个数字按照实际的移码读法读出来的值,这个值也是实际算十进制真值时的指数的值
  • 尾数
    • 规格化尾数最高位是1,隐含表示;实际尾数表示1后的部分
    • 单精度(single precision)尾数可表示:1 + 23bits
    • 双精度(double precision)尾数可表示:1 + 52bits

非规格化数

如下表

58d3e0b57cb25d11718aa2db1b7b4c03.png

关于无穷大,可以利用无穷大作比较,X / 0 > Y其中X、Y为浮点数

关于无穷大和NaN的运算

  • 5.0/0 = +∞; -5.0/0 = -∞;
  • 5+(+∞) = +∞; 5-(+∞) = -∞;
  • 0/0 = NaN; sqrt(-4.0) = NaN;
  • op(NaN, x) = NaN; (+∞)+(-∞) = NaN;
  • ∞/∞ = NaN; (+∞)-(+∞) = NaN;

0d98fe558def01f70c6f26d55bb8b97a.png
单精度浮点数各种极值情况

我们还记得,在规格化数中,尾数表示1.xxxxx,是隐含了最高位为1的。那么对于阶数为0,尾数为非0的非规格化数来说,这个尾数表示的则是0.xxxxx。非规格化数用来应对算数下溢的问题,它提供了一些数来尽可能表示原先算数下溢的数字,以求精确。

总的来说,非规格化数的作用:

  • 提供了表示数值0的方法。IEEE的标准中,值+0.0 和 -0.0 某些方面是不同的(比如阐述负数算数下溢时),而其他方面是相同的(在浮点数比较中,-0.0 == +0.0)。
  • 表示那些非常接近0.0的数,非规格化数的存在使得数的表示可以渐近下溢(下面将会提到)。
  • 对于NaN这样的特殊值,用来表达一些运算得到不能是实数也不能是无穷的结果,例如对-1开根号;某些情况下,用来表示未初始化的数据。

浮点数的溢出

浮点数的溢出同定点数溢出一样,都表示计算产生出来的结果是非常大的,大于寄存器或存储器所能存储或表示的能力限制。

在浮点数中,对于算数上溢,我们用无穷来表示,即

48023fdde1e7474dd60c2d9ad262bd23.png

对于算数下溢来说,表示现在计算结果很接近零,使得计算结果的大小小于浮点数可以表示的最小数字。

界于−fminN and fminN之间的区间称为下溢间距(underflow gap),其中fminN为一般浮点数格式所能表示的最小正数。

在早期的设计中,界于下溢间距之间的数字其值均视为零,因此若出现算术下溢,其结果会被改为零,可能是用硬件或系统软件处理,此处理方式称为“清洗为0”(flush to zero)。

而IEEE引入非正规数后,使用非正规数和0,可以填满下溢间距。假设浮点数指数范围为-128至127,最小可表示正规数为

,次正规数则是类似
……之类的数,计算时会将结果转换为最接近的次正规数,因此可以
渐近下溢,不过最接近的次正规数中仍有可能是零。
对于 渐进下溢(gradual underflow)和 突然式下溢出(abrupt underflow)的区别可以见这里的 非规约形式的浮点数章节

这一章我们介绍了广泛应用于编程语言小数的浮点数IEEE 754标准所定义的规格化数与非规格化数的含义,理解小数在计算机中的表示,这是我们解释浮点数在编程过程中遇到的各种问题时的基础。

这篇文章有诸多概念,我们可以结合下一篇文章的栗子和图文进行理解。

Yannick:Introduction to CSAPP(七)浮点数表示的直观例子​zhuanlan.zhihu.com
73eeadfcd7f00703b1e7ff99fc8f423a.png
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值
>