实验10位运算 【实验目的】 1. 掌握位运算的概念和方法: 2.掌握位运算的使用。 【相关知识点】 1.位运算符 所谓位运算是指进行二进制位的运算,C语言提供如下表所示的位运算符: 运算符 含义 运算符 含义 & 按位与 取反 按位或 左移 按位异或 > 右移 说明: (1)位运算中除了~之外,均为双目运算符: (2)运算对象只能是整型或字符型数据,不能为实型数据。 2.“按位与”运算 参加运算的两个数据,按二进制位进行“与”运算(运算符为&),如果两个相应的二进 制位都为1,则结果值为1,否则为0,即: 0&0=0,0&1=0,1&0=0,1&1=1 示例: 3&5,按照如下方法计算: 00000011(3) &00000101(⑤) 00000001(1)P 3.“按位或”运算 参加运算的两个数据,按二进制位进行“或”运算(运算符为),两个相应的二进制位中 -206-
实验 10 位运算 【实验目的】 1. 掌握位运算的概念和方法; 2. 掌握位运算的使用。 【相关知识点】 1. 位运算符 所谓位运算是指进行二进制位的运算,C 语言提供如下表所示的位运算符: 运算符 含义 运算符 含义 & 按位与 ~ 取反 | 按位或 > 右移 说明: (1)位运算中除了~之外,均为双目运算符; (2)运算对象只能是整型或字符型数据,不能为实型数据。 2. “按位与”运算 参加运算的两个数据,按二进制位进行“与”运算(运算符为&),如果两个相应的二进 制位都为 1,则结果值为 1,否则为 0,即: 0&0=0, 0&1=0, 1&0=0, 1&1=1 示例: 3&5,按照如下方法计算: 3. “按位或”运算 参加运算的两个数据,按二进制位进行“或”运算(运算符为|),两个相应的二进制位中 - 206 -
只要有一个为1,该位的结果为1,即: 010=0,011=1,10=1,11=1 示例: 35,按照如下方法计算: 00000011 (3) 00000101 (5)Ψ 00000111 (⑦) 4.“异或”运算 参加运算的两个数据,按二进制位进行“异或”运算(运算符为^),两个二进制位相同, 则结果为0,两个二进制位不同,则结果为1,即: 00=0,01=1,10=1,11=0 示例: 35,按照如下方法计算: 00000011 (3)Ψ A00000101(⑤)+ 00000110(6 5.“取反”运算 ~是一个单目运算符,用来对一个二进制数按位取反,即将0变1,将1变0。 示例: ~00000101 11111010 6.“左移”运算 用来将一个数的各二进制位全部左移若干位。 示例: x=x<<2,表示将x的二进制数左移2位,右边补2个0,若a=15,其二进制数为 00001111,左移2位得00111100,其对应的十进制数是60,左移1位相当于该数乘以2, 左移2位相当于该数乘以2=4,此结论只合适于该数左移时被溢出舍弃的高位不包含1 的情况。 -207-
只要有一个为 1,该位的结果为 1,即: 0|0=0, 0|1=1, 1|0=1, 1|1=1 示例: 3|5,按照如下方法计算: 4. “异或”运算 参加运算的两个数据,按二进制位进行“异或”运算(运算符为^),两个二进制位相同, 则结果为 0,两个二进制位不同,则结果为 1,即: 0^0=0, 0^1=1, 1^0=1, 1^1=0 示例: 3^5,按照如下方法计算: 5. “取反”运算 ~是一个单目运算符,用来对一个二进制数按位取反,即将 0 变 1,将 1 变 0。 示例: 6. “左移”运算 用来将一个数的各二进制位全部左移若干位。 示例: x=x<<2,表示将x的二进制数左移 2 位,右边补 2 个 0,若a=15,其二进制数为 00001111,左移 2 位得 00111100,其对应的十进制数是 60,左移 1 位相当于该数乘以 2, 左移 2 位相当于该数乘以 22 =4,此结论只合适于该数左移时被溢出舍弃的高位不包含 1 的情况。 - 207 -
7.“右移”运算 用来将一个数的各二进制位全部右移若干位。 示例: x=x>>2,表示将x的二进制数右移2位,左边补2个0,若a=16,其二进制为00010000, 右移2位得00000100,其对应的十进制数是4,右移2位相当于该数除以4,在右移时,需要 注意符号位问题,对于无符号数,右移时左边高位移入0,对于有符号数,如果原来符号位为 0,则左边也是移入0,如果原来符号位为1,左边移入的还是1。这主要取决于所用的计算机 系统,有的系统移入0,称为“逻辑右移”,有的系统移入1,称为“算术右移”。 【实验任务】 一、程序改错 该部分实验主要训练学生读简单程序的能力,并在理解程序的基础上,改正程序中出现 的问题,这些问题都是初学者经常容易犯的错误,针对位运算这一章,主要有如下问题: 1)位运算中的运算数据是实型; 2)“按位异或”运算的规则运用颠倒,即二进制位相同结果为1,二进制位不同,结果 为0: 3)“&”运算符和“&&”运算符混淆。 针对上面出现的问题,查找下面程序中存在的问题,并改正调试。 1.打开c:lc-programming\10\pg10101.cpp,该程序将两个数做“按位与”运算,有一个小 问题,请修改,使程序能正确运行。修改后的程序以pg10101ok.cpp保存。该源程序内容如 下: #include void main(void) float a,b,c; printf("请输入两个数,中间用逗号分隔:")方 scanf("%f,%f",&a,&b); c=a&b: -208-
7. “右移”运算 用来将一个数的各二进制位全部右移若干位。 示例: x=x>>2,表示将 x 的二进制数右移 2 位,左边补 2 个 0,若 a=16,其二进制为 00010000, 右移 2 位得 00000100,其对应的十进制数是 4,右移 2 位相当于该数除以 4,在右移时,需要 注意符号位问题,对于无符号数,右移时左边高位移入 0,对于有符号数,如果原来符号位为 0,则左边也是移入 0,如果原来符号位为 1,左边移入的还是 1。这主要取决于所用的计算机 系统,有的系统移入 0,称为“逻辑右移”,有的系统移入 1,称为“算术右移”。 【实验任务】 一、程序改错 该部分实验主要训练学生读简单程序的能力,并在理解程序的基础上,改正程序中出现 的问题,这些问题都是初学者经常容易犯的错误,针对位运算这一章,主要有如下问题: 1) 位运算中的运算数据是实型; 2) “按位异或”运算的规则运用颠倒,即二进制位相同结果为 1,二进制位不同,结果 为 0; 3) “&”运算符和“&&”运算符混淆。 针对上面出现的问题,查找下面程序中存在的问题,并改正调试。 1.打开 c:\c-programming\10\pg10101.cpp,该程序将两个数做“按位与”运算,有一个小 问题,请修改,使程序能正确运行。修改后的程序以 pg10101_ok.cpp 保存。该源程序内容如 下: #include void main(void) { float a,b,c; printf("请输入两个数,中间用逗号分隔:"); scanf("%f,%f",&a,&b); c=a&b; - 208 -
printf("c=%fn",c); } 了提示:如何发现问题? 编译该程序,系统报告两个编译出错信息,如图10.11所示,第1和第2条信息分别指 示“&”运算符左边和右边运算数为实型数,非法。原因在于,参与“按位与”运算的运算对 象不能是实型。 ☒Conpiling. sNe-programming\19\pg10101.cpp(7):error C2296::illegal,left operand has tupe.Flo C:\c-programming\10\pg10101.cpp(7):error C2297:'&'illegal,right operand has type 'float' Error executing cl.exe. pg10101.obj 2 error(s),0 warning(s) ☑□编译调试查找文件1入查技文件2人结果入s0 L Debug?i?+」 Ln 9,Col 1 REC COL OVR READ 图10.1.1程序编译后的错误信息 改正程序后的运行结果示例如图10.1.2所示: C:\c-programming\10\Debug\pg10101_ok.exe" 回 请输入两个数,中间用逗号分隔:3.5 c= Press any key to continue 图10.1.2pg10101_ok.cpp的运行结果 2.打开c:lc-programming\10pgl0102.cpp,该程序是将整数10对应的二进制的低四位翻 转,即1变0,0变1,有一个小问题,请修改,使程序能正确运行。修改后的程序以pg10102_ok.cpp 保存。该源程序内容如下: #include void main(void) int a=10; a=a0: printf("运算结果为:%dn",a; } 了提示:如何发现问题? -209-
printf("c=%f\n",c); } 提示:如何发现问题? 编译该程序,系统报告两个编译出错信息,如图 10.1.1 所示,第 1 和第 2 条信息分别指 示“&”运算符左边和右边运算数为实型数,非法。原因在于,参与“按位与”运算的运算对 象不能是实型。 图 10.1.1 程序编译后的错误信息 改正程序后的运行结果示例如图 10.1.2 所示: 图 10.1.2 pg10101_ok.cpp 的运行结果 2.打开 c:\c-programming\10\pg10102.cpp,该程序是将整数 10 对应的二进制的低四位翻 转,即1变0,0变1,有一个小问题,请修改,使程序能正确运行。修改后的程序以pg10102_ok.cpp 保存。该源程序内容如下: #include void main(void) { int a=10; a=a^0; printf("运算结果为:%d\n",a); } 提示:如何发现问题? - 209 -
编译、链接该程序,系统未报告任何错误信息,但是运行该程序时结果为10,a变量的值 未变。按照程序思路,分析一下a0的运算,其中变量a对应的二进制数为00001010,和0 做“按位异或”运算,前四位对应位相同,结果为0000:后四位按照对应位相同结果为0, 对应位不同结果为1的原则进行,结果为1010,最终a的二进制数仍然为00001010,未变。 按照题目要求,a变量其低四位翻转,高四位不变,则应该保证和a做“按位异或”运算的运 算数据的低四位为1,高四位为0,即00001111,该二进制数对应的十进制数为15,故a=a0, 应改为a=a15。 改正程序后的运行结果示例如图10.1.3所示。 "C:\c-programming\10\Debug\pg10102_ok.exe" 回8 运算结果为:5 Press any key to continue 图10.1.3pg10102ok.cpp的运行结果 3.打开c:\c-programming\10八pgl0103.cpp,该程序是将十进制数84(其对应的二进制数为 01010100)的最后四位保留下来,有一个小问题,请修改,使程序能正确运行。修改后的程 序以pg10103_ok.cpp保存。该源程序内容如下: #include void main(void) int i; i=84; i=i&&15, printf"i=%dn",i方 } 了提示:如何发现问题? 编译、链接该程序,系统未报告任何错误信息,但是运行该程序时结果为1,按照题目的 意思,最终结果应该为00000100,其十进制数为4。而给出的程序结果为1的原因运算符使 用错误,“&&”运算符和“&”运算符是两个不同的运算符,前者是“逻辑与”运算符,其左 右两边的运算数据如果都为真,其结果就为逻辑真(以数值1代表真),而后者是“按位与” 运算符。 -210-
编译、链接该程序,系统未报告任何错误信息,但是运行该程序时结果为 10,a 变量的值 未变。按照程序思路,分析一下 a^0 的运算,其中变量 a 对应的二进制数为 00001010,和 0 做“按位异或”运算,前四位对应位相同,结果为 0000;后四位按照对应位相同结果为 0, 对应位不同结果为 1 的原则进行,结果为 1010,最终 a 的二进制数仍然为 00001010,未变。 按照题目要求,a 变量其低四位翻转,高四位不变,则应该保证和 a 做“按位异或”运算的运 算数据的低四位为 1,高四位为 0,即 00001111,该二进制数对应的十进制数为 15,故 a=a^0, 应改为 a=a^15。 改正程序后的运行结果示例如图 10.1.3 所示。 图 10.1.3 pg10102_ok.cpp 的运行结果 3.打开 c:\c-programming\10\pg10103.cpp,该程序是将十进制数 84(其对应的二进制数为 01010100)的最后四位保留下来,有一个小问题,请修改,使程序能正确运行。修改后的程 序以 pg10103_ok.cpp 保存。该源程序内容如下: #include void main(void) { int i; i=84; i=i&&15; printf("i=%d\n",i); } 提示:如何发现问题? 编译、链接该程序,系统未报告任何错误信息,但是运行该程序时结果为 1,按照题目的 意思,最终结果应该为 00000100,其十进制数为 4。而给出的程序结果为 1 的原因运算符使 用错误,“&&”运算符和“&”运算符是两个不同的运算符,前者是“逻辑与”运算符,其左 右两边的运算数据如果都为真,其结果就为逻辑真(以数值 1 代表真),而后者是“按位与” 运算符。 - 210 -
改正程序后的运行结果示例如图10.1.4所示。 e"C:\c-programming\10\Debug\pg10103_ok.exe" 回 1=4 Press any key to continue 图10.1.4pg10103_ok.cpp的运行结果 二、程序扩展 l.打开c:lc-programming\10\pg1(0201.cpp,该程序是从一个整数a右端开始,取出其第5 位到第8位。该源程序内容如下: #include void main(void) unsigned a.b.c.d: printf("请输入一个八进制数a:"); scanf"%o",&a方 b=a>>4; c=(0<<4) d=b&c; printf("a=%0,%dn",a,a); printf"d=%0,%d\n",d,d); } 要求:修改上面的程序,要求实现从一个整数a右端开始,取出其第m位到第n位,其 中m和n的值通过键盘输入。修改后的程序以pg5201a.cpp保存。 训练要点:读懂程序中取二进制整数中若干位的算法思路,掌握位运算符的运算规则, 在此基础上,增加变量m和n,实现从右端开始,取其任意段的二进制位的问题。 修改后程序的运行结果如图10.1.5所示。 -211-
改正程序后的运行结果示例如图 10.1.4 所示。 图 10.1.4 pg10103_ok.cpp 的运行结果 二、程序扩展 1.打开 c:\c-programming\10\pg10201.cpp,该程序是从一个整数 a 右端开始,取出其第 5 位到第 8 位。该源程序内容如下: #include void main(void) { unsigned a,b,c,d; printf("请输入一个八进制数 a:"); scanf("%o",&a); b=a>>4; c=~(~0<<4); d=b&c; printf("a=%o,%d\n",a,a); printf("d=%o,%d\n",d,d); } 要求:修改上面的程序,要求实现从一个整数 a 右端开始,取出其第 m 位到第 n 位,其 中 m 和 n 的值通过键盘输入。修改后的程序以 pg5201a.cpp 保存。 训练要点:读懂程序中取二进制整数中若干位的算法思路,掌握位运算符的运算规则, 在此基础上,增加变量 m 和 n,实现从右端开始,取其任意段的二进制位的问题。 修改后程序的运行结果如图 10.1.5 所示。 - 211 -
e"C:\e-programming\10\Debug\pg10201a.exe 回 请输入一个八进制数a:331 人a右端开始,取出其第m位到第n位。 请输入整数n和n,中间用溟号分隔:5.& a的八进制数和十进制数芬别为:331,21? 取出结果的八进制和十进制数分别为:15,13 Press any key to continue 图10.1.5pg10201a.cpp的运行结果 2.打开c:lc-programming1O八pgl0202.cpp,该程序是将一个整数a进行右循环移n位,即 将a中原来左边(32-n)位右移n位,原来最右端n位移到最左边n位。该源程序内容如下: #include void main(void) unsigned a.b.c: int n; printf("请输入整数a(八进制数)和n(十进制数),中间用逗号分隔:")方 scanf("%0,%d",&a,&n); b=a>n: c=clb; printf"最终结果c=%on",c;少 } 要求:修改上面的程序,将一个整数a进行右循环移n位改为进行左循环移n位,修改后 的程序以pgl0202a.cpp保存。 训练要点:读懂程序中将一个整数a进行右循环移n位的算法思路,掌握位运算符的运算 规则,在此基础上,实现左循环移n位。 修改后程序的运行结果如图10.1.6所示。 ex"C:\c-programming\10\Debug\pg10202a.exe" 回☒ 情搅公整数a(八进制数>和n<十进制数),中间用逗号分隔:7.3园 最终结果c=?8 Press any key to continue 图10.1.6pg10202a.cpp的运行结果 -212-
图 10.1.5 pg10201a.cpp 的运行结果 2.打开 c:\c-programming\10\pg10202.cpp,该程序是将一个整数 a 进行右循环移 n 位,即 将 a 中原来左边(32-n)位右移 n 位,原来最右端 n 位移到最左边 n 位。该源程序内容如下: #include void main(void) { unsigned a,b,c; int n; printf("请输入整数 a(八进制数)和 n(十进制数),中间用逗号分隔:"); scanf("%o,%d",&a,&n); b=a>n; c=c|b; printf("最终结果 c=%o\n",c); } 要求:修改上面的程序,将一个整数 a 进行右循环移 n 位改为进行左循环移 n 位,修改后 的程序以 pg10202a.cpp 保存。 训练要点:读懂程序中将一个整数 a 进行右循环移 n 位的算法思路,掌握位运算符的运算 规则,在此基础上,实现左循环移 n 位。 修改后程序的运行结果如图 10.1.6 所示。 图 10.1.6 pg10202a.cpp 的运行结果 - 212 -
三、程序编写 1.编写一个函数getbits,从一个32位的整数单元中取出某几位(即该几位保留原值,其余 位为0,并将取出的那几位移到最低位),例如:getbits(0173253,21,24),函数返回值为6(即 二进制数01l0),该函数包含三个参数,分别为value(待取整数的八进制数),nl(取出的起 始位),n2(取出的结束位),起始位和结束位都是从左向右计算。编写的源程序以pg10301.cpp 保存。 训练要点:掌握位运算的使用。 程序运行结果参考示例如图10.1.7所示。 e"C:\c-programming\10\Debug\pg10301.exe" 回 请输入一个八进制数ua1ue:13253 请输入起始位n1和结束位n2,中间用逗号分隔:21,24 结果为:result=6 Press any key to continue 图10.1.7pg10301.cpp的运行结果 2.编写一个函数move,功能是实现左右循环移位,该函数包含两个参数,分别为value(要 循环移位的整数),n(移位的位数,如果n0表示右移)。编写的源程序以 pgl0302.cpp保存。 训练要点:掌握位运算的使用。 程序运行结果参考示例如图10.1.8所示。 "C:\e-programming\10\Debug\pg10302.exe" 回区 请输入一个八进制数a1ue:7 入一个整数n: -3 循环移位后的结果为:*esu1t=?阳 Press any key to continue 图10.1.8pg10302.cpp的运行结果 -213-
三、程序编写 1.编写一个函数 getbits,从一个 32 位的整数单元中取出某几位(即该几位保留原值,其余 位为 0,并将取出的那几位移到最低位),例如:getbits(0173253,21,24),函数返回值为 6(即 二进制数 0110),该函数包含三个参数,分别为 value(待取整数的八进制数),n1(取出的起 始位),n2(取出的结束位),起始位和结束位都是从左向右计算。编写的源程序以 pg10301.cpp 保存。 训练要点:掌握位运算的使用。 程序运行结果参考示例如图 10.1.7 所示。 图 10.1.7 pg10301.cpp 的运行结果 2.编写一个函数 move,功能是实现左右循环移位,该函数包含两个参数,分别为 value(要 循环移位的整数),n(移位的位数,如果 n0 表示右移)。编写的源程序以 pg10302.cpp 保存。 训练要点:掌握位运算的使用。 程序运行结果参考示例如图 10.1.8 所示。 图 10.1.8 pg10302.cpp 的运行结果 - 213 -