深入理解计算机系统(第二章)

信息的标识和处理

大家可以先对我所提出来的问题进行思考,然后下面会有对应的答案仅供参考,如答案有误欢迎大家评论指正。

问题1

下表中的内容大家或多或少都有所了解,但是有没有想过 为什么 有符号的最小值比最大值绝对值要大1呢?

image-20230612231141509

问题2

还是上表中,对比 int8 与 uint的max范围,为什么 max(int8) * 2 + 1 = max(uint8)呢?

问题3

// 1
for i := 5; i >= 0; i-- {
   fmt.Println(i)
}
// 2
var i uint8
for i = 5; i >= 0; i-- {
	fmt.Println(i)
}
// 1 与 2 的结果是什么? 为什么会这样?

问题4

200 * 300 * 400 * 500 = -884901888 负数(溢出)

问题5

浮点运算不能结合 例如

(3.14 + 1e20)- 1e20 = 0.0

3.14 + (1e20 - 1e20) = 3.14

问题6

程序本质是什么?

问题7

怎么使程序对不同的数据类型的确切大小不敏感

问题8

整型

12345 -> 0x 00003039

二进制:0000 0000 0000 0000 0011000000111001

浮点型

12345 —-> 0x4640E400

二进制: 0100 0110 0100000011100100 0000 0000

为什么有这么多位相等?

问题9

为什么右移运算 区分 逻辑右移和算数右移?左移为什么不区分?

问题10

当我们做强制类型转换,计算机层面做了什么?同时 小转大?大转小? 计算机层面分别有什么操作?

问题11

为什么两个正数相加可能为负?

问题12

当x < y时, x - y >0 为什么?

问题13

我们都了解 x * 2 ^ k = x << k; x / 2^k = 2 >> k, 那么思考下面的代码

	fmt.Println(5 / 2)
	fmt.Println(-5 / 2) 
	fmt.Println(5 >> 1)
	fmt.Println(-5 >> 1)
	fmt.Println(((-5 + 1<<1) - 1) >> 1)

问题14

IEEE浮点格式中数字的表示?

问题15

为什么小数不能精确表示某些值?

#include <stdio.h>
int main(void)
{
    float f1=34.6;
    float f2=34.5;
    float f3=34.0;
    printf("34.6-34.0=%f\n",f1-f3); // 0.599998
    printf("34.5-34.0=%f\n",f2-f3); // 0.500000
    return 0;
}

答案1

首先我们要知道计算机中的所有数据都是二进制,之后想想负数用二进制是如何进行表示的?

例如我们使用 5个二进制位(也就是字长为 5,字长我们使用w来进行表示)来表示有符号数和无符号数的最大最小值

无符号数

  • 最小值,很容易想到便是将所有位都变为 0
    • 0 0 0 0 0 —————–> 0
  • 最大值,那便是将所有的位都变为 1
    • 1 1 1 1 1 ——————> 16 + 8 + 4 +2 + 1 = 31 ————> 2 ^ w - 1

有符号数

  • 最小值,因为我们有符号因此需要考虑符号位,可能为负数的情况,因此有符号数的最小值就是最大负数,也就是符号位为1,其它位为0
    • 1 0 0 0 0 ——————> -16 ——————–> -2 ^ (w - 1)
  • 最大值,便是符号位为0其它位为1的情况
    • 0 1 1 1 1 ——————> 8 + 4 + 2 + 1 = 15 ————–> 2 (w - 1) - 1

因此我们便知道的为什么有符号的最小值绝对值要比最大值大1

答案2

还是沿用上面的5个2进制位来解释原因

无符号数

最大值,那便是将所有的位都变为 1

  • 1 1 1 1 1 ——————> 16 + 8 + 4 +2 + 1 = 31 ————> 2 ^ w - 1

有符号数

最大值,便是符号位为0其它位为1的情况

  • 0 1 1 1 1 ——————> 8 + 4 + 2 + 1 = 15 ————–> 2 (w - 1) - 1

