深入理解计算机系统(第三版)作业题答案(第二章)

https://www.cnblogs.com/machao/p/8397961.html

我发现,当把这些题做完之后对本章知识的理解才算有点小进步。下边的答案主要参考了这两个网站: 

  1. http://blog.csdn.net/zhanyu1990/article/details/24936663
  2. https://dreamanddead.gitbooks.io/csapp-3e-solutions/chapter2

辅助函数:

#include <stdio.h>
#include <math.h>
#include <assert.h>
#include <limits.h>

unsigned f2u(float f)
{
  return *(unsigned *)&f;
}

float u2f(unsigned u)
{
  return *(float *)&u;
}

 

2.58


原理是把指向一个int类型的指针强行改为指向char类型,一般来说一个char占8位,这就能判断出来取出的值是否大于1

int is_little_endian(){
    int a = 1;
    return *((char*)&a);
}

2.59


这个比较简单,主要考察如何获取某些位。

(x&0xFF) | (y&~0xFF)

2.60

i << 3表示i * 2^3, 其原理是找出需要替换的那些位,然后将其替换掉就行了。

unsigned replace_byte(unsigned x, unsigned char b, int i)
{
    return (x & ~(0xFF<<(i<<3))) | (b << (i<<3));
}

位级整数编码规则


2.61


下边的内容跟书的题目有关系,需要根据实际情况。

A(!~x) // 比较简单,不解释
B(!x) // 同上
C(!~(x | (~0xFF))) // x的最低有效字节中的位都等于1
D(!(x >> ((sizeof(int) - 1) << 3))) // x的最高有效字节中的位都等于0

2.62

这个题我觉得在使用补码表示整数的机器上是没啥问题的

#include <stdio.h>

int int_shifts_are_arithmetic() {
    int i = -1;
    return (i >> 1) == -1;
}

int main(void) {
    printf("%d", int_shifts_are_arithmetic());
}

2.63

#include <stdio.h>

unsigned srl(unsigned x, int k) {
    int xsrl = (int)x >> k;
    int w = 8 * sizeof(int);

    unsigned z = 2 << (w - k -1);
    return (z - 1) & xsrl;
}

int sra(int x, int k) {
    int xsra = (unsigned)x >> k;
    int w = sizeof(int) << 3;

    unsigned z = 1 << (w - k - 1);
    unsigned mask = z - 1;

    unsigned right = xsra & mask;
    unsigned left = ~mask & (~(z & xsra) + z);

    return left | right;
}

int main(void) {
    unsigned t1 = srl(100, 2);
    unsigned t2 = (unsigned)100 >> 2;
    printf("%d----%d \n", t1, t2);

    int t3 = sra(100, 2);
    int t4 = 100 >> 2;
    printf("%d----%d \n", t3, t4);

    int t5 = sra(-100, 2);
    int t6 = -100 >> 2;
    printf("%d----%d \n", t5, t6);
}

2.64

// 该题目要求,只要奇数位有1,就返回1,否则返回0

#include <stdio.h>
/* Return 1 when any odd bit of x equals 1, 0 otherwise.
   Assume w = 32.
*/
int any_odd_one(unsigned x) {
    return !!(x & 0x55555555);
}

int main(void) {
    int result = any_odd_one((unsigned)5);
    printf("The result of 5: %d \n", result);

    int result1 = any_odd_one((unsigned)2);
    printf("The result of 2: %d \n", result1);
}

2.65

// 该题目要求,只要二进制书中1的个数为奇数,就返回1,否则返回0


#include <stdio.h>
/* Return 1 when x contains an odd nuimber of 1s, 0 otherwise.
   Assume w = 32.
*/
int odd_ones(unsigned x) {
    // 这是第一层的处理,对某一位i而言,通过右移了一位,我们就获取到了i前边的那一位,把他们异或后,
    // 得到的位的值为0或者1,1就表示和前边的一位中有奇数个1,0表示有偶数个1.
    x ^= (x >> 1);

    // 经过上边的处理后呢,x中每一位的值的意义就不同了,他表示该位和它前边的位1的个数是奇数还是偶数
    //  此时我们再右移2位,就获得了i前边的前边的值j,这个值j表示j和前边一位1的个数是奇数还是偶数
    //  异或后,的值就便是到j前边,一共四位1的个数是奇数还是偶数
    x ^= (x >> 2);

    // 后面的都是按照上边的原理依次类推的

    x ^= (x >> 4);
    x ^= (x >> 8);
    x ^= (x >> 16);
    return x & 1;
}

int main(void) {
    int result = odd_ones((unsigned)5);
    printf("The result of 5: %d \n", result);

    int result1 = odd_ones((unsigned)7);
    printf("The result of 3: %d \n", result1);
}

2.66

#include <stdio.h>
#include <assert.h>

// 1. 先使用或加位移让第一个1的后边都是1
// 2. 然后取非后右移一位后,最右边的1就是我们想要的掩码
// 3. 由于上边得到的那个1就是原值中的第一个1的位置,因此&上原值就清空了1前边的位
int leftmost_one(unsigned x) {
    x |= x >> 1;
    x |= x >> 2;
    x |= x >> 4;
    x |= x >> 8;
    x |= x >> 16;

    return x & (~x >> 1);
}

int main(void) {
    assert(leftmost_one(0xff00) == 0x8000);
    assert(leftmost_one(0x6600) == 0x4000);
    return 0;
}

2.67

#include <stdio.h>
#include <assert.h>

int int_size_is_32() {
    int set_msb = 1 << 31;
    int beyond_msb = set_msb << 1;

    return set_msb && !beyond_msb;
}

int int_size_is_32_for_16bit() {
    int set_msb = 1 << 15 << 15 << 1;
    int beyond_msb = set_msb << 1;

    return set_msb && !beyond_msb;
}

int main(void) {
    printf("1: %lu \n", sizeof(1));
    printf("32: %d \n", int_size_is_32());
    printf("16: %d \n", int_size_is_32_for_16bit());
}

2.68

#include <stdio.h>
#include <assert.h>

int lower_one_mask(int n) {
    int w = sizeof(int) << 3;
    return (unsigned)-1 >> (w - n);
}

int main(void) {
    assert(lower_one_mask(6) == 0x3F);
    assert(lower_one_mask(17) == 0x1FFFF);
    assert(lower_one_mask(32) == 0xFFFFFFFF);
    return 0;
}

2.69

#include <stdio.h>
#include <assert.h>

unsigned rotate_left(unsigned x, int n) {
    int w = sizeof(int) << 3;
    unsigned t = x << n;
    unsigned t1 = x >> (w - n - 1) >> 1;
    return t | t1;
}

int main(void) {
    assert(rotate_left(0x12345678, 4) == 0x23456781);
    assert(rotate_left(0x12345678, 20) == 0x67812345);
    assert(rotate_left(0x12345678, 0) == 0x12345678);
    return 0;
}

2.70

#include <stdio.h>
#include <assert.h>

// 如果x的二进制可以用n位表示就返回1,
/*
   * Assume w = 8, n = 3
   * if x > 0
   *   0b00000110 is ok, 0b00001010 is not
   *   first w-n bits must be 0
   * if x < 0
   *   0b11111100 is ok, 0b10111100 is not, and 0b11111000 is not yet
   *   first w-n+1 bits must be 1
   */
int fits_bits(int x, int n) {
    int w = sizeof(int) << 3;
    x >>= n - 1;

    /*
     * !(x >> 1) 用于判断x大于0的情况
     * !~x 用于判断x小于0的情况
     */
    return !(x >> 1) || !~x;
}

int main(void) {
  
  • 12
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值