Chapter 2 Representing and Manipulating Information 《CSAPP 笔记》

来源:互联网 发布:mac输入法表情符号 编辑:程序博客网 时间:2024/04/28 16:04

Chapter 2 Representing and Manipulating Information

1 Chapter 2 Representing and Manipulating Information

1.1 Information Storage

  • 编译器知道对象类型,但是最终的机器代码不知道类型,只有bytes.
  • Word size:决定了最大Virtual address space 注意这里限制的是虚拟而不是物理 , 因为每个地址用一个字来编码,当有w位时,范围为0~2^(w-1).
  • 大小端 :虚拟地址都是 低~高 的情况下,大端 是 高位~低位,小端 是 低位~高位。 地址低到高,大端大,小端小
  • >>右移:
    • 无符号数一定是 logic右移(补0) ,而 符号数一般都是 算术右移(补符号) (C 未明确规定区分,java有)
    • 当移位k>=类型位数w时,一般移 k mod w 位(C 未明确规定区分,java有)

1.2 Integer Representations

1.2.1 Unsigned Encodings

[[2.1_unsigned_encodings.png]

  • 向量\(\vec{x}\) 的所有位模式 与 (0,2^w - 1)内的 标量x 一一对应。

注意向量x是计算机里的w位比特向量,而标量x是 对 向量x的每位 赋权重后解释得的值

1.2.2 Two's-Complement Encodings

2.3 signed encodings.png

  • 就是把 向量x 的最高位 解释为 -2^(w-1), 其他与无符号相同
  • 向量x 与 标量x [-2^(w-1) , 2^(w-1)-1] 一一对应,因此|TMin| = |TMax| + 1
  • <limits.h> <stdint.h>中 有明确的类型和相应范围宏 记得宏的写法还有些特殊,是有原因的,原因是?

1.2.3 Conversions Between Signed and Unsigned

2.5_signed_to_unsigned.png

  • 有符号标量x -> 向量x -> 无符号标量x 以相同的向量作为中介
  • 就是最高位权重从 -2^(w-1)变成了 2^(w-1),因此正数不变,而负数 + 2^w

2.7_unsigned_to_signed.png

  • 原理同上,都是位模式不变,改变最高位的解释

总结:

  • 就是强制转换,不过C里面不是从数,而是从 位的角度 来看的。 保证了位模式不变,而不是数值不变

(int*) 与 (int) 的异同??如果都只是解释不同,那么(float*)和(float)呢??

1.2.4 singed vs. unsigned in C

  • 有explicit casting 和 implicit casting。 基本规则都是:位模式不变。 仅是针对整型吧?
  • printf 是没有变量的类型信息的,必须有用户通过指示符%d等来,告知类型。
  • 有符号与无符号运算时,统统转成无符号,因此会出现 -1 < 0u 为 false

1.2.5 Expanding the Bit Representation of a Number

  • 无符号扩,就补0;有符号扩,就补符号位 归纳法证,增加一最高符号位是+-2^w,但原符号位变正权值是+2(w-1),最后实际还是-2(w-1)
  • 而大小不同的有符号扩为无符号,如:unsigend y = short x; short 会先size转成int, 再转成 unsigned

先保值扩尺寸 即,是(unsigned)(int) x, 而不是(unsigned)(unsigned short) x从汇编角度看就是:根据src的符号,选用movs或movz,改符号是后续代码的解释责任

1.2.6 Truncating Numbers

有位 和 数值 两种角度

  • 从位模式的角度看 就是从向量x的角度看 ,就是直接截断,然后按无符号或有符号解释
  • 从数值的角度看 就是从标量x的角度看 ,就是取模,再做类型转换。 强制类型转换,就是对同样位模式采用不同解释

1.2.7 2.2.8 Advice on Signed vs. Unsigned

  • signed 到 unsigned 的隐式转换 导致 一些违背直觉的行为;而违背直觉的行为很容易导致bugs。而且还不容易看出问题所在。
  • 例如:
    • i <= length - 1 , 当i为signed, 而length为unsigned, 同时length=0时,访问越界。
    • return strlen(s) - strlen(t) > 0 无符号相减,不会为负

1.3 Integer Arithmetic

1.3.1 加法

  1. +_(u,w)和+_(t,w) 与 + 的数值关系2.11_unsigned_add.png2.14_signed_add.png注意以上各式中很多+的意义是不同的,可理解为计算机中的加法是对数学中加法的重定义
    • 实际就是二进制加法,然后截断获得 其实从位模式角度看非常简单,但从数值角度看就麻烦,就有上面的一堆式子
  2. 溢出判断
    • 无符号加法溢出:当且仅当 sum < x (或者等价的 sum < y)时,发生溢出
      • 证明:数值关系上在溢出时有 sum = x +_(u,w) y = x + y - 2^w 加数本身有范围,所以加法只能溢出一位,因此一定是- 2^w ,而 y - 2^w < 0,所以 sum < x;…另一边也易证。其实就是上面的式子,用于判定溢出
    • 有符号加法溢出:当 x > 0, y > 0, 而 sum <= 0时,正溢出;当 x < 0, y < 0, 而 sum >= 0时,负溢出。就是上面的式子

1.3.2 乘法

  1. *_(u,w) 和 *_(t,w) 与 * 的数值关系2.16_multiplication.png
    • 从上式中看出,无符号和有符号乘法的位级表示都是一样的,只是最后解释不同。
  2. 溢出判断
    • 有符号溢出: p = x * y; return !x || p/x == y

    就是靠逆运算来判断的,而对于加法是不能靠逆运算来判断的,跟什么阿贝尔群有关 无符号的溢出判断怎么做的呢,应该也是逆运算吧 CSAPP上有个证明

1.3.3 与常数的乘除运算

  1. 乘以常数
    • 由编译器将 乘以常数 转化为移位来实现,实际操作方法是:将常数表示为2的幂和形式,然后利用乘法的分配律,如 \(x * (14) = (x<<3) + (x<<2) + (x<<1) = (x<<4) -(x<<1)\)
  2. 除以2的幂
    • 整数除法总是向0取整,而整数的移位是向下取整的 除法丢掉小数部分所以向0;移位减小了"正数"部分,所以变小向下 ,所以在处理负数时,行为不一致;

    解决方法是在 移位之前,加入偏置(上抬一点),即, (x < 0 ? x+(1<<k)-1 : x) >> k 等价于 \(x / pwr2k\)应该编译器不会这么做,只有C代码显示这样写

1.4 Floating Point

1.4.1 Fractional Binary Numbers

  • 二进制与十进制一样, 小数点左边是positive powers, 而小数点右边是negtive powers
  • 小数点的移位,使得整个数值乘2或者除2 因为同时改变了所有权重的解释
  • 0.111…1_2 是 just below 1 的值;对有限位来说 ε 表示最小值,而 1-ε 就 just below 1 的值。
  • fractional binary notation 和十进制分数一样,只能精确表示 x * 2^y 形式的值。

1.4.2 IEEE 的浮点数表示

  • 依据小数点的位置(positional notation)来表示,不是和表示较大的数值,因此,采用 x * 2^y 形式用有限的空间表示更大的数,但实际两种表示方法表示的值空间一定是一样的。
  • IEEE的形式是:\(V = (-1)^S * M * 2^E\)
    • s 符号(sign): -1表示负数,0表示正数和其他一些特殊值
    • M 有效数(sinificand): 二进制小数 属于 \([0,1-\epsilon]\cup[1,2-\epsilon]\)
    • E 指数(exponent): 对上面两者确定的value 乘以 \(2^E\), E可能为负
  • 3个域的位定义
    • sign s: a single sign bit
    • signifcand M: 用 k-bit fraction field
    • exponent E: 用 n-bit exponet field, 该域为0时有特殊的编码规则
  • C语言中的实现
    • single-precision floating-point formant: 1, k=8, n=23
    • double-precision floating-point formant: 1, k=11, n=52
  1. C中浮点数的三种情况
    1. 最常见情况:Normalized Values
      • exp field 非全0,非全1
        • \(E = e - Bias, Bias = 2^{k-1} - 1\) ?E的bias与补码有啥异同?运算上有差异吧?
      • sinificand field
        • fraction 存的是 \(f = 0.f_{n-1}...f_{1}f_{0}\)
        • 有一个implied leading 1, 所以the significand \(M = 1 + f\) 总是存在的1就不用存的,得到1免费精度
      • sign
    2. 也常见:Denormalized Values
      • exp field 全0
        • \(E = 1 - Bias\) 不用-Bias是为了提供从 denormalized 到 normalized values的平顺转化

        注意这里e全0时,e并不是解释为0,而是解释为1。这与normalize时的最小情况是一样的。

        • \(M = f\) 而没有 implied leading 1
      • 两个主要作用
        • 表示0. normalized时,无法表示0。
          • $+0.0$是所有bit位都是0
          • $-0.0$仅仅是符号位为1,其他都为0。它们会被不同对待 ?怎么个不同使用法?
        • 表示非常接近0的数。提供 a property known as gradual underflow
    3. Special Values
      • exp field 全1
      • fraction field
        • 全0,表示 正负无穷
          • 表示 overflow, 例如:两个很大的数相乘,或者除0
        • 全1,表示 NaN, Not a Number
          • 当计算结果不能用 实数或 \(+\infty, -\infty\) 表示时,使用。例如: \(\sqrt{-1}\) 或者 \(\infty - \infty\)
  2. 基于具体例子的讨论
    1. 一共6bits, 3 exponent(bias为\(2^{3-1}-1\)), 2 fraction。如下图所示:
      • 所有数值并不是均匀分布的,而是越靠近0越紧密。
      • Denormalized 与 normalized 之间平滑过渡
        • 最大的 Denormalized 有E=1-bias, f全1,而M=f
        • 最小的 normalized 有E=1-bias, f全0,而M=1 两者之间刚好差一点点,\((1-f)^{1-bias}\)
    2. 基于无符号 来比较 float
      • 一个性质是可以 对正的float, 按位解释为 unsigned integers, 正好也是同样的升序排列。
      • 但是对负的不是,差异在于
        • 最开头有一个符号1 这一点并不影响负数之间的比较,只是不能正负之间用unsigned 来比较。
        • 做为unsigned integers看时,整体上负数是 descending order.
    3. floating-point 表示的一些特点和性质(k exponent, n fraction)
      • +0.0 的 bit representation 总是 全0
      • 最小的正 denormalized 值 仅在最低位有个1,其他全0。\(M=f=2^{-n}\) \(E=1-(2^{k-1}-1)\) 最终得\(V=2^{-n+2-2^{k-1}}\)
      • 最小的positive normalized 值exp的最低位有个1 *注意1的位置与上面不同。*,其他全0。\(f=0\) 但是\(M=1\) 而\(E=1-(2^{k-1}-1)\) *与上面相同*。最终得\(V=2^{2-2^{k-1}}\)
      • 数值1.0, e除了最高位不为1,其他位都为1,\(M=1\)
      • 做大的normalized值,符号位 & e的最低位为0,其他位全1

1.4.3 2.4.4 Rounding

浮点数总是有限的范围和精度,因此需要定义转为浮点数的规则。关键问题在于在两个可能的浮点值之间如何选择。

IEEE floating-point format 提供了4种方式。

Round-to-even(round-to-nearest)默认模式找到最近的匹配。同时保证转化结果的最低位总是为even。相比下面三种模式,在实际中计算误差偏差较小,因为50%向上,50%向下。

其他三种模式能够给数值和计算提供确定的 界。x为原整数值。Round-toward-zero \(|\widehat{x} \leq x|\)Round-down \(x^{-} \leq x\)Round-up \(x \leq x^{+}\)

1.4.4 2.4.5 Floating-Point Operations

对运算的定义很简单,就是 \(Round(x \odot y)\), 其中 $o$表示任一运算

  1. 浮点数加法
    • \(x +^{f} y\) 就是 \(Round(x + y)\)
    • 加法是 commutative,但 **not associative**。因此要小心计算顺序,编译器也不敢为了优化而改变计算顺序。
    • 满足如下的monotonicity property \(if a \geq b then x + a \geq x + b\)
  2. 浮点数乘法
    • \(x *^{f} y\) 就是 \(Round(x * y)\)
    • 同样是 commutative,但 **not associative**。因为可能的 溢出和精度损失。
    • 同样原因,也不能 distribute over addition
    • 满足如下的monotonicity property 注意其中的=是必须的
      • \(a \geq b\) and \(c \geq 0\) \(\rightarrow\) \(a *^{f} c\) \(\geq\) \(b *^{f} c\)
      • \(a \geq b\) and \(c \leq 0\) \(\rightarrow\) \(a *^{f} c\) \(\leq\) \(b *^{f} c\)

1.4.5 2.4.6 Floating Point in C

  1. C标准 与 IEEE标准
    • 所有版本的C都有 float 和 double, 对应 single- 和 double- precision floating point.
    • 机器都使用 round-to-even rounding mode
    • 但是C 标准 没有要求使用 IEEE的floating point, 因此,没有标准的切换rounding mode 和 获取特殊值的方法。 有但是不标准
  2. int, float, double 的 casting规则
    • int to float, 不会溢出,但有 rounding
    • int 和 float to double, 数值能够精确保留,因为double有更大的范围和精度。

    int也全部能精确表示?int的最长模式在float里面放不下,但是在double里面能够放得下

    • double to float, 可能溢出 和 rounding
    • float 和 double to int, 总是 round to zero, 或者有溢出,C标准没有规定特定的溢出值,某些机器有自己特定的溢出值。

    注意前面是round-to-even 这里是 round to zero

?浮点数如何与整数转换呢?有些什么转换方式呢??浮点数的比较问题,精度如何影响比较???NaN的含义?哪些地方产生NaN的呢?正无穷减负无穷

Author: DQR

Created: 2016-10-09 周日 08:16

Emacs 24.5.1 (Org mode 8.2.10)

Validate

0 0
原创粉丝点击