美文网首页
深入理解计算机操作系统第二章家庭作业

深入理解计算机操作系统第二章家庭作业

作者: Leonzai | 来源:发表于2019-03-25 12:39 被阅读0次

    2.55 编译运行下列代码,并且确定机器字节顺序。

    #include <stdio.h>
    
    typedef unsigned char *byte_pointer;
    
    void show_bytes(byte_pointer start, size_t len) {  // size_t == unsigned 8bit integer
        size_t i;
        for (i = 0; i < len; ++i) {
            printf("%.2x ", start[i]);
        }
        printf("\n");
    }
    
    void show_int(int x) {
        show_bytes((byte_pointer) &x, sizeof(int));
    }
    
    void show_float(float x) {
        show_bytes((byte_pointer) &x, sizeof(float));
    }
    
    void show_pointer(void *x) {
        printf("x's address value is [%p] \n", x);
        show_bytes((byte_pointer) &x, sizeof(void *));
    }
    
    void test_show_bytes(int val) {
        int ival = val;
        float fval = (float) ival;
        int *pval = &ival;
        show_int(ival);
        show_float(fval);
        show_pointer(pval);
    }
    
    int main(void) {
        int test_number = 1234;
        test_show_bytes(test_number); // 1234 == 100 1101 0010 == 00 00 04 d2(大端) == d2 04 00 00 (小端)
        return 0;
    }
    

    我的机器是小端顺序,intel 基本上都是小端。

    为什么 byte_pointer 使用 unsigned char * (而不是 char *)?

    #include <stdio.h>
    
    int main()
    {
        char c = 129;// 1000 0001      11111111 1000 0001
        char unsigned uc = 129;
        printf("%d\n", c);
        printf("%x\n", c);
        printf("%d\n", uc);
        printf("%x\n", uc);
        return 1;
    }
    
    /* 输出
    -127
    ffffff81
    129
    81
     * /
    

    2.56 试着用不同示例值运行上面的代码。

    同上。

    2.57 同上面一样去编写程序 show_short, show_long, show_double 并运行。

    #include <stdio.h>
    
    typedef unsigned char *byte_pointer;
    
    void show_bytes(byte_pointer start, size_t len) {
        size_t i;
        for (i = 0; i < len; ++i) {
            printf("%.2x ", start[i]);
        }
        printf("\n\n");
    }
    
    void show_short(short x) {
        show_bytes((byte_pointer) &x, sizeof(short));
    }
    
    void show_long(long x) {
        show_bytes((byte_pointer) &x, sizeof(long));
    }
    
    void show_double(double x) {
        show_bytes((byte_pointer) &x, sizeof(double));
    }
    
    void test_show_bytes(int ival) {
        short sval = (short) ival;
        long lval = (long) ival;
        double dval = (double) ival;
        show_short(sval);
        show_long(lval);
        show_double(dval);
    }
    
    int main(void) {
        test_show_bytes(0x12345678);
        return 0;
    }
    
    78 56
    
    78 56 34 12
    
    00 00 00 78 56 34 b2 41
    

    2.58 编写 is_little_endian 函数判断大端还是小端,返回 0 和 1。

    #include <stdio.h>
    
    int main() {
        int i = 65538; // 00000000 00000001 00000000 00000010
        unsigned char *j = (unsigned char *) &i;
    
        if (*j == 2) {
            printf("1");
            return 1;   // little endian
        }
        printf("0");
        return 0;
    }
    

    2.59 编写程序返回 x 的最低有效字节,和 y 中剩下的字节。

    #include <stdio.h>
    
    int main() {
        int i = 65538; // 0x10002
        int j = 12345; // 0x3039
        printf("%x", (i & 0xff) | (j & ~0xff));
        return 1;
    }
    

    2.60 将字节从 0 开始编号,写出函数实现将参数 x 的字节 i 被替换成字节 b。

    #include <stdio.h>
    #include <assert.h>
    
    int replace_byte(unsigned x, unsigned char i, unsigned char b) {
        return ((-1 - (0xff << (i  << 3))) & x) | (b<<(i<<3));
    }
    
    int main() {
        unsigned rep_0 = replace_byte(0x12345678, 0, 0xAB);
        unsigned rep_3 = replace_byte(0x12345678, 3, 0xAB);
    
        assert(rep_0 == 0x123456AB);
        assert(rep_3 == 0xAB345678);
        return 1;
    }
    

    2.61

    #include <stdio.h>
    
    int get_msb(int x) {
        return ((!x)
                | (!(~x))
                | (!((~(x & 0xff)) & 0xff)) 
                | (!(x >> ((sizeof(x) - 1)<<3 ))));  
    }
    
    int main() {
        printf("%d", get_msb(0xff));
        printf("%d", get_msb(0));
        printf("%d", get_msb(0x11ff));
        printf("%d", get_msb(0xff00));
        printf("%d", get_msb(0xffff00));
        return 1;
    }
    

    2.62

    #include <stdio.h>
    
    int main() {
        int a = -1;
        int res = !(~(a >> 1));
        printf("%d", res);
        return 1;
    }
    

    2.63

    #include <stdio.h>
    
    unsigned srl(unsigned x, int k) {
        unsigned xsra = (int) x >> k;
        return (~(-1 << ((sizeof(int) << 3) - k))) & xsra;
    }
    
    int main() {
        unsigned a = 0xffffffff;
        unsigned v = srl(a, 3);
        printf("%x", v);
        return 1;
    }
    
    #include <stdio.h>
    
    unsigned sra(int x, int k) {
        unsigned xsrl = (unsigned) x >> k;
        int bits = sizeof(int) << 3;
        return (-!!(1 << (bits - 1) & x)) << (bits - k) | xsrl;
    }
    
    int main() {
        unsigned a = 0xffffffff;
        unsigned v = sra(a, 15);
        printf("%x", v);
        return 1;
    }
    

    2.64

    #include <stdio.h>
    
    int any_odd_one(unsigned x) {
        return !!(x & 0xaaaaaaaa);
    }
    
    int main() {
        unsigned a = 0x5;
        int b = any_odd_one(a);
        printf("%d", b);
        return 1;
    }
    

    2.55

    #include <stdio.h>
    #include <assert.h>
    
    int odd_ones(unsigned x) {
        x ^= x >> 16;
        x ^= x >> 8;
        x ^= x >> 4;
        x ^= x >> 2;
        x ^= x >> 1;
        x &= 0x1;
        return x;
    }
    
    int main(int argc, char *argv[]) {
        assert(odd_ones(0x10101011));
        assert(!odd_ones(0x01010101));
        return 0;
    }
    

    2.66

    #include <stdio.h>
    #include <assert.h>
    
    unsigned left_most_one(unsigned x) {
        x |= x >> 1;
        x |= x >> 2;
        x |= x >> 4;
        x |= x >> 8;
        x |= x >> 16;
        return (x + 1) >> 1;
    }
    
    int main() {
        assert(left_most_one(0xff00) == 0x8000);
        assert(left_most_one(0x6600) == 0x4000);
        return 1;
    }
    

    2.67

    1. c11 标准指出:如果右移的位数为负数,或者左移的位数大于等于数值宽度,则结果在标准中未定义。
    2. 和 3.
    #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(int argc, char *argv[]) {
        assert(int_size_is_32());
        assert(int_size_is_32_for_16bit());
        return 0;
    }
    

    2.68

    #include <stdio.h>
    #include <assert.h>
    
    int lower_one_mask(int n) {
        return ~(-1 << n);
    }
    
    int main() {
        assert(lower_one_mask(6) == 0x3f);
        assert(lower_one_mask(17) == 0x1ffff);
        return 1;
    }
    

    2.69

    #include <stdio.h>
    #include <assert.h>
    
    unsigned rotate_left(unsigned x, int n) {
        return (x << n) | (x >> ((sizeof(x) << 3) - n));
    // 这么写不对,考虑 n = w 的情况,左移位数等于数值宽度,在 c 标准中未规范
    // return (x << (n-1)<<1) | (x >> ((sizeof(x) << 3) - n));
    }
    
    int main() {
        assert(rotate_left(0x12345678, 4) == 0x23456781);
        assert(rotate_left(0x12345678, 20) == 0x67812345);
        assert(rotate_left(0x12345678, 0) == 0x12345678);
        return 1;
    }
    

    2.70

    #include <stdio.h>
    #include <assert.h>
    
    int fits_bits(int x, int n) {
        int spare = (sizeof(int) << 3) - n;
        return x == (x << spare >> spare);
    }
    
    int main(int argc, char *argv[]) {
        assert(!fits_bits(0xFF, 8));
        assert(!fits_bits(~0xFF, 8));
    
        assert(fits_bits(0b0010, 3));
        assert(!fits_bits(0b1010, 3));
        assert(!fits_bits(0b0110, 3));
    
        assert(fits_bits(~0b11, 3));
        assert(!fits_bits(~0b01000011, 3));
        assert(!fits_bits(~0b111, 3));
        return 0;
    }
    

    2.71

    书本答案未曾考虑到算术右移。

    #include <stdio.h>
    #include <assert.h>
    
    typedef unsigned packed_t;
    
    int xbyte(packed_t word, int byteNum) {
        packed_t a = (word >> (bytenum << 3)) & 0xff;
        return -(a >> 7) << 8 | a;
    }
    
    int main(int argc, char *argv[]) {
        assert(0x0000000f == xbyte(0x00000f00, 1));
        assert(0xffffffff == xbyte(0x0000ff00, 1));
        assert(xbyte(0xAABBCCDD, 1) == 0xFFFFFFCC);
        assert(xbyte(0x00112233, 2) == 0x11);
        return 0;
    }
    

    2.72

    #include <stdio.h>
    #include <assert.h>
    #include <string.h>
    #include <stdlib.h>
    
    void copy_int(int val, void *buf, int maxbytes) {
        if (maxbytes >= (int) sizeof(val)) {
            memcpy(buf, (void *) &val, sizeof(val));
        }
    }
    
    int main() {
        int a = 0x12345678;
        unsigned maxbytes = sizeof(int);
        void *buf = malloc(maxbytes);
    
        copy_int(a, buf, maxbytes);
        assert(0x12345678 == *(int *) buf);
        int b = 0xffffffff;
        copy_int(b, buf, 0);
        assert(0x12345678 == *(int *) buf);
        assert(0xffffffff != *(int *) buf);
    
        return 1;
    }
    

    2.73

    #include <stdio.h>
    #include <assert.h>
    #include <limits.h>
    
    int saturating_add(int x, int y) {
        int sum = x + y;
        int min = INT_MIN;
        int neg_over = (min & x) && (min & y) && !(min & sum);
        int poa_over = !(min & x) && !(min & y) && (min & sum);
        (negOver && (sum = INT_MIN)) || (posOver && (sum = INT_MAX));
        return sum;
    }
    
    int main(int argc, char *argv[]) {
        assert(INT_MAX == saturating_add(INT_MAX, 0x1234));
        assert(INT_MIN == saturating_add(INT_MIN, -0x1234));
        assert(0x11 + 0x22 == saturating_add(0x11, 0x22));
        return 0;
    }
    

    2.74

    #include <stdio.h>
    #include <assert.h>
    #include <limits.h>
    
    int tsub_ok(int x, int y) {
        int a = (!!(INT_MIN & x)) && (y == -y);
        int b = !((!!(INT_MIN & x)) ^ (!!(INT_MIN & y)));
        return a || b;
    }
    
    int main(int argc, char *argv[]) {
        assert(!tsub_ok(1, INT_MIN));
        assert(tsub_ok(1, 3));
        assert(tsub_ok(-1, INT_MIN));
        assert(!tsub_ok(0x00, INT_MIN));
        assert(tsub_ok(0x00, 0x00));
        return 0;
    }
    

    2.75

    #include <stdio.h>
    #include <assert.h>
    #include <inttypes.h>
    #include <limits.h>
    
    int signed_high_prod(int x, int y) {
        int64_t mul = (int64_t) x * y;
        return mul >> 32;
    }
    
    unsigned unsigned_high_prod(unsigned x, unsigned y) {
        int sig_x = x >> 31;
        int sig_y = y >> 31;
        int signed_prod = signed_high_prod(x, y);
        return signed_prod + x * sig_y + y * sig_x;
    }
    
    unsigned another_unsigned_high_prod(unsigned x, unsigned y) {
        uint64_t mul = (uint64_t) x * y;
        return mul >> 32;
    }
    
    int main(int argc, char *argv[]) {
        unsigned x = 0x12345678;
        unsigned y = 0xffffffff;
        assert(another_unsigned_high_prod(x, y) == unsigned_high_prod(x, y));
        assert(signed_high_prod(x, y) != unsigned_high_prod(x, y));
        return 0;
    }
    

    2.76

    #include <stdio.h>
    #include <assert.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <string.h>
    
    void *another_calloc(size_t nmemb, size_t size) {
        if (nmemb == 0 || size == 0) {
            return NULL;
        }
    
        size_t buf_size = nmemb * size;
        if (nmemb == buf_size / size) {
            void *ptr = malloc(buf_size);
            memset(ptr, 0, buf_size);
            return ptr;
        }
        return NULL;
    }
    
    int main(int argc, char *argv[]) {
        void *p;
        p = another_calloc(0x1234, 2);
        assert(p != NULL);
        free(p);
    
        p = another_calloc(SIZE_MAX, 2);
        assert(p == NULL);
        free(p);
        return 0;
    }
    

    2.77

    #include <stdio.h>
    #include <assert.h>
    
    int A(int x) {
        return (x << 4) + x;
    }
    
    int B(int x) {
        return x - (x << 3);
    }
    
    int C(int x) {
        return (x << 6) - (x << 2);
    }
    
    int D(int x) {
        return (x << 4) - (x << 7);
    }
    
    int main(int argc, char *argv[]) {
        int x = 0x87654321;
        assert(A(x) == 17 * x);
        assert(B(x) == -7 * x);
        assert(C(x) == 60 * x);
        assert(D(x) == -112 * x);
        return 0;
    }
    

    2.78

    #include <stdio.h>
    #include <assert.h>
    #include <limits.h>
    
    int divide_power2(int x, int k) {
        int is_neg = x & INT_MIN;
        (is_neg && (x = x + (1 << k) - 1));
        return x >> k;
    }
    
    int main(int argc, char* argv[]) {
        int x = 0x80000007;
        assert(divide_power2(x, 1) == x / 2);
        assert(divide_power2(x, 2) == x / 4);
        return 0;
    }
    

    2.79

    #include <stdio.h>
    #include <limits.h>
    #include <assert.h>
    
    int div(int x, int k) {
        int is_neg = x & INT_MIN;
        is_neg && (x = x + (1 << k) - 1);
        return x >> k;
    }
    
    int mul3div4(int x) {
        return div((x << 2) - x, 2);
    }
    
    int main(int argc, char *argv[]) {
        int x = 0x87654321;
        assert(mul3div4(x) == x * 3 / 4);
        return 0;
    }
    

    2.80

    #include <stdio.h>
    #include <limits.h>
    #include <assert.h>
    
    int threeforths(int x) {
        int is_neg = x & INT_MIN;
        int f = x & ~0x3;
        int l = x & 0x3;
    
        int fd4 = f >> 2;
        int fd4m3 = (fd4 << 1) + fd4;
    
        int lm3 = (l << 1) + l;
        int bias = (1 << 2) - 1;
        (is_neg && (lm3 += bias));
        int lm3d4 = lm3 >> 2;
    
        return fd4m3 + lm3d4;
    }
    
    int main(int argc, char *argv[]) {
        assert(threeforths(0) == 0);
        assert(threeforths(1) == 0);
        assert(threeforths(2) == 1);
        assert(threeforths(3) == 2);
        assert(threeforths(8) == 6);
        assert(threeforths(9) == 6);
        assert(threeforths(10) == 7);
        assert(threeforths(11) == 8);
        assert(threeforths(12) == 9);
    
        assert(threeforths(-8) == -6);
        assert(threeforths(-9) == -6);
        assert(threeforths(-10) == -7);
        assert(threeforths(-11) == -8);
        assert(threeforths(-12) == -9);
        return 0;
    }
    

    2.81

    -1 << k
    
    ~(-1 << k) << j
    

    2.82

    错。 x 是 INT_MIN
    对。
    对。
    对。
    对。
    

    2.83

    #include <stdio.h>
    #include <limits.h>
    #include <assert.h>
    
    int threeforths(int x) {
        int is_neg = x & INT_MIN;
        int f = x & ~0x3;
        int l = x & 0x3;
    
        int fd4 = f >> 2;
        int fd4m3 = (fd4 << 1) + fd4;
    
        int lm3 = (l << 1) + l;
        int bias = (1 << 2) - 1;
        (is_neg && (lm3 += bias));
        int lm3d4 = lm3 >> 2;
    
        return fd4m3 + lm3d4;
    }
    
    int main(int argc, char *argv[]) {
        assert(threeforths(0) == 0);
        assert(threeforths(1) == 0);
        assert(threeforths(2) == 1);
        assert(threeforths(3) == 2);
        assert(threeforths(8) == 6);
        assert(threeforths(9) == 6);
        assert(threeforths(10) == 7);
        assert(threeforths(11) == 8);
        assert(threeforths(12) == 9);
    
        assert(threeforths(-8) == -6);
        assert(threeforths(-9) == -6);
        assert(threeforths(-10) == -7);
        assert(threeforths(-11) == -8);
        assert(threeforths(-12) == -9);
        return 0;
    }
    

    2.83

    A.
    n = 0.yyyyy...
    n << k = y.yyyyy... = Y + n
    n << k - n = Y
    n = Y/(2^k - 1)
    
    B.
    
    (a).
    y = 101, Y = 5, k = 3
    n = 5/7
    
    (b).
    y = 0110, Y = 6, k = 4
    n = 2/5
    
    (c).
    y = 010011, Y = 19, k = 6
    n = 19/63
    

    2.84

    #include <stdio.h>
    #include <assert.h>
    
    unsigned f2u(float x) {
        return *(unsigned *) &x;
    }
    
    int float_le(float x, float y) {
        unsigned ux = f2u(x);
        unsigned uy = f2u(y);
    
        unsigned sx = ux >> 31;
        unsigned sy = uy >> 31;
    
        return (ux << 1 == 0 && uy << 1 == 0) || /* both zeros */
               (sx && !sy) ||                         /* x < 0, y >= 0 or x <= 0, y > 0 */
               (!sx && ux <= uy) ||            /* x > 0, y >= 0 or x >= 0, y > 0 */
               (sx && ux >= uy);                /* x < 0, y <= 0 or x <= 0, y < 0 */
    }
    
    int main(int argc, char *argv[]) {
        assert(float_le(-0, +0));
        assert(float_le(+0, -0));
        assert(float_le(0, 3));
        assert(float_le(-4, -0));
        assert(float_le(-4, 4));
        return 0;
    }
    

    2.85

    // 注意题目中并没有说有符号位
    bias = 2^(k - 1) - 1
    V = 2^E * M
    
    a. 
    7.0 = 0b111.000...
    M = 0b1.11
    f = 0b0.11
    E = 2
    e = bias + E
    V = 7.0
    结果是 10...1 110...
    
    b.
    bias+n 1...
    
    c.
    1...101 0...
    

    2.86

    0 0...(15) 0 0...(62)1  2^(1-bias-63)
    0 0...(14)1 1 0....(63) 2^(1-bias)
    0 1...(14)0 1 1...(63)  2^bias * (2-2^-63)
    

    2.87

    描述 Hex M E V D
    -0 0x8000 0 -14 -0 -0.0
    >2 least 0x4001 1025/1024 1 1025/512 2.00195312
    512 0x6000 1 9 512 512.0
    bigest denormalized 0x03FF 1023/1024 -14 1023/(2^24) 6.09755516e-5
    -∞ 0xFC00 - - -∞ -∞
    ox3BB0 0x3BB0 123/64 -1 123/128 0.9609375

    2.88

    A bit A value B bit B value
    1 01110 001 -9/16 1 0110 0010 -9/16
    0 10110 101 13*2^4 0 1110 1010 13*2^4
    1 00111 110 -7/2^10 1 0000 0111 -7/2^10
    0 00000 101 5/2^17 0 0000 0001 1/2^10
    1 11011 000 -2^12 1 1110 1111 -31*2^3
    0 11000 100 3*2^8 0 1111 0000 +oo

    2.89

    #include <stdio.h>
    #include <assert.h>
    #include <limits.h>
    
    /*
     * most important thing is that all double number come from ints
     */
    
    /* right */
    int A(int x, double dx) {
        return (float) x == (float) dx;
    }
    
    /* wrong when y is INT_MIN */
    int B(int x, double dx, int y, double dy) {
        return dx - dy == (double) (x - y);
    }
    
    /* right */
    int C(double dx, double dy, double dz) {
        return (dx + dy) + dz == dx + (dy + dz);
    }
    
    /*
     * wrong
     *
     * FIXME I don't know what conditions cause false
     */
    int D(double dx, double dy, double dz) {
        return (dx * dy) * dz == dx * (dy * dz);
    }
    
    /* wrong when dx != 0 and dz == 0 */
    int E(double dx, double dz) {
        return dx / dx == dz / dz;
    }
    
    int main(int argc, char *argv[]) {
    
        int x = 111;
        int y = 222;
        int z = 333;
        double dx = (double) x;
        double dy = (double) y;
        double dz = (double) z;
    
        printf("%x %x %x\n", x, y, z);
    
        assert(A(x, dx));   // double 可以表示所有32位整数
        assert(!B(0, (double) (int) 0, INT_MIN, (double) (int) INT_MIN));    // 溢出问题
        assert(C(dx, dy, dz));    // double 可以表示所有32位整数
        assert(!D((double) (int) 0x64e73387, (double) (int) 0xd31cb264, (double) (int) 0xd22f1fcd)); // double 并不能表示所有的 64位数,导致舍入问题
        assert(!E(dx, (double) (int) 0));    // 除数为零
        return 0;
    }
    

    2.90

    #include <stdio.h>
    #include <assert.h>
    #include <math.h>
    
    float u2f(unsigned x) {
      return *(float*) &x;
    }
    
    /* 2^x */
    float fpwr2(int x) {
      /* Result exponent and fraction */
      unsigned exp, frac;
      unsigned u;
    
      if (x < 2-pow(2,7)-23) {
        /* too small. return 0.0 */
        exp = 0;
        frac = 0;
      } else if (x < 2-pow(2,7)) {
        /* Denormalized result */
        exp = 0;
        frac = 1 << (unsigned)(x - (2-pow(2,7)-23));
      } else if (x < pow(2,7)-1+1) {
        /* Normalized result */
        exp = pow(2,7)-1+x;
        frac = 0;
      } else {
        /* Too big, return +oo */
        exp = 0xFF;
        frac = 0;
      }
    
      /* pack exp and frac into 32 bits */
      u = exp << 23 | frac;
      /* Result as float */
      return u2f(u);
    }
    
    int main(int argc, char* argv[]) {
      assert(fpwr2(0) == powf(2,0));
      assert(fpwr2(100) == powf(2,100));
      assert(fpwr2(-100) == powf(2,-100));
      assert(fpwr2(10000) == powf(2,10000));
      assert(fpwr2(-10000) == powf(2,-10000));
      return 0;
    }
    

    2.91

    A.
    0b11.0010010000111111011011
    
    B.
    0b11.001001(001)...
    
    C.
    第九个
    

    2.92

    float_bits float_negate(float_bits f) {
        unsigned sign = f >> 31;
        unsigned exp = f >> 23 & 0xff;
        unsigned frac = f & 0x7fffff;
        if (exp == 0xff && frac) {
            return f;
        }
        return (~sign << 31) | (exp << 23) | frac;
    }
    

    2.93

    float_bits float_absval(float_bits f) {
        unsigned sig = f >> 31;
        unsigned exp = f >> 23 & 0xFF;
        unsigned frac = f & 0x7FFFFF;
    
        int is_NAN = (exp == 0xFF) && (frac != 0);
        if (is_NAN) {
            return f;
        }
    
        return 0 << 31 | exp << 23 | frac;
    }
    

    2.94

    float_bits float_twice(float_bits f) {
        unsigned sig = f >> 31;
        unsigned exp = f >> 23 & 0xFF;
        unsigned frac = f & 0x7FFFFF;
    
        int is_NAN_or_oo = (exp == 0xFF);
        if (is_NAN_or_oo) {
            return f;
        }
    
        if (exp == 0) {
            /* Denormalized */
            frac <<= 1;
        } else if (exp == 0xFF - 1) {
            /* twice to oo */
            exp = 0xFF;
            frac = 0;
        } else {
            /* Normalized */
            exp += 1;
        }
    
        return sig << 31 | exp << 23 | frac;
    }
    

    2.95

    float_bits float_half(float_bits f) {
        unsigned sig = f >> 31;
        unsigned rest = f & 0x7FFFFFFF;
        unsigned exp = f >> 23 & 0xFF;
        unsigned frac = f & 0x7FFFFF;
    
        int is_NAN_or_oo = (exp == 0xFF);
        if (is_NAN_or_oo) {
            return f;
        }
    
        /*
         * round to even, we care about last 2 bits of frac
         *
         * 00 => 0 just >>1
         * 01 => 0 (round to even) just >>1
         * 10 => 1 just >>1
         * 11 => 1 + 1 (round to even) just >>1 and plus 1
         */
        int addition = (frac & 0x3) == 0x3;
    
        if (exp == 0) {
            /* Denormalized */
            frac >>= 1;
            frac += addition;
        } else if (exp == 1) {
            /* Normalized to denormalized */
            rest >>= 1;
            rest += addition;
            exp = rest >> 23 & 0xFF;
            frac = rest & 0x7FFFFF;
        } else {
            /* Normalized */
            exp -= 1;
        }
    
        return sig << 31 | exp << 23 | frac;
    }
    

    2.96

    int float_f2i(float_bits f) {
        unsigned sig = f >> 31;
        unsigned exp = f >> 23 & 0xFF;
        unsigned frac = f & 0x7FFFFF;
        unsigned bias = 0x7F;
    
        int num;
        unsigned E;
        unsigned M;
    
        /*
         * consider positive numbers
         *
         * 0 00000000 00000000000000000000000
         *   ===>
         * 0 01111111 00000000000000000000000
         *   0 <= f < 1
         * get integer 0
         *
         * 0 01111111 00000000000000000000000
         *   ===>
         * 0 (01111111+31) 00000000000000000000000
         *   1 <= f < 2^31
         * integer round to 0
         *
         * 0 (01111111+31) 00000000000000000000000
         *   ===>
         * greater
         *   2^31 <= f < oo
         * return 0x80000000
         */
        if (exp >= 0 && exp < 0 + bias) {
            /* number less than 1 */
            num = 0;
        } else if (exp >= 31 + bias) {
            /* number overflow */
            /* or f < 0 and (int)f == INT_MIN */
            num = 0x80000000;
        } else {
            E = exp - bias;
            M = frac | 0x800000;
            if (E > 23) {
                num = M << (E - 23);
            } else {
                /* whether sig is 1 or 0, round to zero */
                num = M >> (23 - E);
            }
        }
    
        return sig ? -num : num;
    }
    

    2.97

    #include <stdio.h>
    #include <assert.h>
    #include <limits.h>
    
    typedef unsigned float_bits;
    
    float_bits float_i2f(int i) {
        unsigned sign = i & 0x80000000;
        if (i == 0) {
            return sign;
        }
        if (i == 0x80000000) {
            return 0xcf000000;
        }
    
        unsigned transI = i;
        if (sign) {
            transI = ~i + 1;
        }
        int noSignI = transI & 0x7fffffff;
    
        int isOne = noSignI & 0x80000000;
        int count = 1;
    
        while (!isOne) {
            noSignI <<= 1;
            isOne = noSignI & 0x80000000;
            count++;
        }
    
        int exp = 127 + (32 - count);
        int frac = (transI << count >> 1 + 8) & 0x7fffff;
    
        int ret = sign | exp << 23 | frac;
    
        if (32 - count > 23) {
            int mid = (transI << count >> 1 + 8 << 1 + 8) + 0b100000000;
            if (transI << count > mid) {
                ret++;
            } else {
                if (transI << count == mid && frac & 0x1) {
                    ret++;
                }
            }
        }
        return ret;
    }
    
    int main() {
        unsigned a;
        int b;
        int arr[] = {1, 2, 4, INT_MAX, INT_MIN, 0, -1, -2, 123456789, 2147483582, 2147483584, 2147483585};
        int count = sizeof(arr) / sizeof(int);
        for (int i = 0; i < count; i++) {
            b = arr[i];
            a = float_i2f(b);
            printf("\n %d ==>\t", b);
            printf(" %f ==>\t", (float) b);
            printf(" %f \n", *(float *) (&a));
            assert((float) b == *(float *) (&a));
        }
        return 0;
    }
    

    相关文章

      网友评论

          本文标题:深入理解计算机操作系统第二章家庭作业

          本文链接:https://www.haomeiwen.com/subject/zdmpvqtx.html