计算机系统基础作业一

2.60

1728872275676

看到这个体题我的思路如下:

  1. 先将x中需要替换的部分全都改成0
    1. 创建一个临时变量 tmp = 0x000000FF
    2. 通过向左位移运算右侧补0,将FF字节移到指定的位置
    3. tmp取反,此时 tmp = 0xFF00FFFF
    4. 通过且运算将x中对应字节抹零
  2. 将b转化为unsigned类型,并且左移,让有效数据位与x抹零的部分对其
  3. 通过或预算将b中的有效数据位赋给x抹零的片段
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>

unsigned replace_byte (unsigned x,int i,unsigned char b)
{
//先将x的需要替换的部分全都抹零
unsigned tmp = (0x000000FF);
tmp = tmp << i*8;
tmp = ~tmp;
x = x & tmp;
//再把b的数据转移的合适的位置上通过或预算放到x中
x = x |((unsigned)b) << i*8;
return x;
}

int main()
{
unsigned x = 0x12345678; //以16进制初始化x
int i = 2;
unsigned char b = 0xAB; //以16进制初始化b
printf("replace_byte(0x%08X,%d,0x%02X) = 0x%08X\n",x,i,b,replace_byte(x,i,b));
return 0;
}

代码运行结果如下:

1728876245423

1728876249956

2.65

1728876133682

这道题我们先思考一下:

  1. 要计算32位中一的个数,我们可以分别计算前16位的1的个数+后16位1的个数。
  2. 计算16位1的个数,可以同样分为8+8
  3. 再次划分,我们分为4+4
  4. 然后我们分为2+2
  5. 最后我们分为1+1

这样我们只需要先计算每位中1的个数,再逐级倒退,得到32 位中1的个数

好这样针对每两位中1的个数我们就可以如下实现:

我们假设一个两位的二进制数为x

其中的1的个数为:(x & 1) + ((x>>1) & 1) //将x的两位分别和1进行与运算,结果相加得到1的个数

然后我们再计算每4位中1的个数:(x & 11) + ((x>>2) &11) //4位数中前两位中1的个数+后两位1的个数

接下来同理得到8位中1的个数:(x & 1111) + ((x>>4) & 1111)

同理得16位:(x & 11111111) + ((x>>8) & 11111111)

最后我们就可以得到32位:(x & 1111111111111111) + ((x>>16) + 1111111111111111)

最后我们通过x & 1 来判断x是奇数还是偶数

根据以上思路给出代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include<stdio.h>

int odd_ones(unsigned x)
{
//合并每相邻2位的1的个数
x = (x & 0x55555555) + ((x >> 1) & 0x55555555);
//再合并每相邻4位1的个数
x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
//合并每相邻8位的1的个数
x = (x & 0x0F0F0F0F) + ((x >> 4) & 0x0F0F0F0F);
//合并每相邻16位的1的个数
x = (x & 0x00FF00FF) + ((x >> 8) & 0x00FF00FF);
//得到32位的1的个数
x = (x & 0x0000FFFF) + ((x >> 16) & 0x0000FFFF);
return x & 1 ;
}
int main()
{
int x = 0x10101011;
printf("%d\n", odd_ones(x));
return 0;
}

程序运行结果如下:x = 0x10101011

1728897083037

2.67

1728905974271

我们先来分析报错:left shift count >= width of type 左移位数大于或等于类型的宽度

A).代码第6行 1 << 32如果在32位机器上运行,将1左移32位会让1被移到第33位上,但33位并不存在,超出了类型的宽度。

B).当机器位数>= 32时,我们可以位操作的范围是:0~31。并且题目右移为算数右移,那么我们可以通过将 1 << 31移至符号位,再通过算数右移,此时通过判断beyond的大小来判断机器int是否为32位

1
2
3
4
5
6
7
8
9
10
11
12
13
#include<stdio.h>

int bad_int_sizeis_32(){
int set_msb = 1 << 31 ; //左移31位,将1移到符号位上
int beyond_msb = set_msb >> 31; // 算术右移31位,检查符号位是否保持不变
return beyond_msb == -1; //确保机器位数等于32
}

int main()
{
printf("%d\n", bad_int_sizeis_32());
return 0;
}

C). 当1被左移到符号位时,x会从正数变为复数,我们根据这一条件进行判断,写出代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<stdio.h>

int bad_int_sizeis_32(){
int x = 1;
int count = 1;

// 逐步左移,直到最高位被设置
while (x > 0) {
x <<= 1;
count++;
}
// 如果位宽为32,则返回1,否则返回0
return count == 32;
}

int main()
{
printf("%d\n", bad_int_sizeis_32());
return 0;
}

2.68

1728908942648

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include<stdio.h>

int lower_one_mask(int n)
{
int x = -2;
x = x << n-1; // 使用 n & 31 确保移位位数在 0 到 31 之间
x = ~x;
return x;
}
int main()
{
int n = 1;
while(n!=-1)
{
printf("请输入n的值:");
scanf("%d",&n);
printf("%X\n",lower_one_mask(n));
}
return 0;
}

n>=1 ,所以令x = -2,让 x 每左移n-1位,最后给x取反,就能得到做多1的n bits 的数,就能避免一次位移32位的情况。

结果如下:

1728912863650


计算机系统基础作业一
http://blog.ulna520.com/2024/10/14/第一次作业/
Veröffentlicht am
October 14, 2024
Urheberrechtshinweis