计算机系统基础作业一

2512 字
7 分钟

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抹零的片段
#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是奇数还是偶数

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

#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位

#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会从正数变为复数,我们根据这一条件进行判断,写出代码:

#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

#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