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

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

描述HexMEVD
-00x80000-14-0-0.0
>2 least0x40011025/102411025/5122.00195312
5120x600019512512.0
bigest denormalized0x03FF1023/1024-141023/(2^24)6.09755516e-5
-∞0xFC00---∞-∞
ox3BB00x3BB0123/64-1123/1280.9609375

2.88

A bitA valueB bitB value
1 01110 001-9/161 0110 0010-9/16
0 10110 10113*2^40 1110 101013*2^4
1 00111 110-7/2^101 0000 0111-7/2^10
0 00000 1015/2^170 0000 00011/2^10
1 11011 000-2^121 1110 1111-31*2^3
0 11000 1003*2^80 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;

    if (32 - count > 23) {
        int addition = 0;
        int mid = (transI << count >> 1 + 8 << 1 + 8) + 0b100000000;
        if (transI << count > mid) {
            addition++;
        } else {
            if (transI << count == mid && frac & 0x1) {
                addition++;
            }
        }
        frac += addition;
        if (addition && frac == 0x800000) {
            frac = 0;
            exp += 1;
        }
    }
    return sign | exp << 23 | frac;
}

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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值