代码均经过或复杂或简单的测试,如果有什么不对的地方,敬请留下评论
#include
#include
#include
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]); //line:data:show_bytes_printf
printf("\n");
}
void show_int(int x) {
show_bytes((byte_pointer)&x, sizeof(int)); //line:data:show_bytes_amp1
}
void show_float(float x) {
show_bytes((byte_pointer)&x, sizeof(float)); //line:data:show_bytes_amp2
}
void show_pointer(void *x) {
show_bytes((byte_pointer)&x, sizeof(void *)); //line:data:show_bytes_amp3
}
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 val) {
int ival = val;
float fval = (float)ival;
int *pval = &ival;
short sval = (short)ival;
long lval = (long)ival;
double dval = (double)ival;
show_int(ival);
show_float(fval);
show_pointer(pval);
show_short(sval);
show_long(lval);
show_double(dval);
}
int main() {
test_show_bytes(123);
printf("\n");
test_show_bytes(32);
getchar();
}
int is_little_endian() {
int a = 1;
byte_pointer p = &a;
return p[0];
}
#include
int main() {
int x = 0x89ABCDEF;
int y = 0x76543210;
printf("0x%x\n", (0xFF & x) + (0xFFFFFF00 & y));
system("pause");
}
#include
unsigned replace_byte(unsigned x, int i, unsigned char b) {
char *p = &x;
p[i] = b;
return x;
}
int main() {
printf("0x%x\n", replace_byte(0x12345678, 2, 0xAB));
printf("0x%x\n", replace_byte(0x12345678, 0, 0xAB));
//system("pause");
}
#include
int main() {
int x = 0xFFFFFFFF;
int y = 0x00000000;
int z = 0x123456FF;
int w = 0x00123456;
/*A*/
printf("%d %d %d %d\n", !~x, !~y, !~z, !~w);
/*B*/
printf("%d %d %d %d\n", !x, !y, !z, !w);
/*C*/
printf("%d %d %d %d\n", !~(x | (-1 << 8)), !~(y | (-1 << 8)), !~(z | (-1 << 8)), !~(w | (-1 << 8)));
/*D*/
printf("%d %d %d %d\n", !(x >> ((sizeof(int) - 1) << 3)), !(y >> ((sizeof(int) - 1) << 3)), !(z >> ((sizeof(int) - 1) << 3)), !(w >> ((sizeof(int) - 1) << 3)));
//system("pause");
}
#include
int int_shifts_are_arithmetic() {
return -2 >> 1 == -1;
}
int main() {
if (int_shifts_are_arithmetic()) {
printf("int shifts are arithmetic\n");
}
else printf("int shifts are not arithmetic\n");
//system("pause");
return 0;
}
#include
#include
int w = 8 * sizeof(int);
unsigned srl(unsigned x, int k) {
/*Preform shift arithmetically*/
unsigned xsra = (int)x >> k;
int sign = (x & INT_MIN) && (k != 0); //符号为负且偏移不为0,则为 sign 为 1,否则为 0
//xsra -= (unsigned int)(sign * (-1 << (w - k))); //如果 (int)x 是负则从 xsrl 的前面将 k 个 1 换成 0
/*题目要求不能用乘法,因此把上式换成*/
xsra -= (unsigned int)(-sign & (-1 << (w - k)));
return xsra;
}
int sra(int x, int k) {
/*Perform shift logically*/
int xsrl = (unsigned)x >> k;
int sign = (k != 0) && (x & INT_MIN); //符号为负且偏移不为0
//xsrl += sign * (-1 << (w - k)); //如果是负则从 xsrl 的前面将 k 个 0 换成 1
/*题目要求不能用乘法,因此把上式换成下式*/
xsrl += (unsigned int)(-sign & (-1 << (w - k)));
return xsrl;
}
int main() {
printf("%d\n%d\n%d\n%d\n%d\n", sra(123, 0) == 123 >> 0, sra(-100, 0) == -100 >> 0, sra(-2, w - 1) == -2 >> w - 1, srl(48, 0) == 48 >> 0, srl(UINT_MAX, 2) == UINT_MAX >> 2);
printf("\nsuccess\n");
system("pause");
return 0;
}
/*Return 1 when any odd bit of x equals 1; 0 otherwise. Assume w=32*/
int any_odd_one(unsigned x) {
unsigned int t = 0x55555555;
return (x & t) != 0;
}
搬来的,完全没有思路
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;
}
// 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);
}
A. 位移量大于等于位数, C语言对其行为没有定义
B. C.
#include
/*int32 和 int16 仅用来测试,实际使用时需用 int*/
__int32 int32_int_size_is_32() {
__int32 one = 1;
__int32 set_msb = one << 31;
__int32 beyond_msb = one << 31;
beyond_msb <<= 1;
return set_msb && !beyond_msb;
}
__int16 int16_int_size_is_32() {
__int16 one = 1;
__int16 set_msb = one << 15;
set_msb <<= 15;
set_msb <<= 1;
__int16 beyond_msb = one << 15;
beyond_msb <<= 15;
beyond_msb <<= 2;
//printf("%d %d\n", set_msb, beyond_msb);
return set_msb && !beyond_msb;
}
int main() {
printf("%d %d\n", int32_int_size_is_32(), int16_int_size_is_32());
system("pause");
return 0;
}
#include
#include
int w = 8 * sizeof(int); // int 的位数
int lower_one_mask(int n) {
int k = w - n;
return ((UINT_MAX << k) >> k);
}
int main() {
printf("0x%x 0x%x 0x%x\n",lower_one_mask(6), lower_one_mask(17), lower_one_mask(w));
system("pause");
return 0;
}
#include
#include
int w = 8 * sizeof(int); // int 的位数
unsigned rotate_left(unsigned x, int n) { // 0<=n < w
int t = x << n;
int s = x >> w - n;
return t | s;
}
int main() {
printf("0x%x 0x%x 0x%x\n", rotate_left(0x12345678, 4), rotate_left(0x12345678, 20), rotate_left(0x12345678, 28));
system("pause");
return 0;
}
#include
#include
int w = 8 * sizeof(int); // int 的位数
int fits_bits(int x, int n) {
int k = w - n;
int mask = (UINT_MAX << k) >> k;
int sign = !(x & INT_MIN); //求 x 的符号
int nbits_max = mask >> 1; // n 位补码所能表示的最大值
//int nbits_min = -nbits_max - 1; // n 位补码所能表示的最小值
//return (x >= nbits_min) && (x <= nbits_max); //不能用比较符号所以改用下式
return (sign && //当 x 为正时
((x & nbits_max) == x)) ||
(!sign && //当 x 为负时
((-x == (nbits_max + 1)) ||
((-x & nbits_max) == -x)));
}
int main() {
printf("%d %d %d\n", fits_bits(2, 2), fits_bits(INT_MIN, 32), fits_bits(-1, 1));
system("pause");
return 0;
}
A. 得到的结果是unsigned,而并非扩展为signed的结果。
B. 使用int,将待抽取字节左移到最高字节,再右移到最低字节即可。
int xbyte(unsigned word, int bytenum){
int ret = word << ((3 - bytenum)<<3);
return ret >> 24;
}
A. >=语句左边始终是 unsigned,无论怎样都大于等于 0
B. 改为 if(maxbytes > 0 && maxbytes - sizeof(val) >= 0)
#include
#include
int w = 8 * sizeof(int);
int saturating_add(int x, int y) {
int sum = x + y;
/*根据书上65页的原理,不过又不能这么“直白”
if (x > 0 && y > 0 && sum <= 0) {
sum = INT_MAX;
} else if(x < 0 && y < 0 && sum >= 0) {
sum = INT_MIN;
}
*/
int x_sign = !(x & INT_MIN), //x的符号
y_sign = !(y & INT_MIN), //y的符号
sum_sign = !(sum & INT_MIN); //sum的符号
int pos = x_sign && y_sign && !sum_sign, //正溢出则 pos 为1
neg = !x_sign && !y_sign && sum_sign; //负溢出则 neg 为1
sum = (sum | -pos) & //如果正溢出,sum 会变成 INT_MAX,否则不变
(INT_MAX + (!pos << (w - 1)));
sum = (sum & ((!neg << (w - 1)) >> (w - 1))) | //如果负溢出,sum 会变成 INT_MIN,否则不变
(neg << (w - 1));
return sum;
}
int main() {
printf("%d %d %d %d\n", INT_MAX + 1, saturating_add(INT_MAX, 1), 1 + 2, saturating_add(1, 2));
printf("%d %d %d %d\n", INT_MIN - 1, saturating_add(INT_MIN, -1), -1 + (-2), saturating_add(-1, -2));
system("pause");
return 0;
}
这个题参考了课本习题 2.30,减一个数等于加这个数的相反数,但是 INT_MIN 的相反数溢出,因此分开讨论;
如果 y 不是 INT_MIN,很简单,直接取反;
否则,-y 一定溢出,等于 INT_MAX + 1,如果 x 小于 0,INT_MAX + 1 + x 小于 INT_MAX,一定不溢出;如果 x 大于 0,INT_MAX + 1 + x 一定大于 INT_MAX,一定溢出。
#include
#include
int tsub_ok(int x, int y) {
if (y != INT_MIN) {
y = -y;
// 参考习题 2.30
int sum = x + y;
int neg_over = x < 0 && y < 0 && sum >= 0;
int pos_over = x >= 0 && y >= 0 && sum < 0;
return !neg_over && !pos_over;
}
//如果 y 是 INT_MIN,-y 一定溢出,等于 INT_MAX + 1
else {
// 如果 x 小于 0,INT_MAX + 1 + x 一定小于 INT_MAX,一定不溢出
if (x < 0) {
return 1;
}
else {
return 0;
}
}
}
int main() {
// 简单测试
printf("%d %d\n", tsub_ok(-1, INT_MIN), tsub_ok(1, INT_MAX));
printf("%d %d\n", tsub_ok(INT_MIN, 2), tsub_ok(-1, -2));
int a = -1;
__int64 one = a;
__int64 two = INT_MIN;
printf("%d %d %d\n", (a - INT_MIN) == (one - two), a - INT_MIN, one - two);
system("pause");
return 0;
}
这个题我不太理解,在 StackOverflow 找到的推导 _ (:з」∠)_
To convert a signed, 2's complement, 32-bit integer to an unsigned 32-bit integer, we add 2³² to its value if it is negative.
signed_high_prod does a signed multiplication and returns bits 63 to 32 of the product. We want unsigned_high_prod to do the same for unsigned multiplication and to make use of signed_high_prod and then compensate for the difference between unsigned and signed multiplication.
Let N(i) = { 1, i < 0
{ 0, i >= 0
Let U(i) = i + N(i)·2³² { −2³¹ <= i < 2³¹ }
Then:
U(x)·U(y) = (x + N(x)·2³²)·(y + N(y)·2³²)
= x·y + x·N(y)·2³² + N(x)·2³²·y + N(x)·2³²·N(y)·2³²
= x·y + x·N(y)·2³² + y·N(x)·2³² + N(x)·N(y)·2⁶⁴
⌊U(x)·U(y)/2³²⌋ = ⌊x·y/2³²⌋ + x·N(y) + y·N(x) + N(x)·N(y)·2³²
Since the arithmetic on unsigned, 32-bit integers will be performed modulo 2³², we have:
⌊U(x)·U(y)/2³²⌋ mod 2³² = (⌊x·y/2³²⌋ + x·N(y) + y·N(x) + N(x)·N(y)·2³²) mod 2³²
= (⌊x·y/2³²⌋ + x·N(y) + y·N(x)) mod 2³²
I believe that accounts for the calculations performed by your unsigned_high_prod function.
#include
#include
/*找不到这样的库函数,下面是我自己编撰的,不能保证完全正确性*/
int signed_high_prod(int x, int y) {
__int64 X = x, Y = y;
__int64 s = X * Y;
//printf("%" PRIx64 " * %" PRIx64 "= %" PRIx64 "\n", X, Y, s);
s >>= 32;
return s;
}
/*按照推导写出的函数*/
unsigned unsigned_high_prod(unsigned x, unsigned y) {
unsigned p = (unsigned)signed_high_prod((int)x, (int)y);
if ((int)x < 0) {
p += y;
}
if ((int)y < 0) {
p += x;
}
return p;
}
int main() {
printf("%x %x\n", unsigned_high_prod(0xFFFFFFFF, 0xFFFFFFFF), signed_high_prod(0xFFFFFFFF, 0xFFFFFFFF));
system("pause");
return 0;
}
void *Calloc(size_t nmemb, size_t size) {
if (nmemb == 0 || size == 0) return NULL;
int s = nmemb * size;
if (s / size == nmemb) { //检测溢出
void *p = malloc(s);
memset(p, 0, s);
return p;
}
return NULL;
}
A. (x << 4) + x
B. x - (x << 3)
C. (x << 6) - (x << 2)
D. (x << 4) - (x << 7)
int divide_power2(int x, int k) {
int K = k & (x >> (w - 1)); //如果 x 为负, K 为 k;否则 K 为 0
x += (1 << K) - 1; //如果 K 为 0, x 不变;否则进行偏置
x >>= k;
return x;
}
#include
#include
int w = 8 * sizeof(int);
/* 2.78 中的函数*/
int divide_power2(int x, int k) {
int K = k & (x >> (w - 1)); //如果 x 为负, K 为 k;否则 K 为 0
x += (1 << K) - 1; //如果 K 为 0, x 不变;否则进行偏置
x >>= k;
return x;
}
int mul3div4(int x) {
x = (x << 1) + x;
return divide_power2(x, 2);
}
int main() {
int o = 0x12345678, t = -o;
printf("%d %d\n", mul3div4(o) == 3 * o / 4, mul3div4(t) == 3 * t /4);
system("pause");
return 0;
}
这个题目我不太会,从别的博客搬来的
#include
#include
#include
int w = 8 * sizeof(int);
/*
* 这个题目非常有意思,要保证不溢出,就要先做除法,也就是先除以4再乘以3
* 在下边中用到了一个非常巧妙的地方,把一个整数进行拆分
*/
/*
* calculate 3/4x, no overflow, round to zero
*
* no overflow means divide 4 first, then multiple 3, diffrent from 2.79 here
*
* rounding to zero is a little complicated.
* every int x, equals f(first 30 bit number) plus l(last 2 bit number)
*
* f = x & ~0x3
* l = x & 0x3
* x = f + l
* threeforths(x) = f/4*3 + l*3/4
*
* f doesn't care about round at all, we just care about rounding from l*3/4 //这儿我不太明白,可能是因为 f 加了偏置也没有变化
*
* lm3 = (l << 1) + l
*
* when x > 0, rounding to zero is easy
*
* lm3d4 = lm3 >> 2
*
* when x < 0, rounding to zero acts like divide_power2 in 2.78
*
* bias = 0x3 // (1 << 2) - 1
* lm3d4 = (lm3 + bias) >> 2
*/
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 << 1) + 1;
(is_neg && (lm3 += bias));
int lm3d4 = lm3 >> 2;
return fd4m3 + lm3d4;
}
int main() {
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);
system("pause");
return 0;
}
#include
#include
int main() {
int k = 5, j = 4;
int A = (-1 << k), B = ~(-1 << (k + j)) - ((1 << j) - 1);
printf("A. 0x%x\nB. 0x%x\n", A, B);
system("pause");
return 0;
}
A. x 当 x = 0, y = INT_MIN
B. √ 无论是否溢出,其对低32位的运算没有影响
C. √
~x + ~y + 1 = ~x + 1 + ~y + 1 - 1 = -x + -y - 1 = -(x + y) - 1 = ~(x + y) + 1 - 1 = ~(x + y)
D. √ 无符号数和有符号数位级表示相同
E. √ 左移只能在低位引入0,可能会使 x 变小
A. 令x为无穷序列表示的值,可以得到x*2^k = Y + x。所以 x = Y/(2 ^k - 1)。
B. (a)5/7, (b)6/15 = 2/5, (c) 19/63
return ((ux << 1) == (uy << 1)) || //都为0 +0 -0
(!sx && sy) || //x 为负, y 为正
(sx && sy && (ux <= uy)) || //都为正
(!sx && !sy && (ux >= uy)); //都为负
A.
7.0 = 111.0(二进制); M = 1.11; f = 0.11;
E = 2; Bias = 2^(k - 1) - 1; e = E + Bias = 2 + 2 ^ (k -1) - 1 = 2^(k - 1) + 1;
位表示 = e~f = 10…01 ~ 110…00
B.
e_MAX = 11…110 = 2^k - 2; E_MAX = e_MAX - Bias = 2^(k - 1) - 1;
当 E = n; M = 1.11…; f = 0.11… ;这样才能保证最大而且最低位为 1,即最大奇整数(前提条件是 E_MAX >= n,即指数位数足够大);
此时 e = E + Bias = n + 2^(k - 1) - 1; V = 2^(n+1) - 1;
位表示 = e~f = e ~ 11…11
C.
最小的(正)规格化数: e = 1; E = 1 - 2^(k - 1) + 1 = 2 - 2^(k - 1); M = 1.0; f = 0.0; V = 2^E;
则其倒数:Vr = 2^(-E); Er = -E = 2^(k-1) - 2; Mr = M = 1.0; fr = f = 0.0; er = Er + Bias = 2^k - 3;
位表示 = er~fr = 11…101 ~ 00…00
便于理解,我加了一列
描述 | 值 | 十进制 | 二进制表示 |
---|---|---|---|
最小的正非规格化数 | 2^(-61-2^14) | 3.6452e-4951 | 0~000…000~0~000…001 |
最小的正规格化数 | 2^(-2^14+2) | 3.3621e-4932 | 0~000…001~1~000…000 |
最大的规格化数 | (2 - 2^(-63)) * 2^(2^14 - 1) | 1.1897e+4932 | 0~111…110~1~111…111 |
描述 | Hex | M | E | V | D |
---|---|---|---|---|---|
-0 | 0x8000 | 0 | -14 | -0 | -0.0 |
最小的>2的值 | 0x4001 | 1025/1024 | 1 | 1025 * 2^(-9) | 2.001953 |
512 | 0x6000 | 1 | 9 | 512 | 512.0 |
最大的非规格化的数 | 0x03FF | 1023/1024 | -14 | 1023 * 2^(-24) | 0.000061 |
-∞ | 0xFC00 | —— | —— | -∞ | -∞ |
十六进制表示为 3BB0 的数 | 3BB0 | 123/64 | -1 | 123 * 2^(-7) | 0.960938 |
格式A | 格式B | ||
位 | 值 | 位 | 值 |
1 01110 001 | -9/16 | 1 0110 0010 | -9/16 |
0 10110 101 | 208 | 0 1110 1010 | 208 |
1 00111 110 | -7/2^10 | 1 0000 0111 | -7/2^10 |
0 00000 101 | 5/2^17 | 0 0000 0000 | 0 |
1 11011 000 | -2^12 | 1 1111 0000 | -∞ |
0 11000 100 | 768 | 0 1111 0000 | +∞ |
测试代码:
#include
#include
int A(int x, double dx) {
return (float)x == (float)dx;
}
int B(int x, double dx, int y, double dy) {
return dx - dy == (double)(x - y);
}
int C(double dx, double dy, double dz) {
return (dx + dy) + dz == dx + (dy + dz);
}
int D(double dx, double dy, double dz) {
return (dx*dy)*dz == dx * (dy*dz);
}
int E(double dx, double dz) {
return dx / dx == 1 / 1;
}
int main(int argc, char* argv[]) {
int x = INT_MAX;
int y = INT_MAX - 222;
int z = INT_MAX - 3333333333;
double dx = (double)x;
double dy = (double)y;
double dz = (double)z;
printf("%d\n", D(dx, dy, dz));
system("pause");
return 0;
}
A.√
int转double不会损失;虽然int转float,double转float有可能小数部分损失,但两者仍然相等
B.x
x = INT_MAX,y = -1,int会溢出
C.√
double不会溢出
D.√
x = INT_MAX;
y = INT_MAX - 222;
z = INT_MAX - 3333333333;
double 小数部分可能溢出
E.x
dx = 1;dz = 0
dz/dz = NaN != dx/dx = 1
float fpwr2(int x)
{
/* Result exponent and fraction */
unsigned exp, frac;
unsigned u;
if (x < -149) {
/* Too small. Return 0.0 */
exp = 0;
frac = 0;
} else if (x < -126) {
/* Denormalized result */
exp = 0;
frac = 1<<(x+149);
} else if (x < 128) {
/* Normalized result. */
exp = x + 127;
frac = 0;
} else {
/* Too big. Return +oo */
exp = 0xFF;
frac = 0;
}
/* Pack exp and frac into 32 bits */
u = exp << 23 | frac;
/* Return as float */
return u2f(u);
}
Bias = 127
最小的正非规格化数 = 2^(1-Bias) * 2^(-23) = 2^(-149),因此比 -149 小的都是 0
最大的正规格化数 = 2^(1-Bias) = 2^(-126),因此比 -126 都是非规格化数
最大的规格化数 = 2(28-2 - bias) = 2^127,比 128 小的都是规格化数
A. 3.141593
B. 根据 2.83,x = Y/(2^k - 1),则 22/7 = 21/7 + 1/7的二进制小数表示为 11.001001001…(y=001)
C. 第一个 π 的二进制小数 11.0010010000111,可以看出是第 9 位
typedef unsigned float_bits;
int IsNaN(float_bits f) {
if (((f & 0x7F800000) == 0x7F800000) && ((f & 0x7FFFFF) != 0))
return 1;
return 0;
}
float_bits float_negate(const float_bits f) {
if (IsNaN(f)) {
return f;
} else {
return f ^ 0x80000000;
}
}
typedef unsigned float_bits;
int IsNaN(float_bits f) {
if (((f & 0x7F800000) == 0x7F800000) && ((f & 0x7FFFFF) != 0))
return 1;
return 0;
}
float_bits float_absval(float_bits f) {
if (IsNaN(f)) {
return f;
} else {
return f & 0x7FFFFFFF;
}
}
非规格化数 frac 直接左移,尽管可能进位到 exp,值却是正确的;
最大规格化阶数在 exp 加一的同时,frac = 0,使 f 变为 inf;
其他普通的直接 exp 加一;
测试时发现在 f 为 NaN 时会产生难以描述的行为,这就是为什么课本让我们简单的返回 f 的原因吧;
使用了四个线程,速度快很多,i7 大概一分钟就跑完了
#include
#include
#include
#define THREADNUM_MAX 4
typedef unsigned float_bits;
int IsNaN(float_bits f) {
if (((f & 0x7F800000) == 0x7F800000) && ((f & 0x7FFFFF) != 0))
return 1;
return 0;
}
float_bits float_twice(float_bits f) {
if (IsNaN(f)) {
return f;
}
else {
unsigned sign = f >> 31;
unsigned exp = f >> 23 & 0xFF;
unsigned frac = f & 0x7FFFFF;
/*非规格化数*/
if (exp == 0) {
frac <<= 1;
}
/*最大规格化阶数*/
else if (exp == 0xFE) {
frac = 0;
exp = 0xFF;
}
/*+∞ -∞*/
else if (exp == 0xFF) {
/*do nothing*/
}
else {
exp++;
}
return (sign << 31) | (exp << 23) | frac;
}
}
DWORD WINAPI TestFun(LPVOID pM) {
float_bits start, end;
/*拆分为 4 个线程*/
if ((int)pM == 0) {
start = 0; end = 1073741823;
}
else if ((int)pM == 1) {
start = 1073741824; end = 2147483646;
}
else if ((int)pM == 2) {
start = 2147483647; end = 3221225472;
}
else {
start = 3221225473; end = UINT_MAX;
}
union fu
{
float f;
float_bits u;
} fu1, fu2;
for (float_bits i = start; i <= end; i++) {
if (((int)pM == 3) && i == 0) {
break;
}
fu1.u = i; fu2.u = i;
/*由于NaN运算的复杂性以及题目的要求,对于 NaN 的运算不做处理*/
if (!IsNaN(i)) {
fu2.f *= 2;
}
if (float_twice(fu1.u) != fu2.u) {
printf("test%d detected wrong %x\n", (int)pM, i);
return 0;
}
}
printf("mission%d success!\n", (int)pM);
return 0;
}
int main() {
/*创建线程*/
HANDLE hThread[THREADNUM_MAX];
for (int i = 0; i < THREADNUM_MAX; i++) {
hThread[i] = CreateThread(NULL, 0, TestFun, (LPVOID)i, 0, NULL);
}
/*等待所有线程结束*/
WaitForMultipleObjects(THREADNUM_MAX, hThread, TRUE, INFINITE);
system("pause");
return 0;
}
这里我们考虑舍入,比如 f = 0 000…001 XXX…XYZ 进行右移变为 0 000…000 1XX…XXY(Z),题目要求偶数舍入,需要看 Z 位,如果 Z 是 1,则需要舍入。偶数舍入要使 Y 位(最低有效位)为 0,如果 Y 是 1,那么就 f 就要加 1;如果 Y 是 0,直接舍掉 Z。
#include
#include
#include
#define THREADNUM_MAX 4
typedef unsigned float_bits;
int IsNaN(float_bits f) {
if (((f & 0x7F800000) == 0x7F800000) && ((f & 0x7FFFFF) != 0))
return 1;
return 0;
}
float_bits float_half(float_bits f) {
if (IsNaN(f)) {
return f;
}
else {
unsigned sign = f >> 31;
unsigned exp = f >> 23 & 0xFF;
unsigned frac = f & 0x7FFFFF;
/*进位*/
unsigned add = (frac & 1) && ((frac >> 1) & 1);
/*非规格化数*/
if (exp == 0) {
frac >>= 1;
frac += add;
}
/*最小规格化阶数*/
else if (exp == 0x1) {
exp--;
frac = (frac >> 1) + 0x400000;
frac += add;
}
/*+∞ -∞*/
else if (exp == 0xFF) {
/*do nothing*/
}
/*其他*/
else {
exp--;
}
return (sign << 31) | (exp << 23) | frac;
}
}
DWORD WINAPI TestFun(LPVOID pM) {
float_bits start, end;
/*拆分为 4 个线程*/
if ((int)pM == 0) {
start = 0; end = 1073741823;
}
else if ((int)pM == 1) {
start = 1073741824; end = 2147483646;
}
else if ((int)pM == 2) {
start = 2147483647; end = 3221225472;
}
else {
start = 3221225473; end = UINT_MAX;
}
union fu
{
float f;
float_bits u;
} fu1, fu2;
for (float_bits i = start; i <= end; i++) {
if (((int)pM == 3) && i == 0) {
break;
}
fu1.u = i; fu2.u = i;
/*由于NaN运算的复杂性以及题目的要求,对于 NaN 的运算不做处理*/
if (!IsNaN(i)) {
fu2.f /= 2;
}
if (float_half(fu1.u) != fu2.u) {
printf("test%d detected wrong %x\n", (int)pM, i);
return 0;
}
}
printf("mission%d success!\n", (int)pM);
return 0;
}
int main() {
/*创建线程*/
HANDLE hThread[THREADNUM_MAX];
for (int i = 0; i < THREADNUM_MAX; i++) {
hThread[i] = CreateThread(NULL, 0, TestFun, (LPVOID)i, 0, NULL);
}
/*等待所有线程结束*/
WaitForMultipleObjects(THREADNUM_MAX, hThread, TRUE, INFINITE);
system("pause");
return 0;
}
比较简单
#include
#include
#include
#define THREADNUM_MAX 4
typedef unsigned float_bits;
int float_f2i(float_bits f) {
int sign = f >> 31;
sign = sign ? -1 : 1;
int exp = f >> 23 & 0xFF;
int frac = f & 0x7FFFFF;
int Bias = 127;
int E = exp - Bias;
/*F 表示的是小数值乘以 2^23 之后的值*/
int F = frac + (1 << 23);
int result;
/*非规格化数和比1小的数*/
if (exp == 0 || E < 0) {
result = 0;
}
/*上界*/
else if (E >= 31) {
result = 0x80000000;
}
/*其他*/
else {
if (E - 23 >= 0) {
result = sign * (int)(F << (E - 23));
}
else {
result = sign * (int)(F >> (23 - E));
}
}
return result;
}
DWORD WINAPI TestFun(LPVOID pM) {
float_bits start, end;
/*拆分为 4 个线程*/
if ((int)pM == 0) {
start = 0; end = 1073741823;
}
else if ((int)pM == 1) {
start = 1073741824; end = 2147483646;
}
else if ((int)pM == 2) {
start = 2147483647; end = 3221225472;
}
else {
start = 3221225473; end = UINT_MAX;
}
union fi {
float f;
int i;
} fi1, fi2;
for (float_bits i = start; i <= end; i++) {
if (((int)pM == 3) && i == 0) {
break;
}
fi1.i = i; fi2.i = i;
fi2.i = (int)fi2.f;
if (float_f2i(fi1.i) != fi2.i) {
printf("test%d detected wrong %x %x %x\n", (int)pM, i, float_f2i(fi1.i), fi2.i);
return 0;
}
}
printf("mission%d success!\n", (int)pM);
return 0;
}
int main() {
//创建线程
HANDLE hThread[THREADNUM_MAX];
for (int i = 0; i < THREADNUM_MAX; i++) {
hThread[i] = CreateThread(NULL, 0, TestFun, (LPVOID)i, 0, NULL);
}
//等待所有线程结束
WaitForMultipleObjects(THREADNUM_MAX, hThread, TRUE, INFINITE);
system("pause");
return 0;
}
如 int i = 0 001XX…XX,将其表示为浮点数为 1.XX…XX * 2^Y,所以首先要找到最高位;
单精度浮点数的小数部分长度为23,可能容纳不下,所以需要进行偶数舍入;
另外,如果小数部分 1.11…11 且 Y 为 1,进位变成 10.00…00,这种情况需特殊考虑;
而负数需要 求补 变成正数,方便运算;
#include
#include
#include
#define THREADNUM_MAX 4
typedef unsigned float_bits;
float_bits float_i2f(int i) {
if (i == 0) return 0;
//负数需要求补
int sign = i < 0;
int ic = sign ? -i : i;
//找到最高位
int firstOne = 0;
for (int j = 31; j >= 0; j--) {
if ((ic >> j) & 1) {
firstOne = j;
break;
}
}
int E = firstOne;
int Bias = 127;
//找到需要舍弃的第一个位 firstRound,即连同这个位之后的位都舍弃
int firstRound = firstOne - 24;
//小数部分1.XXXX 只保留 XXXX,并将其左移到合适的位置上来
int frac = (((unsigned)ic << (32 - firstOne)) >> (31 - 22));
//舍入
if (firstRound >= 0) {
//偶数舍入
if ((ic & ((1 << (firstRound + 1)) - 1)) == (1 << firstRound)) {
if ((frac & 1) == 1) {
//特殊处理
if ((frac == 0x7FFFFF)) {
E++; frac = 0;
}
else {
frac++;
}
}
}
//其他情况
else if ((ic >> firstRound) & 1) {
//特殊处理
if ((frac == 0x7FFFFF)) {
E++; frac = 0;
}
else {
frac++;
}
}
}
return (sign << 31) | ((E + Bias) << 23) | frac;
}
DWORD WINAPI TestFun(LPVOID pM) {
float_bits start, end;
/*拆分为 4 个线程*/
if ((int)pM == 0) {
start = 0; end = 1073741823;
}
else if ((int)pM == 1) {
start = 1073741824; end = 2147483646;
}
else if ((int)pM == 2) {
start = 2147483647; end = 3221225472;
}
else {
start = 3221225473; end = UINT_MAX;
}
union fi {
float f;
int i;
} fi1, fi2;
for (float_bits i = start; i <= end; i++) {
if (((int)pM == 3) && i == 0) {
break;
}
fi1.i = i; fi2.i = i;
fi2.f = (float)fi2.i;
if (float_i2f(fi1.i) != fi2.i) {
printf("test%d detected wrong %x %x %x\n", (int)pM, i, float_i2f(fi1.i), fi2.i);
return 0;
}
}
printf("mission%d success!\n", (int)pM);
return 0;
}
int main() {
//创建线程
HANDLE hThread[THREADNUM_MAX];
for (int i = 0; i < THREADNUM_MAX; i++) {
hThread[i] = CreateThread(NULL, 0, TestFun, (LPVOID)i, 0, NULL);
}
//等待所有线程结束
WaitForMultipleObjects(THREADNUM_MAX, hThread, TRUE, INFINITE);
system("pause");
return 0;
}