zoukankan      html  css  js  c++  java
  • 深入理解计算机系统 第二章要点

    1.每台机器都有一个字长,指明了整数和指针的标称大小(normal size),长整数(long int)和指针的大小都是字长(32位机器是32位,64位机器是64位),字长代表了机器的寻址时地址大小,进而限定了寻址空间的大小,字长w的寻址范围是0-2的(w-1)次方,32位机上线是4G。除了和字长同步的类型(long int和指针)其他类型大小和机器无关,比如char,short,int4,long long int8, float4, double8在32位机器上对8字节的类型数据操作时,先编译成一系列4字节的操作代码。

    2.大小端:对一个2字节的short:0x1234
    地址:0x01 0x02
    大端:12 34 (先存高有效位,再存低有效位)
    小端:34 12
    (PS:十进制转十六进制可以用除法,不断除,但显然的,我们可以通过先把一个十进制数字存到内存,计算机会存为一个一个字节,这个时候我们只需按字节取出,
    每个字节再细分为2个4位,通过移位得到每半个字节上的数字,然后把每个数字转为对应的十六进制字符(0-f),连起来就ok了,最后注意一下大小端就好了。
    其实可以直接用%x输出十六进制结果的 =。=)
    网络上字节流中的字节顺序是大端模式。
    对多个字节存一个数据的整数,浮点数等,是受大小端影响的,但对字符串,则没有,它就是一个字节存一个字符。
    PS:像utf-8这种使用字节序列表示一个字符的,受大小端影响吗?网上资料:字符串倒是没有大端小端的问题,但是字符可能会有大端小端的问题,
    因为字符有可能不是一个字节,可能是2个(比如在Java里)或者4个字节(Python里有选项可以使用UTF16或者UTF32),C里也有wchar_t,可能是2个或者4个字节。

    3.位向量表示有限集合:
    如题,书上给出的例子是这样的:
    a=[01101001]表示{0,3,5,6}
    b=[01010101]表示{0,2,4,6}
    最终a&b={01000001}={0,6}

    谁能解释一下这8位二进制是如何表示集合的呢?
    答案:第 i 位 为 1 表示 i 在 集合里。从右边数起,第一个是0位,对于a:第0位是1所以集合有0,第3位是1所以集合里有3...

    4.布尔类型:
    a^0 = a, a^1 = ~a

    5.逻辑右移:左边补0,算术右移:左边补最高位。默认地,对无符号数,>>means逻辑右移,对有符号数,>>means算术右移,整数x>>1代表(x-1)/2

    6.补码:在无符号数编码的基础上,最高位对应的数值加符号。计算机对有符号数一般使用补码编码
    (注意,所谓无符号数编码,补码,反码,原码只是对一系列位的解释,对一个8位数,他们解释成不同的数值,这个解释的逆过程则是他们编码的过程)

    7.有符号数和无符号数之间的转换,所谓转换,只是针对某个n位的数,换一种解释的方式,并不改变位值。
    C语言在对同时包含有符号数和无符号数的表达式时,隐性把有符号数转成无符号数,再进行计算。
    书中说:这个对标准的算术运算,结果和直观无多大差异,只对<和>有差异,但我的测试结果明显不对:

    1    if (-1 < 0u)
    2    {
    3    int i = 0;
    4    }
    5    else
    6    {
    7    unsigned int a = 2147483648;// 0x80000000;
    8    int c = -2147483647;//0x80000001
    9    int j = c - a;//j结果是1
    10    int k = 0;
    11    }

    第1行:-1转成无符号后变得很大,所以执行else,和直观不同
    第7-9行:直观上j应该是一个很小的负数,担结果却是1
    总结:尽量不要互转,除非你确定任何数值都没有问题。具体分析就是一步一步来,反正规则就是转换只改变解释方式,不改变位值,并且默认有符号转无符号。
    在书中还举了个很容易犯的错误:

    int sumElement(int a[], unsigned len)
    {
    int i = 0;
    int ret = 0;
    for (i = 0; i <= len - 1; ++i)//当len=0时,0u-1得到的无符号数很大,其实本质上是一个负的有符号数转为一个无符号数本身是有问题的!
    {    //我想应该没有通用的解决方法,书中说的len改成int是一种解决方法显然不完全对:len很大至变成int是负数呢。
    //第二种方法是i < len,这个是因为这个应用中i一定不是负数,
    //我觉得应该谨记:避免负的有符号数转无符号数,或者它的逆过程。
    ret += a[i];
    }
    return ret;
    }

    8.从小数据类型变成大数据类型,如short to int
    无符号数左边补0,有符号数左边补最高位

    9.同时改变大小和符号情况下,大小优先级高:
    short x = -12345;
    unsigned int y = x;//y = ff ff cf c7,等于y = (unsigned)((int)x);

    10.两个无符号数相加是否溢出:s = x + y; 如果s < x则溢出,因为y < 2的w次方,(s < y也可以)
    我突然想起以前做校招笔试题时,就有求2个整数的平均值的问题,(x+y)/2可能溢出,x/2+y/2是错的,正确方式:(x & y) + ((x ^ y) >> 1),因为:

      每个整数都可以分解成对应的二进制,然后2个二进制相加,如果某位相同,则相加后该位应该变为0或2,即位的值*2,如果不同,则保留为1,所以其平均数为:x&y + (x^y)>>1,前者是位值相同部分相加的平均数,后者是位值不同部分相加的平均数

    11.两个补码相加:
    x+y>=2的(w-1)次方:正溢出
    x+y<-2的(w-1)次方:负溢出
    在中间则正常
    x和y都是负数,x+y>=0则会发生负溢出;当x和y都是正数,但x+y<0则发生正溢出
    书中特别提到Tmin(比如4位则Tmin=-8),-8的负还是-8!所以对tmin要保持警惕,看下一条:

    12.补码的非:x=Tmin则x的非是Tmin,因为Tmin+Tmin=0(这个是对计算机而言哈,不是直观的)
    x>Tmin则x的非是-x.
    在位级表示上,求x的非的方法:书中提了2种方法,其实原理是一样的,反正x的非就是0-x,想象一下位级的减法:
    00000000   :向最高位借1 => 11111112
    xxxxxxxx            xxxxxxxx
    所以非最低位就是1-原值(0则是1,1则是0,即原值的非),而最低位则是2-原值,即1-原值后+1,这就是书中的方法一了。
    书中的方法二也可以推出:找到xxxxxxxx最右边的那个1,左边是原值的非,右边不用借位都保持0,自己的位借了2所以为1.

    13.无符号数的乘法和补码的乘法 都使用位数截断。
    判断乘法是否溢出可以用下面代码判断:
    int mul_ok(int x, int y)
    {
    int p = x*y;
    return !x || p/x == y;
    }
    x!=0情况的数学证明方法思路是x*y= a + t*2的w次方, b = a/x=>b*x + r = a,当b=y时,t=r=0:不溢出;b!=y时,t!=0溢出
    上面是补码乘法溢出判定,无符号数乘法溢出也类似

    也可以用先用更大的数据类型存结果,然后转为小数据类型,看相不相等:int x,y; long long int p = x*y; int q = (int)p;if (p!=q)溢出。

    14.乘以一个常数可以把常数换成2的幂的和,即把乘法换成移位和加法(减法)

    15.先不看浮点数相关,先看第3章:程序的机器级表示,第3章主要讲程序的汇编级别代码

  • 相关阅读:
    [cf 947E] Perpetual Subtraction
    loj3120. 「CTS2019 | CTSC2019」珍珠
    loj「LibreOJ NOI Round #2」不等关系
    loj6395. 「THUPC2018」城市地铁规划 / City
    loj2553. 「CTSC2018」暴力写挂
    loj6270. 数据结构板子题
    loj6358. 前夕
    loj6677. EntropyIncreaser 与菱形计数
    fiddler模拟接口响应数据
    Fiddler请求详解/autoResponseder重定向
  • 原文地址:https://www.cnblogs.com/Tearix/p/6917597.html
Copyright © 2011-2022 走看看