2017-2018-1 20155228 《信息安全系统设计基础》第三周学习总结
2017-2018-1 20155228 《信息安全系统设计基础》第三周学习总结
教材学习内容总结
十六进制表示法
一个字节由8位组成。在二进制表示法中,它的值域是0000000-11111111。如果看成十进制整数,它的值域就是0~255。两种符号表示法对于描述位模式来说都不是非常方便。二进制表示法太冗长,而十进制表示法与位模式的互相转化很麻烦。替代的方法是,以16为基数,或者叫做十六进制(hexadecimal)数,来表示位模式。十六进制(简写为“hex”)使用数字0一9以及字符A一F来表示16个可能的值。
十进制和十六进制表示之间的转换需要使用乘法或者除法来处理一般情况。将一个十进制数字x转换为十六进制,可以反复地用16除二,得到一个商q和一个余数r,也就是x=q•16+r。然后,我们用十六进制数字表示的r作为最低位数字,并且通过对q反复进行这个过程得到剩下的数字。
寻址和字节顺序
排列表示一个对象的字节有两个通用的规则。考虑一个w位的整数,其位表示为[Xw-1,Xw-2...X1,X0],其中Xw-1是最高有效位,而X0是最低有效位。假设w是8的倍数,这些位就能被分组成为字节,其中最高有效字节包含位[Xw-1,Xw-2...Xw-8],而最低有效字节包含位[X7, X6...X0],其他字节包含中间的位。某些机器选择在内存中按照从最低有效字节到最高有效字节的顺序存储对象,而另一些机器则按照从最高有效字节到最低有效字节的顺序存储。前一种规则—最低有效字节在最前面的方式,称为小端法((little endian)。后一种规则—最高有效字节在最前面的方式,称为大端法(big endian)。
布尔代数
C语言中的移位运算
C语言还提供了一组移位运算,向左或者向右移动位模式。x向左移动k位,丢弃最高的k位,并在右端补k个0。移位量应该是一个0~w-1之间的值。有一个相应的右移运算,但是它的行为有点微妙。一般而言,机器支持两种形式的右移:逻辑右移和算术右移。逻辑右移在左端补k个0,算术右移是在左端补k个最高有效位的值,这种做法看上去可能有点奇特,但是我们会发现它对有符号整数数据的运算非常有用。
补码编码
关于补码编码,有几点值得注意。第一,补码的范围是不对称的|TMin|=|TMax|+1,也就是说,TMin没有与之对应的正数。正如我们将会看到的,这导致了补码运算的某些特殊的属性,并且容易造成程序中细微的错误。之所以会有这样的不对称性,是因为一半的位模式(符号位设置为1的数)表示负数,而另一半(符号位设置为0的数)表示非负数。因为0是非负数,也就意味着能表示的整数比负数少一个。第二,最大的无符号数值刚好比补码的最大值的两倍大一点:UMaxw= 2TMaxw+1。补码表示中所有表示负数的位模式在无符号表示中都变成了正数。
有符号数和无符号数之间的转换
C语言中的有符号数和无符号数
由于C语言对同时包含有符号和无符号数表达式的这种处理方式,出现了一些奇特的行为。当执行一个运算时,如果它的一个运算数是有符号的而另一个是无符号的,那么C语言会隐式地将有符号参数强制类型转换为无符号数,并假设这两个数都是非负的,来执行这个运算。
整数乘法的乘以常数
由于整数乘法比移位和加法的代价要大得多,许多C语言编译器试图以移位、加法和减法的组合来消除很多整数乘以常数的情况。例如,假设一个程序包含表达式x*14。利用14 = 23+22+2^1,编译器会将乘法重写为(x<<3) + (x<<2) + (x<<1),将一个乘法替换为三个移位和两个加法。无论x是无符号的还是补码,甚至当乘法会导致溢出时,两个计算都会得到一样的结果。(根据整数运算的属性可以证明这一点。)更好的是,编译器还可以利用属性14=24一21,将乘法重写为(x<<4)一(x<<1),这时只需要两个移位和一个减法。
教材学习中的问题和解决过程
用函数bis和bic来实现按位|和^运算
Digital Equipment的VAX计算机没有布尔运算AND和OR指令,只有bis(位设置)和bic(位清除)这两种指令。两种指令的输入都是一个数据字x和一个掩码字m。它们生成一个结果z,z是由根据掩码m的位来修改x的位得到的。使用bis指令,这种修改就是在m为1的每个位置上,将z对应的位设置为1。使用bic指令,这种修改就是在m为1的每个位置,将z对应的位设置为O。
假设有两个函数bis和bic来实现位设置和位清除操作。只想用这两个函数,而不使用任何其他C语言运算,来实现按位|和^运算。
bis运算等价于布尔。R—如果x中或者m中的这一位置位了,那么z中的这一位就置位。另一方面,bic (x,m)等价于x&m;实现只有当x对应的位为1且m对应的位为0时,该位等于1.由此,可以通过对bis的一次调用来实现|。为了实现^,可以利用以下属性x^y=(x&y)|(~x&y)
/*Declarations of functions implementing operations bis and bic*/
int bis(int x, int m);
int bic(int x, int m);
/*Compute xly using only calls to functions bis and bic*/
int bool_or(int x, int y)
{
int result=bis(x,y);
return result;
}
/*Compute x"y using only calls to functions bis and bic*/
int bool_xor(int x, int y)
{
int result=bis(bic(x,y),bic(y,x));
return result;
}
小数值与二进制数与十进制数之间的转换
考虑二进制小数表示的一个简单方法是将一个数表示为形如x/(2^k)的小数。将这个形式表示为二进制的过程是:使用x的二进制表示,并把二进制小数点插人从右边算起的第k个位置。举一个例子,对于25/16,我们有25=11001。然后把二进制小数点放在从右算起的第4位,得至1. 1001。把分数拆分成若干形如1/(2x)之和的形式,例如25/16=1/(20)+1/(21)+1/(24),那么可以知道,小数点前为1,小数点后第一位和第四位为1,小数点后其他位为0。
代码调试中的问题和解决过程
用代码实现将一个数组中的元素头尾两端依次对调
void reverse_array(int a[],int cnt)
{
int first,last;
for (first=0,last=cnt-1;first<=last;first++,last--)
inplace_swap(&a [first],&a[last]);
}
对一个包含元素1, 2, 3和4的数组使用这个函数时,正如预期的那样,现在数组的元素变成了4, 3, 2和1。
不过,当对一个包含元素1, 2,3,4和5的数组使用这个函数时,得到数字的元素为5, 4, 0, 2和1。
实际上,这段代码对所有偶数长度的数组都能正确地工作,但是当数组的长度为奇数时,它就会把中间的元素设置成0。
对于一个长度为奇数的数组,长度cnt=2k+1,函数reverse array最后一次循环中,变量first和last的值都为k,所以试图交换正中间的元素和它自己。
在这种情况中,inplace_ swap的参数x和Y都指向同一个位置。当计算x^y的时候,得到0。然后将0作为数组正中间的元素,而后面的步骤一直都把这个元素设置为0。
这时调用函数inplace swap会将数组元素设置为0。
将reverse array的第4行的测试简单地替换成first<last就能消除这个问题,因为没有必要交换正中间的元素和它自己。
代码托管
结对及互评
评分标准
-
正确使用Markdown语法(加1分):
- 不使用Markdown不加分
- 有语法错误的不加分(链接打不开,表格不对,列表不正确...)
- 排版混乱的不加分
-
模板中的要素齐全(加1分)
- 缺少“教材学习中的问题和解决过程”的不加分
- 缺少“代码调试中的问题和解决过程”的不加分
- 代码托管不能打开的不加分
- 缺少“结对及互评”的不能打开的不加分
- 缺少“上周考试错题总结”的不能加分
- 缺少“进度条”的不能加分
- 缺少“参考资料”的不能加分
-
教材学习中的问题和解决过程, 一个问题加1分
-
代码调试中的问题和解决过程, 一个问题加1分
-
本周有效代码超过300分行的(加2分)
- 一周提交次数少于20次的不加分
-
其他加分:
- 周五前发博客的加1分
- 感想,体会不假大空的加1分
- 排版精美的加一分
- 进度条中记录学习时间与改进情况的加1分
- 有动手写新代码的加1分
- 课后选择题有验证的加1分
- 代码Commit Message规范的加1分
- 错题学习深入的加1分
- 点评认真,能指出博客和代码中的问题的加1分
- 结对学习情况真实可信的加1分
-
扣分:
- 有抄袭的扣至0分
- 代码作弊的扣至0分
- 迟交作业的扣至0分
点评过的同学博客和代码
-
本周结对学习情况
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 20篇 | 400小时 | |
第一周 | 10/10 | 1/1 | 6/6 | |
第三周 | 210/220 | 2/3 | 6/12 |
尝试一下记录「计划学习时间」和「实际学习时间」,到期末看看能不能改进自己的计划能力。这个工作学习中很重要,也很有用。
耗时估计的公式
:Y=X+X/N ,Y=X-X/N,训练次数多了,X、Y就接近了。
-
计划学习时间:6小时
-
实际学习时间:6小时
(有空多看看现代软件工程 课件
软件工程师能力自我评价表)