注意!这些作业以及实验都要求在32位机器上实现哦!
2.59
编写一个C表达式,生成一个字,由x的最低有效字节和y中剩下的字节组成。
对于运算数x=0x89ABCDEF,y=0x76543210,就得到0x765432EF
Tips. 一个字长等于32位,一个字节是8位。所以最低有效字节是末8位。
(1)首先要取出x的最低有效字节,可以采用 x & 0xFF 的方法

(2)再取出y的剩下字节,可采用 y & ~0xFF 的方法,

步骤(1)(2)这里都运用到了与1相与是本身,与0相与是0的思想。
(3)然后考虑到一个数与0相或是它本身,所以把这两部分相或就能得到结果。

2.61
写一个C表达式,在下列描述的条件下产生1,而在其他情况下得到0。假设x是int类型。
A:x的任何位都等于1
B:x的任何位都等于0
C:x的最低有效字节中的位都等于1
D:x的最高有效字节中的位都等于0
限制:不能使用(==)和(!=)
在课本第二章P39的2.1.8中,我们知道逻辑运算符(|| && !),他们将0视作逻辑“FALSE”(假);将所有非0值视作逻辑“TRUE”(真);计算结果总是0/1。
A.当x的任何位都等于1时产生1——可以先全部按位取反,这样得到任何位都应该是0,再通过逻辑非运算(!)就可以产生1
例:0x 1111 1111取反->0x 0000 0000->逻辑非运算->0x 0000 0001,此时为非零值,返回1
0x 1111 0000取反->0x 0000 1111->逻辑非运算->0x 0000 0000,此时为0,返回0
emm,我觉得也可以这么记逻辑非——原来不是0(不管你是1,2,3……还是100000……),逻辑非后就都成了0;原来是0,逻辑非后就成了非0值(也就是1)
B.当x的任何位都等于0时产生1——直接使用逻辑非运算(!)即可
例:0x 0000 0000->逻辑非->0x 0000 0001,此时为非零值,返回1
0x 1111 0000->逻辑非->0x 0000 0000,此时为0,返回0
C.x的最低有效字节中的位都等于1时产生1——
思路:2.59+2.61(A)
(1)获取x的最低字节:x & 0xFF
(2)套用A中的公式:!~ (x & 0xFF)
例:0x 0000 0000 & 0xFF-> 0x 0000 0000->取反得0x 1111 1111-> 逻辑非运算得 0
D.x的最高有效字节中的位都等于0时产生1——
思路:(1)抽取最高有效字节-> x & (0xff00 0000)
(2)直接返回即可
2.64
/*Return 1 when any odd bit of x equals 1;0 otherwise. Assume w=32 */
/*当x的奇数位为1时返回1,否则返回0*/
int any_odd_one(unsigned x);
函数应该遵循位级整数编码规则,不过你可以假设数据类型int有w=32位。
(1)首先构造掩码,使用移位运算符构造出奇数位全1的数(mask) ,
(2)然后获取输入值 x 的奇数位,其他位清零,也就是(mask & x),然后与mask进行异或操作,若(mask & x)与mask相同则最终结果为0,然后返回其值的逻辑非,也就是返回1
- #include
-
- /* Return 1 when odd bit of x equals 1; 0 otherwise
- Assume w=32 */
-
- int any_odd_one(unsigned x) {
- /* Mask 0xAAAAAAAA */
- unsigned mask = (0xAA << 24) | (0xAA << 16) | (0xAA << 8) | (0xAA);
- return !((mask & x) ^ mask);
-
- void main(){
- printf("result %d",any_odd_one(0x10));
- printf("\n");
- }
2.66
/* 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);
这道题理解题目我想了很久诶TUT
先来分析一下题目给的示例——
0x FF00的二进制表示为1111 1111 0000 0000,0x 8000 的二进制表示为 1000 0000 0000 0000
0x 6600的二进制表示为0110 0110 0000 0000,0x 4000的二进制表示为 0100 0000 0000 0000
再结合 Generate mask indicating leftmost 1 in x这句话,我们可以知道这道题的意思是:让最左边的1的右边全部为0.
(1)先让最左边的1的右边全部变成1,得到新的数x
(2)得到的x右移一位再加一,就可以得到原来的数的最左边的1的右边全为0的数了
补充:代码中(x>>1)并没有直接+1,而是+(x&&1),这里用(x&&1)来判断x是不是0,在上面那道题也说了,逻辑运算符(|| && !),他们将0视作逻辑“FALSE”(假);将所有非0值视作逻辑“TRUE”(真);计算结果总是0/1。 那么在(x&&1)这个式子中,当x==0时,运算结果为0;当x是其他数时,运算结果为1
- #include <stdio.h>
- #include <assert.h>
-
- int leftmost_one(unsigned x) {
- x |= x >> 16;
- x |= x >> 8;
- x |= x >> 4;
- x |= x >> 2;
- x |= x >> 1;
- return (x >> 1) + ( x && 1);
- }
-
- int main() {
- assert(leftmost_one(0xff00)==0x8000);
- assert(leftmost_one(0x6600)==0x4000);
- return 0;
- }
2.72
You are given the task of writing a function that will copy an integer
valinto a bufferbuf, but it should do so only if enough space is available in the buffer.Here is the code you write:
/* Copy integer into buffer if space is available */
/* WARNING: The following code is buggy */
void copy_int(int val, void *buf, int maxbytes) { if(maxbytes-sizeof(val) >= 0) { memcpy(buf, (void*)&val, sizeof(val)); } }测试这段代码后,哪怕maxbytes很小的时候,它也能把值复制到缓冲区。
A.解释为什么代码中的条件测试总是成功。提示:sizeof运算符返回类型为size-t的值
B.你该如何重写这个条件测试,使之工作正确。
A.因为运算结果是无符号数,而无符号数肯定是大于等于零的,所以这个测试总是成功。
B.条件测试改为 maxbytes >=sizeof(val)
- #include <stdio.h>
- #include <assert.h>
-
- int conditional_test(int val, int maxbytes) {
- return maxbytes >= (int)sizeof(val);
- }
-
- int main() {
- assert(conditional_test(0, 4));
- assert(!conditional_test(0, 2));
- assert(!conditional_test(0, 0));
- return 0;
- }
2.77
将整数变量x乘以不同的常数因子K。为了提高效率,我们想只用+、=、<<运算。
A.K=17
B.K=-7
C.K=60
D.K=-112
可以通过(x<
2.85 给定具有 k 位指数和 n 位小数的浮点格式,对于下列数,写出阶码(指数) E、尾数(有效数) M、小数 f 和值 V 。此外,描述位表示形式。 A.数7.0 B.能够被准确描述的最大奇整数 C.最小的规格化数的倒数
首先,我们得知道基本的知识点,我列出几个式子——
偏置值——bias=2^(k-1)-1,其中k为阶码段的长度。例如:bias(float)=2^(7-1)-1=127
值V——V=(-1)^S*M*2^E
阶码的值——(1)规格化数:E=e-bias。其中e为阶码段的值。以float为例,阶码段长度为8,而规格化数的阶码段不全为0/不全为1;那么e的最小值为0000 0001,也就是1,e的最大值为1111 1110,也就是254
(2)非规格化数:E=1-bias
尾数——(1)规格化数:M=1+f
(2)非规格化数:M=f
计算步骤:
A.数7.0
(1)题目给出浮点格式为k为指数,所以bias=2^(k-1)-1
(2)7.0的二进制表示为0b111.0,然后移动小数点直到小数点左边只有一个1,得M=0b1.110,小数部分f=0b0.11,进而得E=2,因为阶码E也叫指数,左移两位,也就是指数为2。值V就是他自己,V=7.0。
(3)另外,e=E+bias=2+2^(k-1)-1=2^(k-1)+1,所以位模式表示为0 10...01 110...
B.能够被准确描述的最大奇整数
(1)最大奇整数——首先,该数的二进制表示应为1111 1111...,即V=0b 1111 1111...;其次,最大:它得是个正数,因此符号位s=0;接着,能够被准确描述:所以小数点后的位数一共有确定的能够准确存储的n位,所以M=1.1111...,f=0.1111...(小数点后有n个1),E=n
(2)同样,bias=2^(k-1)-1,e=E+bias=2^(k-1)-1+n
(3)位模式表示为0 2^(k-1)-1+n 1111...
C.最小的规格化数的倒数
(1)emm,最小的规格化数,应该是个负数吧,那么符号位s=1
(2)既然最小,e=1,M=1.00...,f=0.00...,E=e-bias=1-bias=1-2^(k-1)-1=-2^(k-1),V=(-1)^1*1*2^[-2^(k-1)]=-1/{2^[2^(k-1)]},当然这个式子看起来很“烦”,可以写成V=-2^(1-bias)
(3)它的倒数V=-2^(bias-1),同样M=1.00...,f=0.00...,也可得E=bias-1,而e=E+bias=-1
(4)位模式表示为 1 11...101 000...
2.88
请考虑以下两个基于 IEEE 浮点格式的 9 位浮点表示形式。
格式 A
有一个符号位。
有 k=5 个阶码位。指数偏置量为 15。
有 n=3 个小数位。
格式 B
有一个符号位。
有 k=4 个阶码位。指数偏置量为 7。
有 n=4 个小数位。
下面,在格式化为 A 时为您提供了一些位模式,您的任务是将它们转换为格式 B 中的最接近的值。如果需要舍入,则应向 +∞ 舍入。此外,提供格式 A 和格式 B 位模式给出的数字值。以整数或分数形式给出这些值。
本题也会用到2.85的公式~
(1)格式A位:0 10110 101
根据位模式,我们可知,符号位s-0,阶码位有5位(即k=5),bias=2^(5-1)-1=15,e=2^1+2^2+2^4=2+4+16=22,E=e-bias=7,小数位f=(2^-1+2^-3)=5/8,M=1+f=13/8
可得V=(-1)^0*(13/8)*2^7=208
格式B位:我是这么想的,就是求格式化A位的值的反过来。
已知格式B值等于208,是一个整数,符号位s=0,E=7,M=13/8,f=5/8,但是此时bias=7,可得e=14,而14=2+4+8,转换为二进制就是0 1110 1010
(2)格式A位:1 00111 110
同理,s-1,bias=15,e=2^0+2^1+2^2=7,E=e-bias=-8,小数位f=2^(-1)+2^(-2)=6/8,M=1+f=14/8
可得V=(-1)^1*(14/8)*2^(-8)=-7/1024
格式B位:已知-7/1024,符号位s=1,bias=7,而A中E=e-bias=-8,e又不为负,B的指数E和A最接近的话只能是-6,这样一来e=0,可知格式B位是一个非规格化数。指数E少了-2,那只能在小数位补,由A的V式子可知B的M应等于14/32,则f=M=7/16,转为二进制为1 0000 0111
(3)格式A位:0 00000 101
注意!这里的阶码段全为0!所以它是一个非规格化数!
s=0,bias=15,e=0,E=1-bias=-14,小数位f=5/8,M=f=5/8
可得V=(-1)^0*(5/8)*2^(-14)=5/2^(-17) 这道题和答案有出入,个人认为是答案错了
格式B位:已知5/2^(-17) ,符号位s=0,bias=7,而A中E=-14,B的指数E和A最接近的话只能是-6,即B又是个非规格化数。指数少了-8,在小数位补8,B的M应为5/2^11,但是M最多就到2^-4,我也搞不明白了……
(4)后面的题都类似,自己算一下就好了
答案: