课程主页:https://courses.cs.washington.edu/courses/cse351/16sp/

课程资料:

实验部分:https://github.com/vuquangtrong/HW-SW_Interface_Course

实验说明:https://courses.cs.washington.edu/courses/cse351/13sp/lab-0.html

课件:http://academictorrents.com/details/b63a566df824b39740eb9754e4fe4c0140306f4b

课程视频:https://www.bilibili.com/video/BV1Zt411s7Gg?from=search&seid=8781593976070799647

这次回顾第二部分,整型数和浮点数。

第二部分:整型数和浮点数

整数表示:无符号和有符号

假设比特表示为

无符号整数
有符号整数
几个重要值

以$w=16$为例

C中无符号和有符号整数

不同长度的值

不难看出有如下关系

  • $|\text{TMin}|=\text{TMax}+1$
  • $\text {UMax}=2\times \operatorname{TMax}+1$

C语言中上述常数的使用方式如下

#include <limits.h>
ULONG_MAX
LONG_MAX
LONG_MIN
C中无符号和有符号整数

强制转换规则为:比特表示不变,解释方法改变。

int tx, ty;
unsigned ux, uy;

tx = (int) ux;
uy = (unsigned) ty;

如果在某个表达式中同时有有符号和无符号整数,那么有符号整数被强制转换为无符号整数。

算术和移位

移位
  • 左移:$ {x} << {y} $
    • 将比特向量$x$左移$y$个位置,扔掉左边多余的部分
    • 在右边填$0$
  • 右移:$ {x} >> {y} $
    • 将比特向量$x$右移$y$个位置,扔掉右边多余的部分
    • 逻辑移位
      • 左侧填充0
    • 算数移位
      • 左侧填充符号位($x$最左侧的符号)
  • 未定义的行为
    • 移位量$<0$或$\ge$单词长度
无符号整数的移位

逻辑移位。

有符号整数的移位

算数移位。

符号拓展

无符号拓展比较简单,直接在前面的比特补$0$即可,有符号拓展比较麻烦,具体如下:

  • 任务:
    • 给定$w$比特位的有符号整型$x$
    • 将其转换为$w+k$比特位有符号整型,并且值相同
  • 规则:
    • 将符号位复制$k$份
    • $X^{\prime}=X_{w-1}, \dots, X_{w-1}, X_{w-1}, X_{w-2}, \dots, X_{0}$

证明如下:

原始的值:

现在的值:

来看一个具体例子:

short int x = 15213;
int ix = (int) x;
short int y = -15213;
int iy = (int) y;

背景:二进制小数

分数二进制小数

转换成十进制的结果为

IEEE浮点标准

浮点数表示
  • 数值形式:

    • 符号位$s$确定数字是负数还是正数
    • 尾数$M$为属于范围$1\sim 2-\epsilon$或$0\sim 1-\epsilon$的二进制小数
    • 阶码$E$是指数
  • 编码

    • 最高位s表示符号位$s$
    • 阶码字段exp表示$E$
    • 小数字段frac表示$M$

根据阶码字段的不同,浮点数可以分为以下几个部分:

下面分别介绍:

规格化的值
  • 当$\text{exp}\neq 000\ldots 0$且$\text{exp}\neq 111\ldots 1$称为规格化的值
  • 阶码的值为$E=\exp -\text{bias}$
    • 其中$\exp$为exp域的无符号值
    • $\text {bias}=2^{k-1}-1$,其中$k$为exp域的比特数
  • 小数字段隐式的用$1$作为首位:$M=1 .\text{xxx} \ldots \text{x}_{2}$
    • $\text{xxx} \ldots \text{x}$:小数域
    • 取最小值当$\text{frac}=000\ldots 0(M=1.0)$
    • 取最大值当$\text{frac}=111\ldots 1(M=2.0-\epsilon)$

来看一个具体例子:

  • 浮点数$F=15213.0$

  • 尾数:

  • 阶码:

  • 结果:

非规格化的值

