数据的位运算及补码运算[makefile的简答使用]

数据的位运算及补码运算[makefile的简答使用]

要求

(1)位操作

表1-7行出了一组位操作函数。“功能”栏给出函数应实现的输出(即功能),“约束条件”栏指出函数实现必须满足的编码规则,“最多操作符数量”指出设计的函数实现中允许使用的操作符的最大数量。

(2)补码运算

表8-11行出了设计的程序中一组使用整数的补码表示的函数。

表补码运算题目

1 lsbZero 将x的最低有效位(LSB)清零 仅能使用! ~ & ^ | + << >> 5
2 byteNot 将x的第n个字节取反(字节从LSB开始到MSB依次编号为1-4) 仅能使用! ~ & ^ | + << >> 6
3 byteXor 比较x和y的第n个字节(字节从LSB开始到MSB依次编号为1-4),若不同,则返回1;若相同,则返回0 仅能使用! ~ & ^ | + << >> 20
4 logicalAnd x&& y 仅能使用! ~ & ^ | + << >> 20
5 logicalOr x|| y 仅能使用! ~ & ^ | + << >> 20
6 rotateLeft 将x循环左移n位 仅能使用! ~ & ^ | + << >> 25
7 parityCheck 若x有奇数个1,则返回1;否则,返回0 仅能使用! ~ & ^ | + << >> 20

实现

将x的第n个字节取反(字节从LSB开始到MSB依次编号为0-3)

对某一位进行取反,就是和 111…0…11 进行异或操作[倒数第n位为0] ;计算这个数的步骤:将0…01左移n-1位 ;因为不能使用 - 操作符,那么就0…01先左移n位,再右移1位;

1.计算得出111…0…11 [倒数第n位为0]

2.与x进行异或运算 -> 1^0=1,0^0=1; 其他位置与1^后不变

1
2
3
4
5
6
int byteNot(int x, int n) {
int temp = (1 << n) >> 1;
printbinary(temp); //测试左移后得到的数是否正确
int result = x ^ temp;
return result;
}
比较x和y的第n个字节(字节从LSB开始到MSB依次编号为0-3),若不同,则返回1;若相同,则返回0

将x,y除第n个字节以外的置0:进行与运算,00…1…0[倒数第n位为1],这样得到的结果就是0…[本来的值]…0,同byteNot函数中的操作
最后再进行一次异或比较 注:要使相同为1,不同为0,需要先对计算后的x,y进行一次取反操作

1.计算得到00…1…0[倒数第n位为1]

2.与x,y进行与运算

3.两个结果进行异或比较

1
2
3
4
5
6
int byteXor(int x, int y, int n) {
int temp_x = (x << n) >> 1;
int temp_y = (y << n) >> 1;
int result = temp_x ^ temp_y;
return result;
}

注:两次逻辑非的使用 !! 作用是获得逻辑真/假,即1/0;

例:0010 ^ 0000 结果 0010 ,而结果要的是1,就使用!!

总结:其他数据类型向bool值的转换。

后面的代码就不一一分开详述了,思想在注释中
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
#include <iostream>
using namespace std;

// 十进制转二进制
void printbinary(int x)
{
for (int i = 16; i >= 0; i--)
{
if (x & (1 << i))
cout << "1";
else
cout << "0";
}
cout << endl;
}



//将x的最低有效位(LSB)清零
//要将最后一位清零,可以进行与运算是实现: 1 & 0 = 0; 0 & 0 = 0; -> 找一个最后一位为0[ &运算后归0 ],其余位为1[ &运算后不变 ]; 即 ~1 ;
int lsbZero(int x) {
int temp = ~1;
int result = x & temp;
return result;
}

//将x的第n个字节取反(字节从LSB开始到MSB依次编号为0-3)
//对某一位进行取反,就是和 111…0…11 进行异或操作[倒数第n位为0] ;计算这个数的步骤:将0…01左移n-1位 ;
//因为不能使用 - 操作符,那么就0…01先左移n位,再右移1位;
int byteNot(int x, int n) {
int temp = (1 << n) >> 1;
printbinary(temp); //测试左移后得到的数是否正确
int result = x ^ temp;
return result;
}

//比较x和y的第n个字节(字节从LSB开始到MSB依次编号为0-3),若不同,则返回1;若相同,则返回0
//将x,y除这一位以外的数都置0:进行与运算,00…1…0[倒数第n位为1],这样得到的结果就是0…[本来的值]…0,同byteNot函数中的操作
//最后再进行一次异或比较,要使相同为1,不同为0,需要先对计算后的x,y进行一次取反操作
int byteXor(int x, int y, int n) {
int temp = (1 << n) >> 1;
//printbinary(temp);
int temp_x = temp & x;
int temp_y = temp & y;
//printbinary(temp_x);
//printbinary(temp_y);
int result = !!(temp_x ^ temp_y);
return result;
}

// x && y
// 判断 !!x 是不是 1 ,是的话再判断!!y 是不是1 ,是的话返回1 ,不是返回0
// 仅用这些操作符,无法做到部分判断,那么就计算两个值加起来是不是2,是就代表逻辑真
bool logicalAnd(int x, int y) {
int temp = !!x + !!y;
bool result = !!(temp & 2);
return result;
}

//x || y
// 判断 !!x 是不是 1 ,是的话直接输出1,否则再判断!!y 是不是1 ,是的话返回1 ,不是返回0
// 仅用这些操作符,无法做到部分判断,那么就计算两个值加起来是不是不为0,是就代表逻辑真
bool logicalOr(int x,int y) {
int temp = !!x + !!y;
bool result = !!(temp);
return result;
}

// 将x循环左移n位
// 得到x的前n位,用temp记录,取出记录的前n位->前n位右移至低n位,即移动16-n位,只允许+,[二进制负数=正数值取反加1]则用+代替-,即17+~n
// 如果是负数得到结果前面全1,这样最后合并的时候,前面部分就会出现0被1替代的情况
// 所以:将右移的结果 & 00…11 [n个1],即~1 + (1 << n) + 1
int rotateLeft(int x,int n) {
int temp = x;
int temp2 = temp >> (~n + 17);
int temp3 =temp2 & (~1 + (1 << n) + 1);
//printbinary(temp2);
//printbinary(temp3);
//printbinary(temp);
//int result = (x << n) | ((temp >> (~n + 17)) & (~1 + (1 << n) + 1));
int result = (x << n) | temp3;
return result;
}

// 若x有奇数个1,则返回1;否则,返回0
// 给定二进制数01,它只有两位,那么它的奇偶性可以通过0^1 = 1获得,这里返回1,与它是奇数相符合。
// 给定二进制数11,它只有两位,那么它的奇偶性可以通过1^1 = 0获得,这里返回0,与它是偶数相符合。
// 总结:异或可以压缩两位上1个数的奇偶性。即压缩奇偶性信息为1或者0.
// 二叉树思想异或:每次将最后两位进行压缩; 那么目的就是不断右移,判断最后两位
bool parityCheck(int x) {
x = x ^ (x >> 1);
x = x ^ (x >> 2);
x = x ^ (x >> 4);
x = x ^ (x >> 8);
x = x & 1; //最后和1进行与运算,若1则返回1,表示奇数个;若0则返回0,表示偶数个;
return x;
}

// 计算2*x,如果不溢出,则返回1,否则,返回0
// 判断第一位是否相同:与10000…进行与运算,保留第一位,再将这两个数进行异或运算,即符号位相同,没溢出,不同代表溢出了
bool mul2OK(int x) {
int x2 = x << 1;
int temp_x = x & (1 << 16);
int temp_x2 = x2 & (1 << 16);
bool result = temp_x ^ temp_x2;
return result;
}


// 计算(x*3)/2,朝零方向取整
int mult3div2(int x) {
// 先计算x*3/2; *3用x+2x表示
int temp = (x << 1) + x;
// 如果是负数,取整要加上后一位的值
int flag = temp & (1 << 16); //同上进行一次与运算即可,得到符号位1000……,然后右移15位
flag = flag >> 16;
int result = temp >> 1; //进行除2操作,然后和~flag进行与运算:如果是正数那么还是原值,如果是负数,要再判断一下是否加最后一位的值,向0取整
result = ((~flag) & result) + (flag & (result + (temp & 1)));
return result;
}

