ch2 信息的表示与处理

整数

  • 数字都用有限的bits表示,整数是精确的,而浮点数大部分都是近似的。
  • 字节byte是最小的可寻址的内存单位。机器级程序将内存视为一个非常大的字节数组,称为虚拟内存,所有可能的地址集合称为虚拟地址空间。
  • 数据类型的大小依赖于程序是如何被编译的,为了避免依赖典型大小和不同编译器设置带来的奇怪行为,iso c99引入了数据大小固定的一类数据类型,如int32_t,int64_t。gcc –m32 hello.c, gcc –m64 prog.c。
  • 大部分数据类型都编码为有符号数值,除非有unsigned关键字。但是char是一个例外,c标准不保证char为有符号的。因此要使用有符号char的时候应该加上signed。
  • 大小端:大端高位字节放在低地址,和正常阅读顺序类似,小端模式相反。
    附上测试代码:
//1->bigEndian,2->smallEndian
int checkEndian(){
    int a = 0x12;
    char *pchar = (char*)&a;
    if (*pchar == 0x12) return 2;
    return 1;
}
  • 逻辑运算时,如果第一个参数就能确定表达式的结果,那么就不会继续下去,这就是短路原则。
  • 移位运算分为左移和右移,右移需要注意逻辑右移和算术右移,逻辑右移会在左侧补上k个0,而算术右移会在左端补上k个最高有效位的值。C标准没有明确定义使用哪种右移,尽管大部分编译器和机器都对有符号数使用算术右移,还是不能完全避免移植性问题,当移位的位数大于数据本身的位数时,c标准并没有说明应该怎么做,因此需要避免。
  • 无符号数的编码:
    这里写图片描述
  • 有符号数的编码:
    这里写图片描述
  • c标准没有要求使用补码来表示有符号整数,尽管几乎所有的机器都这么做,如果希望代码具有最大可移植性,除了下图所示范围,不应该假设任何 数值范围。Iso c99标准在文件stdint.h中引入一组数据类型,intN_t,uintN_t.
    这里写图片描述

  • 有符号数和无符号数的转换:对于大多数的c语言实现,处理同样字长的有符号数和无符号数之间相互转换的一般规则:数值可能会变,但是位模式不变。
    这里写图片描述
    这里写图片描述

  • 当一个数是有符号而另一个数是无符号的时,c语言会隐式地将有符号转换为无符号。

  • 当把short转换成unsigned时,先改变大小再从有符号到无符号,这是c标准要求的。
  • 运算
    这里写图片描述
    这里写图片描述

浮点数

  1. 定点表示法,0.5,0.25,0.125,0.0625,0.03125…
  2. IEEE浮点表示法,V = (-1)^s * M * 2^E,
    S决定这是一个负数还是一个正数,尾数m是一个二进制小数,范围是1~2-ε或者0~1-ε。阶码E对浮点数加权。
  3. 内存表示
    这里写图片描述
  4. 根据exp的值可以分为三种情况:

    • 规格化的:阶码不全为0或者1。阶码被解释为biased形式表示的有符号整数,即E = e –bias,其中e是无符号数,bias为2^(k-1)-1,因此对于单精度来说指数范围为-126~+127,注意正范围比负范围大。小数字段被解释为描述小数值f,0<=f<1,也即是说小数点在frac字段最高有效位的左边。位数M定义为1+f。由于第一位总是等于1,因此我们不需要显式的显示它。注意:最高有效位不是为1的最高位,以32位长度为例,不管他为不为1,32位长度的二进制串的最高有效位都是第31位。
    • 非规格化的值:当阶码全为0的时候,表示的数是非规格化的。E=1-bias,m=f。首先这提供了表示数值0的方法,因为当规格化的时候,m总是大于或者等于1的。+0.0的位表示全为0,当s为1时,得到-0.0.,两者在某些方面不同。还有另外一个功能,表示非常接近于0.0的数,提供一种属性,逐渐溢出
    • 特殊值:阶码全为1的时候,小数全为0代表无穷。小数不为0代表NaN,not a number。
  5. 尝试将3510593十进制转化为单精度浮点数:首先2进制为1101011001000101000001,然后将小数点左移21位得到1.101011001000101000001,由于frac段的长度为23,因此我们在后面添加两个0,而且第一个1不需要显示因此要去掉。得到frac字段为10101100100010100000100,阶码位数在单精度中为8,因此bias=2^7-1=127,E=e-bias=21,因此e等于148,二进制表示为10010100,再加上s为0,因此最终的浮点数表示为01001010010101100100010100000100。

  6. 注意,printf不会强制转换类型,尽管用了%u来输出float,因此输出不对。好像会转化成双精度,具体原因还要仔细调试才懂。

  7. 舍入方式:

    • 向偶数舍入,试图找到一个最接近的值,当值为两个可能结果的中间值的时候,向上或者向下舍入,使得结果的最低有效数字是偶数。
    • 向零舍入,正数向下舍入【3】,负数向上舍入【4】
  8. 向偶数舍入也可以应用到小数和二进制小数上。我们将最低有效位的值0认为是偶数,值1认为是奇数。只有xxxxxxx10这种位形式需要考虑,因为这才有中间值。

  9. 为什么1e10+3.14会舍入为1e10?
    二进制表示:1001010100000010111110010000000000,总共34位,因此需要移动向左移动33位得到1.001010100000010111110010000000000,去掉开头的1和多余的10位得到00101010000001011111001,bias为127,因此得到e=160,二进制表示为10100000,再加上s=0,得到最终二进制表示为01010000000101010000001011111001,十六进制表示为501502F9。发现最后的10个位都被截断了,因此3.14就没有了。

猜你喜欢

转载自blog.csdn.net/qq_15255105/article/details/72550906