我们将有符号数 * 2 也就是左移 1位

0 1 1 1 1 ——–左移1位—–> 0 1 1 1 1 0 ————- + 1 ———> 0 1 1 1 1 1(无符号数的最大值)

结论 Umax = 2 * Tmax + 1

答案3

结果

1: 正常执行结束

2: 无限循环

原因

无符号数最小值是 0,因此for循环永远不会结束,同时当 无符号数 变成 0 0 0 0 0 - 1 会变为 1 1 1 1 1 无符号数的最大值,代码中千万小心。

答案4

主要是因为正数都是使用有限的二进制位表示,因此当超出之后位数后,会发生截断,只保留n位,然后解释为新的补码,最高位是1则解释为负数,例如:

w=8: 127 + 1 = 128 = 1 0000000, 最高位是1,解释为负数的补码, 负数补码到原码(按位取反+1) 因此,10000000 的补码取反后是 01111111,加上 1 后是 10000000 即 -128。因此,溢出后的结果是 -128,而不是 128。

答案5

也是因为浮点数无法精确表示二进制小数,导致 (a + b) + c 有可能不等于 a + (b + c),例如 (0.1 + 0.2) + 0.3 由于 0.1、0.2、0.3无法精确表示为 二进制小数,可能发生舍入问题,因此可能导致 (0.1 + 0.2) + 0.3 有可能不等于 0.1 + (0.2 + 0.3)

答案6

本质只是字节序列

答案7

设定对应数据类型的取值范围,同时不能假设任何可表示的数值范围,不应假设有符号数会使用何种特殊的表示方式,因为几乎所有机器都是采用补码来表示有符号数。

答案8

因为浮点数采用 IEEE规范表示,正数构造IEEE浮点数,浮点数的小数高位置为 整数的低位

例如 12345 0000 0000 0000 0000 0011000000111001

构造单精度 小数位 则去除最高位1,然后补充10个0,即为他的小数位,

10的原因是 单精度在32bit下,IEEE表示 S = 1 E = 8 M = 23(填充的0则是填补23位剩余部分)

image-20230716205553650

答案9

1.1 为什么右移区分算术右移和逻辑右移

主要原因在于 有符号数 负数符号位为 1,右移是在前面补x值,因此可能造成负数变成正数

1.2 因为左移运算都是后面直接补0,不会影响正负,同时算术左移和逻辑左移都是相同的结果,因此没必要区分。

答案10

小转大

例如 4bit —> 8bit,分为两种情况,无符号数和补码

无符号数

零扩展: 例如: 1 0 1 1 —–> 0 0 0 0 1 0 1 1 算出来值都是相同,也就是我们强转后值不变

补码

符号位扩展: 例如 1 0 1 1(-8 + 2 + 1 = -5) ——-> 1 1 1 1 1 0 1 1(-128 + 64 + 32 + 16 + 8 + 2 + 1 = -5),值同样不变

大转小

例如 8bit —-> 4bit,分为两种情况无符号数和补码

截断无符号数: 例如:1 0 0 0 1 0 1 1 (128 + 8 + 2 + 1 = 139) ——-> 1 0 1 1(8 + 2 + 1 = 11) = 139 % 2 ^ 4 = 11

截断补码:例如 1 0 0 0 1 0 1 1 (-128 + 8 + 2 + 1 = -117) ———-> 1 0 1 1(-8 + 2 + 1 = -5) = -117 % 2 ^ 4 = -5

答案11

因为计算机中采用补码进行加减法,补码加减法便有 Tmin Tmax

当 x+y >= 2 ^ (w-1) = x + y - 2 ^w (发生正溢出)

例如 w = 4,下面列子都是w = 4为例

5 + 5 = 10 => 0 1 0 1 + 0 1 0 1 = 0 1 0 1 0, 因为我们w = 4,因此进行截断 => 1 0 1 0 = > -8 + 2 = -6

x + y < -2 ^ (w - 1) = x + y + 2 ^ w (发生负溢出)