此时

  • 当$\text{exp}=000\ldots 0$称为规格化的值
  • 阶码为$E=1-\text {bias }$
  • 小数字段的首位为$0$,即$M=0 .\text{xxx} \ldots \text{x}_{2}$
  • 例子
    • $\exp =000 \ldots 0, \text {frac}=000 \ldots 0$
      • 上述两者均表示$0$
      • 注意根据符号位的不同有$+0$和$-0$的区别
    • $\exp =000 \ldots 0, \text {frac}\neq000 \ldots 0$
      • 可以表示接近于$0.0$的数
特殊值
  • 当$\text{exp}=111\ldots 1$称为特殊值
  • 例1:$\exp =111 \ldots 11, \text {frac}=000 \ldots 0$
    • 表示$\infty$
    • 表示操作溢出,$s=1$表示$-\infty$,$s=0$表示$+ \infty$
    • $1.0 / 0.0=-1.0 /-0.0=+\infty, 1.0 /-0.0=-\infty$
  • 例2:$\exp =111 \ldots 01, \text {frac}\neq000 \ldots 0$
    • Not-­a-­Number(NaN)
    • 表示计算结果无法表达的情形
    • 例如$\text{sqrt}(-1),\infty-\infty,\infty \times 0$
可视化:浮点编码

浮点运算和舍入

浮点数运行的基本想法
  • $\mathrm{x}+_\mathrm{f} \mathrm{y}=\operatorname{Round}(\mathrm{x}+\mathrm{y})$
  • $\mathrm{x}\times_\mathrm{f} \mathrm{y}=\operatorname{Round}(\mathrm{x}\times\mathrm{y})$
  • 基本想法
    • 首先计算精确结果
    • 使它适合所需的精度
      • 如果指数太大可能会溢出
      • 可能将其舍入为frac
舍入

考虑几种舍入的方法:

浮点数采用的是向偶数舍入。

向偶数舍入
  • 默认舍入模式

    • 其他的舍入模式会产生偏差:一组正数之和将一致地被高估或低估
  • 应用于小数位/比特位

    • 当位于中间值时,进行舍入,使得最低有效位为偶数

    • 例子

      | 值 | 舍入 | 原因 |
      | ————- | —— | ———————————- |
      | 7.8949999 | 7.89 | (Less than half way) |
      | 7.8950001 | 7.90 | (Greater than half way) |
      | 7.8950000 | 7.90 | (Greater than half way) |
      | 7.8850000 | 7.88 | (Half way-round down) |

舍入二进制数
  • 二进制小数

    • 如果最低有效位为$0$则表示偶数
    • 中间值表示为$100\ldots_2$
  • 例子

    • 舍入到小数点后$2$比特

      | 值 | 二进制 | 舍入 | 动作 | 舍入后的值 |
      | ———————- | —————— | ————- | ———————————- | —————— |
      | $2\frac 3 {32}$ | $10.00011_2$ | $10.00_2$ | $(<1 / 2-\text {down})$ | $2$ | | $2\frac 3 {16}$ | $10.00110_2$ | $10.01_2$ | $(>1 / 2-\text{up})$ | $2\frac 14$ |
      | $2\frac 7 {8}$ | $10.11100_2$ | $11.00_2$ | $(1 / 2-\text{up})$ | $3$ |
      | $2\frac 5 {8}$ | $10.10100_2$ | $10.10_2$ | $(1 / 2-\text{down})$ | $2\frac 1 2$ |

C中的浮点数

  • C中有两种精度的浮点数
    • float:单精度
    • double:双精度
  • int,float,double进行转换时,程序改变比特的模式如下
    • double/float转换为int
      • 截断分数部分
      • 向$0$舍入
      • 如果超过NaN范围则没有定义:通常转换为$\text{TMin}$
      • 例如$1.999$转换为$1$,$-1.999$转换为$-1$,$1e10$转换为$-21483648$
    • int/float转换为double
      • 因为double的范围更大,所以保留精确值
    • int转换为float
      • 数字不会溢出,但是可能会产生舍入(float的frac域没有足够的位表示int)
    • double转换成float,可能溢出为$+\infty$或$-\infty$,由于精度的问题还会产生舍入