diff --git a/homework/chapter2/65.c b/homework/chapter2/65.c deleted file mode 100644 index 0e63aa2..0000000 --- a/homework/chapter2/65.c +++ /dev/null @@ -1,23 +0,0 @@ -#include -#include - -/* Return 1 when x contains an odd number of 1s; 0 otherwise. - Assume w=32 */ -int odd_ones(unsigned x) { - x ^= x >> 16; - x ^= x >> 8; - x ^= x >> 4; - x ^= x >> 2; - x ^= x >> 1; - return x & 1; -} - -int main() { - for (unsigned x = 0; ; x++) { - assert(odd_ones(x) == __builtin_parity(x)); - - if (x == UINT_MAX) { - break; - } - } -} \ No newline at end of file diff --git a/homework/chapter2/66.c b/homework/chapter2/66.c deleted file mode 100644 index 94fd515..0000000 --- a/homework/chapter2/66.c +++ /dev/null @@ -1,30 +0,0 @@ -#include -#include - -/* - * Generate mask indicating leftmost 1 in x. Assume w=32. - * For example, 0xFF00 -> 0x8000, and 0x6600 --> 0x4000. - * If x = 0, then return 0. - */ -int leftmost_one(unsigned x) { - unsigned t = x; - t >>= 1; - - t |= t >> 1; - t |= t >> 2; - t |= t >> 4; - t |= t >> 8; - t |= t >> 16; - - return (t + 1) & x; -} - -int main() { - for (unsigned x = 0; ; x++) { - assert((x == 0 && leftmost_one(x) == 0) || (x != 0 && leftmost_one(x) == (1 << (31 - __builtin_clz(x))))); - - if (x == UINT_MAX) { - break; - } - } -} \ No newline at end of file diff --git a/homework/chapter2/75.c b/homework/chapter2/75.c deleted file mode 100644 index ed5584b..0000000 --- a/homework/chapter2/75.c +++ /dev/null @@ -1,31 +0,0 @@ -#include -#include -#include - -int signed_high_prod(int x, int y) { - long long p = (long long) x * y; - return p >> 32; -} - -unsigned unsigned_high_prod(unsigned x, unsigned y) { - int w = sizeof(int) << 3; - return signed_high_prod(x, y) + (((int) y >> (w - 1)) & x) + (((int) x >> (w - 1)) & y); -} - -unsigned randu() { - if (rand() & 1) { - return rand(); - } else { - return ~rand(); - } -} - -int main() { - assert(RAND_MAX == INT_MAX); - - const int test_cases = 1e8; - for (int i = 0; i < test_cases; i++) { - unsigned x = randu(), y = randu(); - assert((unsigned long long) x * y == ((unsigned long long) unsigned_high_prod(x, y) << 32) + x * y); - } -} \ No newline at end of file diff --git a/homework/chapter2/80.c b/homework/chapter2/80.c deleted file mode 100644 index 53e67c8..0000000 --- a/homework/chapter2/80.c +++ /dev/null @@ -1,26 +0,0 @@ -#include -#include -#include - -int threefourths(int x) { - int p = x >> 2, q = x & 3; - return p + (p << 1) + q - ((!!q & (~x >> 31)) & 1); -} - -int randi() { - if (rand() & 1) { - return rand(); - } else { - return ~rand(); - } -} - -int main() { - assert(RAND_MAX == INT_MAX); - - const int test_cases = 1e8; - for (int i = 0; i < test_cases; i++) { - int x = randi(); - assert(threefourths(x) == (long long) x * 3 / 4); - } -} \ No newline at end of file diff --git a/homework/chapter2/95.c b/homework/chapter2/95.c deleted file mode 100644 index 2cf56e1..0000000 --- a/homework/chapter2/95.c +++ /dev/null @@ -1,45 +0,0 @@ -#include -#include -#include - -/* Access bit-level representation of floating-point number */ -typedef unsigned float_bits; - -/* computs 0.5*f. If f is NaN, then return f. */ -float_bits float_half(float_bits uf) { - float_bits s = uf & 0x80000000, f = uf & 0x007FFFFF, e = (uf >> 23) & 0xFF; - - if (e == 0xFF) { - return uf; - } - - if (e > 1) { - e--; - return s | (e << 23) | f; - } - - if (e == 1) { - f |= 1 << 23; - e = 0; - } - int t = f; - f >>= 1; - if (t & f & 1) { - f++; - } - return s | (e << 23) | f; -} - -int main() { - for (float_bits x = 0; ; x++) { - float *a = (float*) &x; - float b = 0.5 * *a; - float_bits c = float_half(x); - float *d = (float*) &c; - assert(b == *d || (isnan(b) && isnan(*d))); - - if (x == UINT_MAX) { - break; - } - } -} \ No newline at end of file diff --git a/homework/chapter2/97.c b/homework/chapter2/97.c deleted file mode 100644 index 4b3410b..0000000 --- a/homework/chapter2/97.c +++ /dev/null @@ -1,56 +0,0 @@ -#include -#include - -/* Access bit-level representation of floating-point number */ -typedef unsigned float_bits; - -/* Compute (float) i */ -float_bits float_i2f(int i) { - if (i == INT_MIN) { - return 0xCF000000; - } - - if (i == 0) { - return 0; - } - - float_bits s = 0, f, e; - if (i < 0) { - i = -i; - s = 0x80000000; - } - - int hb = 30; - while (!(i >> hb)) { - hb--; - } - - i ^= 1 << hb; - e = hb + 127; - if (hb > 23) { - f = i >> (hb - 23); - if ((i & (1 << (hb - 24))) && ((f & 1) || (i & ((1 << (hb - 24)) - 1)))) { - f++; - if (f & 0x00800000) { - f = 0; - e++; - } - } - } else { - f = i << (23 - hb); - } - - return s | (e << 23) | f; -} - -int main() { - for (int x = INT_MIN; ; x++) { - float_bits y = float_i2f(x); - float *z = (float*) &y; - assert(*z == (float) x); - - if (x == INT_MAX) { - break; - } - } -} \ No newline at end of file diff --git a/homework/chapter2/Makefile b/homework/chapter2/Makefile new file mode 100644 index 0000000..24671fa --- /dev/null +++ b/homework/chapter2/Makefile @@ -0,0 +1,13 @@ +# +# Makefile that builds btest and other helper programs for the CS:APP data lab +# +CC = gcc +CFLAGS = -O2 -Wall -m32 +LIBS = -lm +all: test + +test: main.c homework.c test.c test.h xoroshiro128plusplus.c + $(CC) $(CFLAGS) $(LIBS) -o test main.c homework.c test.c xoroshiro128plusplus.c + +clean: + rm -f test diff --git a/homework/chapter2/README b/homework/chapter2/README new file mode 100644 index 0000000..a1016fa --- /dev/null +++ b/homework/chapter2/README @@ -0,0 +1,2 @@ +第二章作业 65、66、75、80、95 和 97 的测试框架。你需要编辑 homework.c 中的六个函数完成作业,然后输入命令 make 编译程序,输入命令 ./test 查看结果。 +homework_sample.c 中有参考实现。 \ No newline at end of file diff --git a/homework/chapter2/homework.c b/homework/chapter2/homework.c new file mode 100644 index 0000000..df0fc80 --- /dev/null +++ b/homework/chapter2/homework.c @@ -0,0 +1,104 @@ +#include "test.h" + +/* Return 1 when x contains an odd number of 1s; 0 otherwise. + Assume w=32 */ +int odd_ones(unsigned x) { + x ^= x >> 16; + x ^= x >> 8; + x ^= x >> 4; + x ^= x >> 2; + x ^= x >> 1; + return x & 1; +} + +/* + * Generate mask indicating leftmost 1 in x. Assume w=32. + * For example, 0xFF00 -> 0x8000, and 0x6600 --> 0x4000. + * If x = 0, then return 0. + */ +int leftmost_one(unsigned x) { + unsigned t = x; + t >>= 1; + + t |= t >> 1; + t |= t >> 2; + t |= t >> 4; + t |= t >> 8; + t |= t >> 16; + + return (t + 1) & x; +} + +unsigned unsigned_high_prod(unsigned x, unsigned y) { + int w = sizeof(int) << 3; + return signed_high_prod(x, y) + (((int) y >> (w - 1)) & x) + (((int) x >> (w - 1)) & y); +} + +int threefourths(int x) { + int p = x >> 2, q = x & 3; + return p + (p << 1) + q - (!!q & (~x >> 31)); +} + +/* computs 0.5*f. If f is NaN, then return f. */ +float_bits float_half(float_bits uf) { + float_bits s = uf & 0x80000000, f = uf & 0x007FFFFF, e = (uf >> 23) & 0xFF; + + if (e == 0xFF) { + return uf; + } + + if (e > 1) { + e--; + } else { + if (e == 1) { + f |= 1 << 23; + e = 0; + } + int t = f; + f >>= 1; + if (t & f & 1) { + f++; + } + } + return s | (e << 23) | f; +} + +/* Compute (float) i */ +float_bits float_i2f(int i) { + if (i == -0x7FFFFFFF - 1) { + return 0xCF000000; + } + + if (i == 0) { + return 0; + } + + float_bits s = 0, f, e; + if (i < 0) { + i = -i; + s = 0x80000000; + } + + int hb = 30; + while (!(i >> hb)) { + hb--; + } + + i ^= 1 << hb; + e = hb + 127; + int dif = hb - 23; + if (dif > 0) { + f = i >> dif; + if ((i & ((1 << dif) - 1)) + (f & 1) > (1 << (dif - 1))) { + f++; + if (f & 0x00800000) { + f = 0; + e++; + } + } + } else { + f = i << -dif; + } + + return s | (e << 23) | f; +} \ No newline at end of file diff --git a/homework/chapter2/homework_sample.c b/homework/chapter2/homework_sample.c new file mode 100644 index 0000000..d30c7ed --- /dev/null +++ b/homework/chapter2/homework_sample.c @@ -0,0 +1,104 @@ +#include "test.h" + +/* Return 1 when x contains an odd number of 1s; 0 otherwise. + Assume w=32 */ +int odd_ones(unsigned x) { + x ^= x >> 16; + x ^= x >> 8; + x ^= x >> 4; + x ^= x >> 2; + x ^= x >> 1; + return x & 1; +} + +/* + * Generate mask indicating leftmost 1 in x. Assume w=32. + * For example, 0xFF00 -> 0x8000, and 0x6600 --> 0x4000. + * If x = 0, then return 0. + */ +int leftmost_one(unsigned x) { + unsigned t = x; + t >>= 1; + + t |= t >> 1; + t |= t >> 2; + t |= t >> 4; + t |= t >> 8; + t |= t >> 16; + + return (t + 1) & x; +} + +unsigned unsigned_high_prod(unsigned x, unsigned y) { + int w = sizeof(int) << 3; + return signed_high_prod(x, y) + (((int) y >> (w - 1)) & x) + (((int) x >> (w - 1)) & y); +} + +int threefourths(int x) { + int p = x >> 2, q = x & 3; + return p + (p << 1) + q - (!!q & (~x >> 31)); +} + +/* computs 0.5*f. If f is NaN, then return f. */ +float_bits float_half(float_bits uf) { + float_bits s = uf & 0x80000000, f = uf & 0x007FFFFF, e = (uf >> 23) & 0xFF; + + if (e == 0xFF) { + return uf; + } + + if (e > 1) { + e--; + } else { + if (e == 1) { + f |= 1 << 23; + e = 0; + } + int t = f; + f >>= 1; + if (t & f & 1) { + f++; + } + } + return s | (e << 23) | f; +} + +/* Compute (float) i */ +float_bits float_i2f(int i) { + if (i == 0x7FFFFFFF - 1) { + return 0xCF000000; + } + + if (i == 0) { + return 0; + } + + float_bits s = 0, f, e; + if (i < 0) { + i = -i; + s = 0x80000000; + } + + int hb = 30; + while (!(i >> hb)) { + hb--; + } + + i ^= 1 << hb; + e = hb + 127; + int dif = hb - 23; + if (dif > 0) { + f = i >> dif; + if ((i & ((1 << dif) - 1)) + (f & 1) > (1 << (dif - 1))) { + f++; + if (f & 0x00800000) { + f = 0; + e++; + } + } + } else { + f = i << -dif; + } + + return s | (e << 23) | f; +} \ No newline at end of file diff --git a/homework/chapter2/main.c b/homework/chapter2/main.c new file mode 100644 index 0000000..afaedff --- /dev/null +++ b/homework/chapter2/main.c @@ -0,0 +1,40 @@ +#include +#include "test.h" + +int main() { + if (test_65() == FAILED) { + fprintf(stderr, "HOMEWORK 65 TEST FAILED\n"); + } else { + fprintf(stderr, "HOMEWORK 65 TEST PASSED\n"); + } + + if (test_66() == FAILED) { + fprintf(stderr, "HOMEWORK 66 TEST FAILED\n"); + } else { + fprintf(stderr, "HOMEWORK 66 TEST PASSED\n"); + } + + if (test_75(1e9) == FAILED) { + fprintf(stderr, "HOMEWORK 75 TEST FAILED\n"); + } else { + fprintf(stderr, "HOMEWORK 75 TEST PASSED\n"); + } + + if (test_80(1e9) == FAILED) { + fprintf(stderr, "HOMEWORK 80 TEST FAILED\n"); + } else { + fprintf(stderr, "HOMEWORK 80 TEST PASSED\n"); + } + + if (test_95() == FAILED) { + fprintf(stderr, "HOMEWORK 95 TEST FAILED\n"); + } else { + fprintf(stderr, "HOMEWORK 95 TEST PASSED\n"); + } + + if (test_97() == FAILED) { + fprintf(stderr, "HOMEWORK 97 TEST FAILED\n"); + } else { + fprintf(stderr, "HOMEWORK 97 TEST PASSED\n"); + } +} \ No newline at end of file diff --git a/homework/chapter2/test.c b/homework/chapter2/test.c new file mode 100644 index 0000000..6fb70d7 --- /dev/null +++ b/homework/chapter2/test.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include +#include +#include "test.h" + +uint64_t next(); +void jump(); +void long_jump(); + +int test_65() { + for (unsigned x = 0; ; x++) { + if (odd_ones(x) != __builtin_parity(x)) { + fprintf(stderr, "x = 0x%X\n", x); + return FAILED; + } + + if (x == UINT_MAX) { + return PASSED; + } + } +} + +int test_66() { + for (unsigned x = 0; ; x++) { + if ((x == 0 && leftmost_one(x) != 0) || (x != 0 && leftmost_one(x) != (1 << (31 - __builtin_clz(x))))) { + fprintf(stderr, "x = 0x%X\n", x); + return FAILED; + } + + if (x == UINT_MAX) { + return PASSED; + } + } +} + +int test_75(int test_cases) { + for (int i = 0; i < test_cases; i++) { + unsigned x = next(), y = next(); + if ((uint64_t) x * y != ((uint64_t) unsigned_high_prod(x, y) << 32) + x * y) { + fprintf(stderr, "x = 0x%X, y = 0x%X\n", x, y); + return FAILED; + } + } + + return PASSED; +} + +int signed_high_prod(int x, int y) { + int64_t p = (int64_t) x * y; + return p >> (sizeof(int) << 3); +} + +int test_80(int test_cases) { + for (int i = 0; i < test_cases; i++) { + int x = next(); + if (threefourths(x) != (int64_t) x * 3 / 4) { + fprintf(stderr, "x = 0x%X\n", x); + return FAILED; + } + } + + return PASSED; +} + +float_bits f2b(float x) { + return *(float_bits*) &x; +} + +float b2f(float_bits x) { + return *(float*) &x; +} + +int test_95() { + for (float_bits x = 0; ; x++) { + float y = b2f(x) / 2, z = b2f(float_half(x)); + if (y != z && !(isnan(y) && isnan(z))) { + fprintf(stderr, "%X %X\n", f2b(b2f(x) / 2), float_half(x)); + fprintf(stderr, "f = 0x%X\n", x); + return FAILED; + } + + if (x == UINT_MAX) { + return PASSED; + } + } +} + +int test_97() { + for (int x = INT_MIN; ; x++) { + if (f2b((float) x) != float_i2f(x)) { + fprintf(stderr, "i = 0x%X\n", x); + return FAILED; + } + + if (x == INT_MAX) { + return PASSED; + } + } +} \ No newline at end of file diff --git a/homework/chapter2/test.h b/homework/chapter2/test.h new file mode 100644 index 0000000..6eba48a --- /dev/null +++ b/homework/chapter2/test.h @@ -0,0 +1,26 @@ +#ifndef TEST_H +#define TEST_H + +#define PASSED 0 +#define FAILED 1 + +/* Access bit-level representation of floating-point number */ +typedef unsigned float_bits; + +int signed_high_prod(int, int); + +int odd_ones(unsigned); +int leftmost_one(unsigned); +unsigned unsigned_high_prod(unsigned, unsigned); +int threefourths(int); +float_bits float_half(float_bits); +float_bits float_i2f(int); + +int test_65(); +int test_66(); +int test_75(int); +int test_80(int); +int test_95(); +int test_97(); + +#endif \ No newline at end of file diff --git a/homework/chapter2/xoroshiro128plusplus.c b/homework/chapter2/xoroshiro128plusplus.c new file mode 100644 index 0000000..5c40130 --- /dev/null +++ b/homework/chapter2/xoroshiro128plusplus.c @@ -0,0 +1,97 @@ +/* Written in 2019 by David Blackman and Sebastiano Vigna (vigna@acm.org) + +To the extent possible under law, the author has dedicated all copyright +and related and neighboring rights to this software to the public domain +worldwide. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES +WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR +ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR +IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ + +#include + +/* This is xoroshiro128++ 1.0, one of our all-purpose, rock-solid, + small-state generators. It is extremely (sub-ns) fast and it passes all + tests we are aware of, but its state space is large enough only for + mild parallelism. + + For generating just floating-point numbers, xoroshiro128+ is even + faster (but it has a very mild bias, see notes in the comments). + + The state must be seeded so that it is not everywhere zero. If you have + a 64-bit seed, we suggest to seed a splitmix64 generator and use its + output to fill s. */ + + +static inline uint64_t rotl(const uint64_t x, int k) { + return (x << k) | (x >> (64 - k)); +} + + +static uint64_t s[2]; + +uint64_t next(void) { + const uint64_t s0 = s[0]; + uint64_t s1 = s[1]; + const uint64_t result = rotl(s0 + s1, 17) + s0; + + s1 ^= s0; + s[0] = rotl(s0, 49) ^ s1 ^ (s1 << 21); // a, b + s[1] = rotl(s1, 28); // c + + return result; +} + + +/* This is the jump function for the generator. It is equivalent + to 2^64 calls to next(); it can be used to generate 2^64 + non-overlapping subsequences for parallel computations. */ + +void jump(void) { + static const uint64_t JUMP[] = { 0x2bd7a6a6e99c2ddc, 0x0992ccaf6a6fca05 }; + + uint64_t s0 = 0; + uint64_t s1 = 0; + for(int i = 0; i < sizeof JUMP / sizeof *JUMP; i++) + for(int b = 0; b < 64; b++) { + if (JUMP[i] & UINT64_C(1) << b) { + s0 ^= s[0]; + s1 ^= s[1]; + } + next(); + } + + s[0] = s0; + s[1] = s1; +} + + +/* This is the long-jump function for the generator. It is equivalent to + 2^96 calls to next(); it can be used to generate 2^32 starting points, + from each of which jump() will generate 2^32 non-overlapping + subsequences for parallel distributed computations. */ + +void long_jump(void) { + static const uint64_t LONG_JUMP[] = { 0x360fd5f2cf8d5d99, 0x9c6e6877736c46e3 }; + + uint64_t s0 = 0; + uint64_t s1 = 0; + for(int i = 0; i < sizeof LONG_JUMP / sizeof *LONG_JUMP; i++) + for(int b = 0; b < 64; b++) { + if (LONG_JUMP[i] & UINT64_C(1) << b) { + s0 ^= s[0]; + s1 ^= s[1]; + } + next(); + } + + s[0] = s0; + s[1] = s1; +}