美文网首页
信息的处理与表示

信息的处理与表示

作者: 淇漯草 | 来源:发表于2018-11-28 07:49 被阅读0次

    计算机以8位为一块(称作字节byte)作为最小的可寻址的内存单位。
    虚拟地址空间(virtual address space)


    小端表示与大端表示是关于某一个数据在计算机的存储顺序

    以字节为单位


    布尔代数中,and可用于令特定位为0,or可用于令特定位为1,xor可用于令特定位保持不变。

    A xor B = (A&~B) | (~A&B)
    其本质含义是,将不同的拿出来。


    在C语言中,编译器大多认为对符号数右移为算数右移。


    无符号的编码和补码的编码,定义由向量从右到左排列之和。

    具有唯一性

    宏能保证:无论代码如何被编译的,都能生成正确格式
    如printf("x=%" PRId32 ", y=%" PRIu64 "\n",x,y)
    C预处理器遇到仅用空格分割的字符串常量序列,就串联起来


    反码最高位权重比补码低1
    原码最高位表符号

    两者都有两个0,一般不采用


    补码用2^w - x,表示-x,而反码由直接表示

    有符号数与无符号数之间的转换
    我们采用二进制作为过渡

    补码->无符号数
    x + 2^w if< 0
    x if> 0
    也就是x+X(w-1)2^w*
    无符号数->补码(Two's Complement)
    u <= TMax(w)
    u-2^w > TMax(w)
    在C语言中,向无符号靠近。
    -1 < 0U 时 为0
    2147483647U > -2147483647 - 1 为0

    在上述中采用了-2147483647-1。
    在宏定义中,主要是因为奇怪的规则。采用了这种方式。

    #define INT_MAX 2147483647
    #define INT_MIN  (-INT_MAX - 1)
    

    零扩展与符号扩展

    在C语言中,short->unsigned时,先改变大小,再完成无符号转换


    无符号的截断数字是取模
    有符号的截断数字是取模后再转为有符号


    由于这种强制类型转换会导致错误

    getpeername的安全漏洞。
    函数void *memcpy(void *dest, void *src, size_t n);复制到用户的缓冲区。
    n如果选用负数-->变成size_t的无符号数,可能导致溢出

    Java中没有无符号数


    无符号加法的溢出
    x+y x+y < 2^w
    x+y-2^w 2^ <= x+y <2^(w+1)
    求反则是2^w-x

    检测(x+y)>= x


    补码加法的溢出
    正溢出:x+y - 2^w(本质:去掉溢出的,再加上符号的负)
    正常:x+y
    负溢出:x+y + 2^w(只进了1位,变成正的,+上进的,+符号)

    对于负溢出
    我们先将其转换为无符号数,则+2^w,去掉高处部分,此时符号位为0。
    我们要记住的就是:正-->负, 负-->正, 正常-->正常
    推导方式,转为无符号,再转回来。
    最终表达式x+y = U2Tw[(x+y)mod 2^w]
    :补码取的是-x的表示方法

    检测:s==(x+y)当x>0,y>0,s<=0,与x<0,y<0, s>=0

    阿尔贝群中加法逆元操作恒成立


    补码的非,除了最小值=自己,其他相反

    一、非的位级表示,~x+1 与 -x相同。二、从右到左,第一个1,以前取反。


    无符号乘法=截断
    补码乘法=U2Tw(xymod2^w)*

    位级等价性


    乘法是否溢出

    int tmult_ok(int x, int y){
      int p = x*y;
      return !x || p/x == y;
    }
    

    证明方法:
    一、xy = p + t2^w。仅有t>0时,溢出
    二、除法时,p=xy+r,xy = xy + r + t2^w,
    三、仅当r = t2^w时,原式成立。此时,t=0,不溢出
    在这里我们阐明三个问题。
    首先,x
    y=p在t>0时,不满足。
    q=y当且仅当t=r=0时成立。
    否则q就不等于y,那么也就表明溢出。

    补码乘法,本来就是截断的,那么也就意味着,如果乘法发生溢出,那么截断也就出现了问题。
    我们要注意的就是,溢出的值使得仍保留在原位的值不再与实际值相同

    int tmult_ok(int x, int y){
      int64_t pll = (int64_t)x*y;
      return pll == (int)pll;
    }
    

    这里可以再次说明,乘法的位级等价性,不仅仅用于说明乘积的位级表示相同,还说明,无符号乘积在溢出的判断的意义是和补码是等价的。

    void *copy_elements(void *ele_src[]), int ele_cnt, size_t ele_size){
      void *result = malloc(ele_cnt * ele_size);
      if(result == NULL)
        return NULL;
      void *next = result;
      int i;
      for(i=0; i<ele_cnt; i++){
        memcpy(next, ele_src[i], ele_size);
        next += ele_size;
      }
      return result;
    }
    

    假如在malloc 处发生溢出,则分配内存不足,导致缓冲区溢出。


    乘以常数,利用移位优化。
    考虑k的形式 n位到m位都是1

    形式A:(x<<n) + (x<<(n-1)) + ...+(x<<m)
    形式B:(x<<(n+1)) - (x<<m)

    当n = m时,A
    当n = m+1,A B同速
    当n > m+1,B


    除以2的幂

    无符号,直接>>
    补码,加偏置(y-1)
    原因:负数要向0舍入,
    x = qy+r, floor((x+y-1)/y) = q+(floor(r+y-1)/y)

    C表达式:(x<0 ? x+(1<<k)-1 : x) >> k


    写一个函数div16,对于整数参数x返回x/16的值。你的函数使用除法、模运算、乘法、任何条件语句(if或者?:)、任何比较运算符(>、<、==)或任何循环。你可以假设数据类型int是32位字长,使用补码表示,而右移是算术右移。

    int div16(int x){
      ins bias = (x>>31) & 0xF;
      return (x+bias)>>4;
    }
    

    相关文章

      网友评论

          本文标题:信息的处理与表示

          本文链接:https://www.haomeiwen.com/subject/ggltzftx.html