2017-2018-1 20155213 《信息安全系统设计基础》第三周学习总结
2017-2018-1 20155213 《信息安全系统设计基础》第三周学习总结
教材学习内容总结
浏览了正章,重点学习了以下几个点
- int,float,void*在内存中存储形式,通过P31页的代码,了解的更深一点
- 此函数使用char*型把以上三种类型的数强制转换成按字节读取的类型,因而能更加直观的看出每个字节的位置,以及其包含的值;
- 根据上图可以看出来我的电脑是按照大端法存储的,即高位对其低位;
- 信息=位+上下文
- 计算机一般都是按照冯诺依曼体系构架的,即存储形式都是以二进制形式存储的,只有0、1两种情况,具体说就是位的两种形式;
- 如果仅仅有位的概念,那所有的存储都是无意义的,还需要对其有解释的方法,也就是在不同语境下的不同解释方法,赋予了位的意义,也就是联系上下文去解释位,解释出来的就是信息;
- 为了更深的理解,我做了下面两种比较:
- 相同的位但被解释出了不同的信息:教材P83页,整数3510593.00的单精度浮点数存储的十六进制表示是0x4A564504,而对于整数0x4A564504表示的十进制的值为1247167748比3510593大得多,虽然有着相同的位,但解释方法不同,也就会有不同的值(信息);
- 不同的位但被解释出了相同的信息:对于0x80000001,按照int型的数来解释就是-1,但如果是unsigned型的则为2147483649。
教材学习中的问题和解决过程
- 问题1:P58页练习题2.25题,运行时出现内存错误
- 问题1解决方案:首先这个length是unsigned型的,即当length=0时,length-1即为2^32-1,而传过来的a[N]的长度远小于这个值,所以会出现内存错误,即越界,非法访问;正确修改就是把length改为int型的;
代码调试中的问题和解决过程
- 问题1:F:\Atom_C文件\float_bits\float_bits2.c: In function 'main':
F:\Atom_C文件\float_bits\float_bits2.c:12:6: error: invalid operands to binary ^ (have 'float' and 'unsigned int')
f^=x; - 问题1解决方案:上面已经写了,说明float不能进行位运算,
- 查阅资料后,位运算符只能用于整型操作数,即只能用于带符号或无符号的char,short,int与long类型,C语言位运算详解;
- 解决方案就是可以使用int指针指向float型的,然后对该指针进行位操作;
- 问题2:
/tmp/ccVdmxHM.o:在函数‘float_f2i’中:float_bits.c:(.text+0x183):对‘pow’未定义的引用float_bits.c:(.text+0x1f4):对‘pow’未定义的引用;collect2: error: ld returned 1 exit status
意思就是没找到pow函数。 - 问题2解决:可是我在代码里已经声明了
#include<math.h>
了的,要么是在linux中没有pow这个函数,或者说是表示不同,或者就是有这个函数但不在<math.h>中。百度了问题,就是后者,gcc的数学函数都是定义在libm.so里面了linux c数学库函数
家庭作业(P97页2.96题)
- 题目:遵循位级浮点编码规则,实现如下原型的函数:
int float_f2i(float_bits f);
对于浮点数f,这个函数计算(int)f。如果f是NaN,你的函数一个向零舍入。如果f不能用整数表示(例如,超出表示范围,或者他是一个NaN),那么函数一应该返回0x80000000.测试你的函数,对参数f可以取得所有2^32个值求值,将结果与你使用的机器的浮点运算得到的结果相比较。
- 题目分析:
- 这题是要在没有float型的数运算的前提下,按照float编码形式读出四个字节中的数,并将此数用(int)强制转换。
- 首先是按照float读出unsigned字节,需要四句程序,
unsigned sign=f>>31;unsigned exp=f>>23&0xFF; int exp_E=(int)exp-127;unsigned frac=f&0x7FFFFF;
- 这样之后float_bits函数就好做了,根据要求写出该函数
int float_f2i(float_bits f)
{
unsigned sign=f>>31;
unsigned exp=f>>23&0xFF;
int exp_E=(int)exp-127;
unsigned frac=f&0x7FFFFF;
frac=frac|0x800000;
if(exp==0)return f&0x80000000;
if(exp_E>30)return 0x80000000;
if(exp_E<0)return 0;
if(sign==1)return -(int)(frac*pow(2,exp_E-23));
return (int)(frac*pow(2,exp_E-23));
}
-
- 剩下的就是检测,但怎么获得一个float值的位信息并将其位不变换的转换成unsigned型,这就需要之前在书上P31页看到的东西,将float型按位读取,并赋值给unsigned型数,于是有了下面函数
unsigned swift(bit_transform b)
{
unsigned un=0;
unsigned sign[4];
sign[0]=(unsigned)b[0];
sign[1]=((unsigned)b[1])<<8;
sign[2]=((unsigned)b[2])<<16;
sign[3]=((unsigned)b[3])<<24;
un=sign[0]|sign[1]|sign[2]|sign[3];
printf("%x %x %x %x\n", b[3],b[2],b[1],b[0]);
return un;
}
-
- 这两个问题解决了就是测试主函数的编写了:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
typedef unsigned float_bits;
typedef unsigned char* bit_transform;
unsigned swift(bit_transform b);
int float_f2i(float_bits f);
int main()
{
unsigned x=0x80000000;
float f=-9.8;
printf("%d\n",float_f2i(swift((bit_transform)&f)));
printf("%d",(unsigned)f);
printf("\nHello world!\n");
return 0;
}
-
- 运行截图
-
现在解决题目中的第二大问题就是:对参数f可以取得所有2^32个值求值。
-
这个好解决,就是将传入的unsigned值一个一个加上去,但又出现了一个问题,就是如何检测,虽然对unsigned值可以一个一个加,但float值不可以一个一个加来改变每一位,并且float也不能通过位运算来改变每一位,此时就想到可不可以通过除法来控制每一位,经过反复测试,有这么句除法形式可以很好的操作,
float f=(i*2)/pow(2,150);
-
这样得到的从i=0取到i=223,输出值就是0x0-0x0080000;但在往后取就不会再有每位的变化了,比方说i=(224)时,位信息是0x01000000,而i=(2^24)+1,位信息依然是0x01000000,并且这种方法计算量也挺大的,故而舍弃;
-
这时就想到可以借鉴P35页的那个
showbyte()
函数的构造来进行位操作从而改变每一位,借鉴其思想就是用一个unsigned型指针指向float型数,然后将该指针指向的值每每加一来实现,unsigned* un_p;float f;un_p=&f;
-
-
问题都解决了,就需要运行并且比较检测了,但2^32次是真的太多了,我电脑几次跑崩了,这里就节选了三部分进行了检测,第一部分是
0x0-0xFFFF
(32位的前65535);第二部分5201-5239
(我班学号);第三部分0xFFFF0000-0xFFFFFFFE
(32位的后65535),全部写到文件里了,可以在我的码云那部分找到; -
截图
代码托管
(statistics.sh脚本的运行结果截图)
结对及互评
-
结对队友20155303
-
他的博客中值得学习的或问题:
-
他的代码中值得学习的或问题:
-
结对照片:
-
结对学习内容
其他(感悟、思考等,可选)
这周就是学习了几种数值类型在计算机中的存储方式,以及解释方法,以前觉得浮点型就是规定了几位存小数点前面的数,规定了几位存小数点后面的数,一直也没有深究过,现在回头看看自己,发现我那种解释还是有点道理的,不过当真正遇到浮点型表示超过整型数时,我的解释就崩溃了。学无止境,带着自己的猜测去学习位未知的东西,总会发现有趣的东西。
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 15篇 | 400小时 | |
第一周 | 177/177 | 1/1 | 10/10 | |
第三周 | 308/485 | 2/2 | 12/22 |
尝试一下记录「计划学习时间」和「实际学习时间」,到期末看看能不能改进自己的计划能力。这个工作学习中很重要,也很有用。
耗时估计的公式
:Y=X+X/N ,Y=X-X/N,训练次数多了,X、Y就接近了。
-
计划学习时间:XX小时
-
实际学习时间:XX小时
-
改进情况:
(有空多看看现代软件工程 课件
软件工程师能力自我评价表)