zoukankan      html  css  js  c++  java
  • 信息的表示和处理 及 CS:APP 15213 datalab

    信息的表示和处理

    在通用计算机中中,字节作为最为最小 的可寻址的内存单元,而不是访问内存中单独的位。

    寻址和字节顺序

    • big endian (大端法),数据最高字节部分地址在地址处,和人的感觉逻辑相似
    • little endian (小端法),低字节部分在低地址处

    布尔代数

    • 1 TRUE
    • 2 FALSE
    • ~ NOT
    • & AND
    • | OR
    • ^ EXCLUSIVE-OR(异或)
      • 1 ^ 0 = 1
      • 1 ^ 1 = 0
      • 0 ^ 0 = 0
      • 0 ^ 1 = 1

    IEEE 754 浮点数

    $ V = (-1)^s imes M imes 2^E$

    • 符号(sign) s(1)为负数, s(0)为非负数
    • 尾数(significand) M 是一个二进制小数, 范围为 $1 sim 2 - varepsilon $ 或者 (0 sim 1 - varepsilon)
    • 阶码(exponent) E的作用是对浮点数加权, 权重的范围为2的 E 次方幂

    将浮点数的位划分位三个字段,分别对这些值赋值:

    • 一个单独的符号位 s 直接编码符号位 s, 1-bit
    • k 位的阶码字段 (exp = e_{k-1} cdots e_1 e_0) 编码阶码 E, k=7(单精度), k=11(双精度)
    • n 位小数字段 (frac = f_{n-1} cdots f_1 f_0) 编码尾数 M, 且编码的值依赖阶码字段的值是否等于 0, n=23(单精度), n=52(双精度)

    浮点数的值:

    • e 为无符号整数,其位表示 (e_{k-1} cdots e_1 e_0)
    • 小数字段 frac 被解释为描述小数值 (f), 其中 (0 le f le 1), 其二进制表示(0.f_{n-1} cdots f_1 f_0)
    • Bias 是一个等于 $2^{k-1} -1 $ 的偏置值
    • 规格化((exp !=0, exp != 2^{k}-1)), 最常遇到的值
      • 阶码的值 (E = exp - Bias)
      • 尾数定义 (M = 1 + f)
    • 非规格化((exp == 0)), 提供表示数值 0 及逐渐接近 0 的方法
      • 阶码的值 $E = 1 - Bias $
      • 尾数定义 (M = f)
    • 非规格化((exp == 2^{k}-1)), 特殊值 NaN

    舍入
    表示方法限制了浮点数的范围和精度
    偶数舍入(round-to-even) 为默认的舍入方式, 其将数字向上或向下舍入,使得结果的最低有效数字(保留位)是偶数(0)
    只有是在两个可能的结果的中间值才考虑向偶数舍入, 大于 0.5 是直接进位的
    向上舍入的情况,向下舍入可以不管(反正要丢弃了,不影响结果)
    尾数 (1.BBGRXXX), 保留位(Guard bit)、近似位(Round bit) 和 粘滞位(Sticky bit)

    • Round = 1, Sticky = 1 > 0.5 进位
    • Guard = 1, Round = 1, Sticky = 0 -> 偶数向上舍入

    实验部分

    1. 只用 ~& 操作符求两个数的或
    摩根定律: $ eg(p lor q) = eg p land eg q ( 异或:) p oplus q = ( eg p land q) lor (p land eg q)$
    所以展开即可

    /*
     * bitXor - x^y using only ~ and &
     *   Example: bitXor(4, 5) = 1
     *   Legal ops: ~ &
     *   Max ops: 14
     *   Rating: 1
     */
    int bitXor(int x, int y) {
        return ~(~(~x & y) & ~(x & ~y));
    }
    

    2. 最小的整形补码, 可用符号 ! ~ & ^ | + << >>
    $ -2^{31} $ (0xF0000000)

    /*
     * tmin - return minimum two's complement integer
     *   Legal ops: ! ~ & ^ | + << >>
     *   Max ops: 4
     *   Rating: 1
     */
    int tmin(void) {
        return 1 << 31;
    }
    

    3. 判断是否是最大的整形数,可用符号 ! ~ & ^ | +*
    直接利用 INT_MAX + INT_MAX + 2 = 0 的结果并且排除0xFFFFFFFF,还要注意一个不能直接相加,只能 x+1+x+1

    /*
     * isTmax - returns 1 if x is the maximum, two's complement number,
     *     and 0 otherwise
     *   Legal ops: ! ~ & ^ | +
     *   Max ops: 10
     *   Rating: 2
     */
    int isTmax(int x) {
        return !(x + 1 + x + 1) & !!(x + 1);
    }
    

    4. 判断所有的奇数位为1,可用符号 ! ~ & ^ | + << >>
    排除偶数位的干扰得到奇数位的值,再与奇数位的 0xaaaaaaaa 做亦或运算,如果正确结果必为 0,这时做 非运算 就可以了
    所有先得到 0xaaaaaaa

    /*
     * allOddBits - return 1 if all odd-numbered bits in word set to 1
     *   Examples allOddBits(0xFFFFFFFD) = 0, allOddBits(0xAAAAAAAA) = 1
     *   Legal ops: ! ~ & ^ | + << >>
     *   Max ops: 12
     *   Rating: 2
     */
    int allOddBits(int x) {
        int bits0_15 = (0xAA << 8) + 0xAA;
        int bits0_23 = (bits0_15 << 8) + 0xAA;
        int bits0_31 = (bits0_23 << 8) + 0xAA;
    
        return !((bits0_31 & x) ^ bits0_31);
    }
    

    5.取负,可用符号 ! ~ & ^ | + << >>

    /*
     * negate - return -x
     *   Example: negate(1) = -1.
     *   Legal ops: ! ~ & ^ | + << >>
     *   Max ops: 5
     *   Rating: 2
     */
    int negate(int x) { return ~x + 1; }
    

    6. 判断是否是 ASCII 数字,可用符号 ! ~ & ^ | + << >>

    1. 判断高 6_31 位,必须是 0
    2. 判断 4 5 位,必须为 1
    3. 判断第四位,通过相加6判断是否有进位
    /*
     * isAsciiDigit - return 1 if 0x30 <= x <= 0x39 (ASCII codes for characters '0'
     * to '9') Example: isAsciiDigit(0x35) = 1. isAsciiDigit(0x3a) = 0.
     *            isAsciiDigit(0x05) = 0.
     *   Legal ops: ! ~ & ^ | + << >>
     *   Max ops: 15
     *   Rating: 3
     */
    int isAsciiDigit(int x) {
        int bit6_31 = !((x >> 6) & (~0));
        int bit_5 = (x & 0x20) >> 5;
        int bit_4 = (x & 0x10) >> 4;
        int bits0_3 = !(((x & 0xF) + 6) & 0x10);
        return bits0_3 & bit_4 & bit_5 & bit6_31;
    }
    

    7. 条件判断,三目运算符, 可用字符 ! ~ & ^ | + << >>
    思路:由于 X & 0xFFFFFFFF = X, X & 0x0 = 0, 将两个数和 0xFFFFFFFF, 0x0 做与操作,再相加

    1. 只需要找到什么时候为 0xFFFFFFFF 和 0x0, 注意这两者可通过 ~ 得到
    /*
     * conditional - same as x ? y : z
     *   Example: conditional(2,4,5) = 4
     *   Legal ops: ! ~ & ^ | + << >>
     *   Max ops: 16
     *   Rating: 3
     */
    int conditional(int x, int y, int z) {
      int flag = (!!x + ~0);
      return (z & flag) + (y & ~flag);
    }
    

    8. 小于等于 可用字符 ! ~ & ^ | + << >>
    思路:判断相等,同符号相减判断是否有进位,不同符号直接判断第一个数的符号是否为 正

    /*
     * isLessOrEqual - if x <= y  then return 1, else return 0
     *   Example: isLessOrEqual(4,5) = 1.
     *   Legal ops: ! ~ & ^ | + << >>
     *   Max ops: 24
     *   Rating: 3
     */
    int isLessOrEqual(int x, int y) { 
        int equal = !(x ^ y);             // x == y
        int same_sign = !((x ^ y) >> 31); // sign
        int x_reduce_y = ~y + 1 + x;
        return equal | (same_sign & (x_reduce_y >> 31)) | ((!same_sign) & (x >> 31) & 1);
    }
    

    9. 非运算符 可用字符 ! ~ & ^ | + << >>
    思路:核心就是抓住 符号位判断

    1. 考虑取反还是取负,取反所有数字的符号位都改变,取负只有 0 和 0x80000000 符号位不变,且这两个符号位相反,所以用取负的方式
    2. 将数与其负数直接做与操作,只有 0x80000000,符号为 1 不变,不能筛选出 0 的情况
    3. 考虑别的情况,将数取反做与操作,符号相反的数与操作后仍然为 0, 0x800000000 取反(符号为0)与其负数(符号为0)相与也还为 0,只有0取反后符号为1,与操作后仍为1
    /*
     * logicalNeg - implement the ! operator, using all of
     *              the legal operators except !
     *   Examples: logicalNeg(3) = 0, logicalNeg(0) = 1
     *   Legal ops: ~ & ^ | + << >>
     *   Max ops: 12
     *   Rating: 4
     */
    int logicalNeg(int x) {
        return ((~x & ~(~x + 1)) >> 31) & 0x1;
    }
    

    10. 计算一个最少的补码位可以表达的位数 可用字符 ! ~ & ^ | + << >>
    思路:将相邻位做亦或操作,找到最高的位为 1 所在的位
    ~(bits16 << 3) + 1) + (((bits16 ^ 1) & 0x1) << 3, bits* 为上一个移位的结果,利用这个结果判断是增加位移的大小

    /* howManyBits - return the minimum number of bits required to represent x in
     *             two's complement
     *  Examples: howManyBits(12) = 5
     *            howManyBits(298) = 10
     *            howManyBits(-5) = 4
     *            howManyBits(0)  = 1
     *            howManyBits(-1) = 1
     *            howManyBits(0x80000000) = 32
     *  Legal ops: ! ~ & ^ | + << >>
     *  Max ops: 90
     *  Rating: 4
     */
    int howManyBits(int x) {
       // all assignment must be followed by a declaration.
        int bits16, bits8, bits4, bits2, bits1;
        int shift16, shift8, shift4, shift2, shift1;
    
        int shift_off = 16; // first shift offset
        x ^= x << 1;        // find the highest 1-bit after XOR adjacent bits
    
        bits16 = !(x >> shift_off);
        shift16 = bits16 << 4;
    
        // binary search.
        // if result of prev offset != 0, shift_off should be increasing half prev
        // offset , else should be decreasing half.
        shift_off = shift_off + (~(bits16 << 3) + 1) + (((bits16 ^ 1) & 0x1) << 3);
        bits8 = (!(x >> shift_off));
        shift8 = bits8 << 3;
    
        shift_off = shift_off + (~(bits8 << 2) + 1) + (((bits8 ^ 1) & 0x1) << 2);
        bits4 = (!(x >> shift_off));
        shift4 = bits4 << 2;
    
        shift_off = shift_off + (~(bits4 << 1) + 1) + (((bits4 ^ 1) & 0x1) << 1);
        bits2 = (!(x >> shift_off));
        shift2 = bits2 << 1;
    
        shift_off = shift_off + (~(bits2) + 1) + ((bits2 ^ 1) & 0x1);
        bits1 = (!(x >> shift_off));
        shift1 = bits1;
        
        return 32 + (~(shift1 + shift2 + shift4 + shift8 + shift16) + 1);
    }
    

    11. 计算浮点数 f * 2, 返回浮点数的二进制位表示, 可用符号不受限制
    思路:由于尾数的值取决于 frac 和 exp,所以要对其分开处理

    • 对于规格数,exp + 1, 但要考虑 +1 后不能为 255
    • 对于非规格数
      • exp = 255, 直接返回参数
      • exp = 0, frac = 0 返回 0, 因为这就是个 0
      • exp = 0, frac != 0, frac 左移一位(尾数取值的问题),又要判断左移后是否溢出(0-22bit)
    /*
     * float_twice - Return bit-level equivalent of expression 2*f for
     *   floating point argument f.
     *   Both the argument and result are passed as unsigned int's, but
     *   they are to be interpreted as the bit-level representation of
     *   single-precision floating point values.
     *   When argument is NaN, return argument
     *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
     *   Max ops: 30
     *   Rating: 4
     */
    unsigned float_twice(unsigned uf) {
      int exp = 0x7f800000 & uf;
      int frac = 0x007FFFFF & uf;
      int sign = 0x80000000 & uf;
      int bias = (exp >> 23) - 127;
    
      if (uf == 0x0)
        return 0;
      if (bias == 128) // NaN return NaN, inf can't *2
        return uf;
    
      // frac depends on exp, so exp could not add 1 alone.
      if (exp == 0) { // (exp + frac) << 1
        frac = (frac << 1) & 0x007FFFFF;
        if (uf & 0x00400000)
          exp = 0x00800000;
      } else {
        exp = (exp + 0x00800000) & 0x7F800000;
        if (exp == 0x7F800000)
          frac = 0;
      }
      uf = sign | exp | frac;
      return sign | exp | frac;
    }
    

    12. 整数转浮点数,返回浮点数的二进制位表示, 可用符号不受限制
    思路:核心在于发现该数的绝对值的最高位 1 对应浮点数隐式精度的 1, 然后最高位1后的23位排列在 frac 位置

    • 取数的绝对值,后面对非负数数进行操作
    • 取最少可以表达整数(最高位 1)的 k 位 inum,
    • 所在的位数 n 整数i转浮点数f 在位模式上为 将 k-1 .. k-2 .. 0 放置在浮点数的 frac 部分,非规格数有一个隐式 1, 代替数字有效最高位 1
    • 由上精度有限制,有效位的前23位充当尾数部分,要对后9位进行判断是否需要舍入
    • 将 exp = 127 + n
    • 符号位不变
    • 其他 0 等情况考虑
    /*
     * float_i2f - Return bit-level equivalent of expression (float) x
     *   Result is returned as unsigned int, but
     *   it is to be interpreted as the bit-level representation of a
     *   single-precision floating point values.
     *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
     *   Max ops: 30
     *   Rating: 4
     */
    unsigned float_i2f(int x) {
      unsigned abs_x = x;
      unsigned sign = x & 0x80000000;
      int flag = 0;
      int n = 30;
    
      if (x == 0)
        return x;
      else if (x == 0x80000000)
        return 0xcf000000;
    
      if (sign)
        abs_x = -x;
    
      while (!(abs_x & (1 << n)))
        n--;
      abs_x <<= 32 - n;
    
      if ((abs_x & 0x01ff) > 0x0100)
        flag = 1;
      else if ((abs_x & 0x03ff) == 0x0300)
        flag = 1;
      else
        flag = 0;
    
      return sign + ((n << 23) + 0x3F800000) + (abs_x >> 9) + flag;
    }
    

    13. 浮点数转整数,返回整数的二进制位表示, 可用符号不受限制
    思路:有上面的 float_i2f() 做铺垫,

    • 集中在对精度的处理, 对于 exp
      • 大于 31,超过整形的表达范围
      • 小于 23,值不发生改变,右移 23 - exp
      • 大于 23 小于等于 31,值发生改变 左移 exp -23
    • 由于浮点数的正负只由符号位影响,所以可以最后做取负操作。
    /*
     * float_f2i - Return bit-level equivalent of expression (int) f
     *   for floating point argument f.
     *   Argument is passed as unsigned int, but
     *   it is to be interpreted as the bit-level representation of a
     *   single-precision floating point value.
     *   Anything out of range (including NaN and infinity) should return
     *   0x80000000u.
     *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
     *   Max ops: 30
     *   Rating: 4
     */
    int float_f2i(unsigned uf) {
        unsigned sign = uf & 0x80000000;
        unsigned exp = uf & 0x7F800000;
        unsigned frac = uf & 0x007FFFFF;
    
        if (uf == 0x7F800000)
            return 0x80000000;
        else if (uf == 0)
            return 0;
        
        if (exp == 0)
            return 0;
    
        int m = 0x00800000 + frac;
        int e = (exp >> 23) - 127;
    
        if (e < 0)
            return 0;
        else if (e > 31)
            return 0x80000000;
        else if (e < 23)
            m >>= (23 - e);
        else
            m <<= (e - 23);
    
        if (sign)
            m = -m;
        return sign | m;
    }
    
  • 相关阅读:
    哈工大《机器学习》最小二乘法曲线拟合——实验一
    最小二乘法曲线拟合以及matlab实现
    Dubbo简介
    Redis持久化策略
    Linux安装Redis
    RabbitMQ-Demo
    RabbitMQ安装相关
    SpringCloud-Alibaba-Nacos-Demo
    Nacos_启动失败原因
    IDEA中properties中文显示乱码
  • 原文地址:https://www.cnblogs.com/shuqin/p/10975730.html
Copyright © 2011-2022 走看看