// 计算x –y,如果不溢出,则返回1,否则,返回0
// 判断是否会溢出:异号相减才会发生 10-(-5),-10-5,才可能溢出,而10-5两个数都在范围内,相减的绝对值肯定小于任一数的绝对值,不可能溢出
bool subOK(int x,int y) {
int flag_x = x >> 16; //求x符号位
int flag_y = y >> 16; //求y符号位
int flag = (~y + x + 1) >> 16; //x-y 用 ~y + x +1表示 ,然后求符号位
//判断x,y是否异号,然后判断flag是否和x符号一致 期望:x,y异号,x,z异号,此时溢出返回0
bool result = (flag_x ^ flag_y) & (flag_x ^ flag);
return !result;
}


// 求x的绝对值
// 负数的话将第一位修改为0即可 :和 0111…进行与操作
int absVal(int x) {
//获得操作数0111…:100…取~值,即将1左移17位再~
int temp = ~(1 << 16);
//取出符号位
int flag = x >> 16;
//printbinary(temp); //验证是不是0111…
//通过符号位控制是否要对原始数据进行改变,原理同 mult3div2 函数
//负数的话要取反码+1
int result = ((~flag) & x) + (flag & ((~x) + 1));
//printbinary(x);
//printbinary(result); //输出二进制表示,验证结果
return result;
}

int main() {
cout<< " ************** 测试案例1 ****************** "<< endl;
printf("%d", sizeof(int*));

int x = 5 ; // 0101
int y = 6 ; // 0110
int z = 7 ; // 0111
int m = 0 ;
int n = 52222 ;
cout << "-----将x的最低有效位(LSB)清零-----" << endl;
cout << "输入x值为:";
cin >> x;
printbinary(lsbZero(x));
cout << "------将x的第n个字节取反----" << endl;
cout << "输入x值为:";
cin >> x;
cout << "输入n值为:";
cin >> n;
printbinary(byteNot(x,n));
cout << "-----比较x和y的第n个字节,若不同,则返回1;若相同,则返回0-----" << endl;
cout << "输入x值为:";
cin >> x;
cout << "输入y值为:";
cin >> y;
cout << "输入n值为:";
cin >> n;
printbinary(byteXor(x,y,n));
cout << "输入x值为:";
cin >> x;
cout << "输入y值为:";
cin >> y;
cout << "输入n值为:";
cin >> n;
printbinary(byteXor(x,y,n));
cout << "-----x && -----" << endl;
cout << "输入x值为:";
cin >> x;
cout << "输入y值为:";
cin >> y;
cout << logicalAnd(x, y) << endl;
cout << "-----x || y-----" << endl;
cout << "输入x值为:";
cin >> x;
cout << "输入y值为:";
cin >> y;
cout << logicalOr(x, y) << endl;
// cout << "----------" << endl;
// cout << logicalAnd(x, m) << endl;
cout << "-----将x循环左移n位-----" << endl;
cout << "输入x值为:";
cin >> x;
cout << "输入n值为:";
cin >> n;
cout << "循环前:" << endl;
printbinary(x);
printbinary(rotateLeft(x, n));
cout << "-----若x有奇数个1,则返回1;否则,返回0-----" << endl;
cout << "输入x值为:";
cin >> x;
cout << "x的二进制表示为:";
printbinary(x);
cout << "结果如下:";
cout << endl << parityCheck(x);
cout << endl << "-----计算2*x,如果不溢出,则返回1,否则,返回0-----" << endl;
cout << "输入x值为:";
cin >> x;
cout << mul2OK(x);
cout << endl << "-----计算(x*3)/2,朝零方向取整-----" << endl;
cout << "输入x值为:";
cin >> x;
//printbinary(50000);
cout << mult3div2(x);
cout << endl << "----计算x –y,如果不溢出,则返回1,否则,返回0------" << endl;
cout << "输入x值为:";
cin >> x;
cout << "输入y值为:";
cin >> y;
cout << subOK(x,y);
cout << endl << "-----求x的绝对值-----" << endl;
cout << "输入x值为:";
cin >> x;
cout << absVal(x) <<endl ;
}