-8 + (-5) => 1 0 0 0 + 1 0 1 1 => 0 0 0 1 1,截断 => 0 0 1 1 => 2 + 1 = 3

当 -2^(w - 1) <= x + y <= 2 ^ (w - 1) = x + y

-8 + 5 => 1 0 0 0 + 0 1 0 1 = 1 1 0 1 => 不用截断 => -8 + 4 + 1 = -3

2 + 5 => 0 0 1 0 + 0 1 0 1 = 0 1 1 1 = 不用截断 => 2 + 5 = 7

答案12

同上 x - y = x + (-y)

例如 x = -8 y = 5,w = 4, -8 < 5, -8 - 5 > 0

-8 + (-5) => 1 0 0 0 + 1 0 1 1 => 0 0 0 1 1,截断 => 0 0 1 1 => 2 + 1 = 3

答案13

我们所了解的不错,但是是有一定的限制范围的,我们了解的 在 无符号数 以及正数确实是这样,因为无符号数 使用逻辑右移补0,正数虽然使用算是右移但是也是补0,因此对于结果没有影响

但是在计算机中负数采用的算数右移,因此最高位补1,这样算出来的结果对于某些 除不尽 2^k的负数。便有一定的差异

-5 >> 1 = 1 0 1 1(-8 + 2 + 1) = 1 1 0 1(-8 + 4 + 1) = -3

还有就是移位操作 向下舍入正数,向上舍入负数,如果是整数则是整数

例如 5 / 2 = 2.5 ==> 2 -5 / 2 = -2.5 = -3

为了避免这种错误的舍入方式与算术移位方式,我们可以在移位之前进行”偏置“(增加偏移量,例如向右移动k位,那么偏移量为 (2 ^ k) - 1)

例如上述的 -5 算数右移 1位出现了错误,因此进行偏置(k = 1; 2 - 1 = 1) => 1 0 1 1 + 0 0 0 1 => 1 1 0 0

算术右移一位 1 1 0 0 >> 1 = 1 1 1 0 => -8 + 4 + 2 = -2

-4 算术右移 = - 4 + 1 = -3 = 1 1 0 1 >> 1 = 1 1 1 0 = -2 (不会影响)

答案14

V=(-1) ^ s(符号决定正负) * M(尾数,二进制小数) * 2 ^ E(阶码浮点加权)

答案15

因为浮点数遵循IEEE规范 例如需要 x * 2 ^ y,34.6 无法用二进制准确表示,因此只能近似表示,所以产生了上述结果

学习笔记

符号扩展思想

有符号数 符号扩展不影响原值

1 1 1 0 (-2)(当我们进行符号扩展)

1 1 1 1 0 (-2)

截断思想

无符号数: 保留几位(w) = 原数 mod 2 ^ w

有符号数: 保留几位(w) = 原数的无符号数 mod 2 ^ w

1 1 0 1 有符号数 -3 无符号数 13

1 1 1 0 有符号数 -2 无符号数 14

13 * 14 = 0xb6 取最低位 6 = 0 1 1 0

-3 * -2 = 6

左移右移原理

x = ∑ x * 2 ^ 0 ——> 左移 1 ——> x = ∑ x* 2 ^ (0 + 1) = 2 * ∑ x * 2 ^ 0

虚拟内存

机器级程序将程序视为一个很大的字节数组,称为虚拟内存

虚拟内存地址

内存中的每个字节都由一个唯一的数字标识,称为地址,所有可能的地址的集合称为虚拟地址空间

舍入

向偶数舍入

将数字向上或者是向下舍入,保证结果最低有效数字是偶数

向零舍入

正数向下舍入,负数向上舍入(去除小数部分保留整数部分)

向下舍入

正数负数都向下舍入

向上舍入

正数负数都向上舍入

方式1.401.601.502.50-1.50
向偶数舍入1222-2
向零舍入1112-1
向下舍入1112-2
向上舍入2223-1

float、double向int强转

使用向零舍入

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值