在Liunx中用gcc实现

Makefile文件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
test: main.o printbinary.o lsbZero.o byteNot.o byteXor.o logicalAnd.o logicalOr.o rotateLeft.o parityCheck.o mul2OK.o mult3div2.o subOK.o absVal.o
g++ -o test main.o printbinary.o lsbZero.o byteNot.o byteXor.o logicalAnd.o logicalOr.o rotateLeft.o parityCheck.o mul2OK.o mult3div2.o subOK.o absVal.o

main.o: main.c test.h
g++ -c main.c

printbinary.o: printbinary.c test.h
g++ -c printbinary.c

lsbZero.o: lsbZero.c test.h
g++ -c lsbZero.c

byteNot.o: byteNot.c test.h
g++ -c byteNot.c

byteXor.o: byteXor.c test.h
g++ -c byteXor.c

logicalAnd.o: logicalAnd.c test.h
g++ -c logicalAnd.c

logicalOr.o: logicalOr.c test.h
g++ -c logicalOr.c

rotateLeft.o: rotateLeft.c test.h
g++ -c rotateLeft.c

parityCheck.o: parityCheck.c test.h
g++ -c parityCheck.c

mul2OK.o: mul2OK.c test.h
g++ -c mul2OK.c

mult3div2.o: mult3div2.c test.h
g++ -c mult3div2.c

subOK.o: subOK.c test.h
g++ -c subOK.c

absVal.o: absVal.c test.h
g++ -c absVal.c

clean:
rm -rf test
rm -rf *.o

test文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#ifndef _TEST_H
#define _TEST_H
void printbinary(int x);
int lsbZero(int x);
int byteNot(int x, int n);
int byteXor(int x, int y, int n);
bool logicalAnd(int x, int y);
bool logicalOr(int x,int y);
int rotateLeft(int x,int n);
bool parityCheck(int x);
bool mul2OK(int x);
int mult3div2(int x);
bool subOK(int x,int y);
int absVal(int x);
int main();
#endif

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <iostream>
#include "test.h"
using namespace std;

int main() {
cout<< " ************** 测试案例1 ****************** "<< endl;
// cout << sizeof(int*);

int x = 5 ; // 0101
int y = 6 ; // 0110
int z = 7 ; // 0111
int m = 0 ;
int n = 52222 ;
cout << "-----将x的最低有效位(LSB)清零-----" << endl;
cout << "输入x值为:";
cin >> x;
printbinary(lsbZero(x));
cout << "------将x的第n个字节取反----" << endl;
cout << "输入x值为:";
cin >> x;
cout << "输入n值为:";
cin >> n;
printbinary(byteNot(x,n));
cout << "-----比较x和y的第n个字节,若不同,则返回1;若相同,则返回0-----" << endl;
cout << "输入x值为:";
cin >> x;
cout << "输入y值为:";
cin >> y;
cout << "输入n值为:";
cin >> n;
printbinary(byteXor(x,y,n));
cout << "输入x值为:";
cin >> x;
cout << "输入y值为:";
cin >> y;
cout << "输入n值为:";
cin >> n;
printbinary(byteXor(x,y,n));
cout << "-----x && -----" << endl;
cout << "输入x值为:";
cin >> x;
cout << "输入y值为:";
cin >> y;
cout << logicalAnd(x, y) << endl;
cout << "-----x || y-----" << endl;
cout << "输入x值为:";
cin >> x;
cout << "输入y值为:";
cin >> y;
cout << logicalOr(x, y) << endl;
// cout << "----------" << endl;
// cout << logicalAnd(x, m) << endl;
cout << "-----将x循环左移n位-----" << endl;
cout << "输入x值为:";
cin >> x;
cout << "输入n值为:";
cin >> n;
cout << "循环前:" << endl;
printbinary(x);
printbinary(rotateLeft(x, n));
cout << "-----若x有奇数个1,则返回1;否则,返回0-----" << endl;
cout << "输入x值为:";
cin >> x;
cout << "x的二进制表示为:";
printbinary(x);
cout << "结果如下:";
cout << endl << parityCheck(x);
cout << endl << "-----计算2*x,如果不溢出,则返回1,否则,返回0-----" << endl;
cout << "输入x值为:";
cin >> x;
cout << mul2OK(x);
cout << endl << "-----计算(x*3)/2,朝零方向取整-----" << endl;
cout << "输入x值为:";
cin >> x;
//printbinary(50000);
cout << mult3div2(x);
cout << endl << "----计算x –y,如果不溢出,则返回1,否则,返回0------" << endl;
cout << "输入x值为:";
cin >> x;
cout << "输入y值为:";
cin >> y;
cout << subOK(x,y);
cout << endl << "-----求x的绝对值-----" << endl;
cout << "输入x值为:";
cin >> x;
cout << absVal(x) <<endl ;
}
函数示例:
项目结构:

运行结果1:

1将x的最低有效位(LSB)清零

x = 5 即 0101 清零后 0100

2将x的第n个字节取反(字节从LSB开始到MSB依次编号为1-4)

x = 5 n = 2; 取反后 0110

3 比较x和y的第n个字节(字节从LSB开始到MSB依次编号为1-4),若不同,则返回1;若相同,则返回0

x = 5 即0101 ; y = 6 即0110 ; n = 2; 第二个字节不一样,返回0

x = 6 即0110 ; y = 7 即0111 ; n = 2; 第二个字节一样,返回1

4 x&& y

x = 10 ; y =-10 ; 都是非0,返回1

5 x|| y

x = 10 ; y =0 ; 不全0,返回1

6 将x循环左移n位

x = -1002 n = 5;

循环左移前:11111110000010110

循环左移后:11000001011011111

7 若x有奇数个1,则返回1;否则,返回0

x = 103 ;即00000000001100111 5个1返回1

8 计算2*x,如果不溢出,则返回1,否则,返回0

x = 5000; 溢出返回0

9 计算(x*3)/2,朝零方向取整

x = -104 -104*3/2 = -156 返回-156

x = 105 105*3/2 = 157.5 返回 157

10 计算x –y,如果不溢出,则返回1,否则,返回0

x = 50000 y = -50000 溢出返回1

11 求x的绝对值

x = -1900 返回1900

运行结果2:

1将x的最低有效位(LSB)清零

x = 13 即 1101 清零后 1100

2将x的第n个字节取反(字节从LSB开始到MSB依次编号为1-4)

x = 12 即 1100 n = 3; 取反后 1000

3 比较x和y的第n个字节(字节从LSB开始到MSB依次编号为1-4),若不同,则返回1;若相同,则返回0

x = 12 即1100 ; y = 13 即1001 ; n = 2; 第二个字节一样,返回1

x = 12 即1100 ; y = 13 即1001 ; n = 1; 第1个字节不一样,返回0

4 x&& y

x = 10 ; y = 0 ; y为0,返回 0

5 x|| y

x = 0 ; y = 0 ; x,y全0,返回0

6 将x循环左移n位

x = 998 n = 4;

循环左移前:11111110000010110

循环左移后:11000001011011111

7 若x有奇数个1,则返回1;否则,返回0

x = 120 ;即00000000001100111 4个1返回0

8 计算2*x,如果不溢出,则返回0,否则,返回1

x = 20; 不溢出返回0

9 计算(x*3)/2,朝零方向取整

x = -105 -105*3/2 = -157.5 返回-157

10 计算x–y,如果不溢出,则返回1,否则,返回0

x = 500 y = -500 不溢出返回1

11 求x的绝对值

x = 1900 返回1900

注:第8个求两倍溢出的可能有些逻辑问题需要更改,等有空重新写一个函数

解决的问题:

在编写完makefile文件后,在终端输入make命令进行编译,报错:*** 没有规则可制作目标“/xxx.c”,由“/xxx.o” 需求。 停止。

解决方案:空格替换Tab ; 成功运行 ;


数据的位运算及补码运算[makefile的简答使用]
http://example.com/2023/03/16/数据的位运算及补码运算-makefile的简答使用/
作者
zhanghao
发布于
2023年3月16日
许可协议