接着上一节课,我们再讲两道题目
#includeint main() { int i = -20; unsigned int j = 10; printf("%dn", i + j); printf("%un", i + j); return 0; }
请问两个式子打印的结果是什么?
答:遇到这种题目,我们首先要将i和j的二进位制补码表示出来,用他们的二进位制补码相加减得到我们要的结果
整型i的源码是1000000000000000 0000000000010100
对应的反码是1111111111111111 1111111111101011
对应的补码是1111111111111111 1111111111101100
j是无符号数,无符号数没有原反补码的概念,所以对应的源码就是存在内存中的补码
j的源码是0000000000000000 0000000000001010(补码)
i和j的补码对应相加得到 1111111111111111 1111111111110110
printf("%dn", i + j);表示我们打印的是整型,对应的就是signed int,是有符号整型,有两种方法计算对应的值,第一种方法就是求出我们i和j的补码相加的结果对应的源码(不再赘述)第二种方法非常简单,因为我们使用的是有符号整型,那么我们可以直接跳过内部计算的细节,-20+10=-10
注意由补码求源码有两种方法,第一种:和源码求补码的步骤一样,按位取反+1,第二种方法,和源码求补码的步骤相反,也就是先-1,再按位取反,两种方法记忆一种即可。
第二个式子:
我们的第一个式子打印的是有符号整型,第二个式子打印的是无符号整型,我们前面计算的i和j的补码相加之前的所有步骤都不变,变得是如何看待i和j的补码相加的结果,也就是1111111111111111 1111111111110110
既然是无符号整数,那么所有位数都是数值位,直接当做二进位制数字进行计算
如图,我们计算的二进位制序列对应的数字就是4294967286,是一个非常大的数字 ,进行运行检测
结果相同
总结:类型决定了如何看待内存中二进位制序列
第二题:
int main()
{
unsigned int i;
for ( i = 9; i >= 0; i--)
{
printf("%un", i);
}
return 0;
}
这段代码运行的结果是什么?
答:死循环
为什么会死循环呢?
答:for循环内部的计算步骤是这样的:i=9,满足i>=0;i--,直到减到0,0满足i>=0,0-1的结果就相当于0+(-1),-1对应的二进位制补码是11111111111111111111111111111111,0的补码就是0,0+ -1对应的二进位制补码结果就是-1的二进位制的补码,因为我们的i是无符号整型,所以这串代码的全部位数都是数值位,所以i就变成了2^32-1,因为2^32-1大于0,一直相减的结果就始终大于0,所以就死循环。
接下来,我们讲一下c语言中的bool
问题1:c语言中有没有bool类型
答:c89 c90没有bool类型,c99中引入_Bool类型,_Bool类型的头文件是#include
在没有头文件的时候,我们引用bool类型,可以发现,出现错误
当我们引用了头文件#include
可以发现,bool类型只占一个字节 我们转到bool类型的定义
可以发现,boll类型中定义真为1假为0
理论上,表示真假,一个字节就足够了,不过要取决于编译器,vs2013认为是一个字节
我们切换一个大写的试试
我们可以发现,使用大写依旧没问题(不过要加windows的头文件),那么大小写究竟有什么差异呢
我们转到BOOL的定义
可以看到,这个BOOL类型是由微软研发的
我们进行运行,可以发现,打印了四个字节
我们查看定义,可以发现
这个BOOL相当于整型,占四个字节
需要注意的是,优先使用小写的bool,因为大写的BOOL只在微软旗下的产品才可用
bool类型和0进行比较
int main()
{
int flag = 0;
if (flag == 0)
{
printf("1n");
}
if (flag == false);
{
printf("2n");
}
if (!flag)
{
printf("3n");
}
return 0;
}
上面那三种方法最好
第一种,不合适,原因是flag==0和int x==0,这两种看起来没什么区别,语义不明
第二种我们也不推荐,因为我们第二种必须有c99平台支持,必须有头文件,没有头文件的情况下,是编译不过去的
更推荐的是第三种,我们介绍一下if语句的执行步骤
1:先执行()中的表达式和步骤or或函数,得到真假结果
2:条件 判定功能
3:进行 分支功能
我们这里的真假true 和false ,这是逻辑结果,直观的反映了flag是bool类型
接下来,我们介绍一些浮点型的特性
int main()
{
double f = 3.6;
return 0;
}
这里的3.6默认的就是double类型的,而不是float类型的
当我们想用float类型的变量存储3.6时,可以在3.6后面加上f
int main()
{
float f = 3.6f;
return 0;
}
当不加f时
我们可以发现,这里说了从double到float截断,原因是什么?
答:float类型占四个字节,3.6是double类型的数据,占8个字节,数据在存储的时候,和变量的类型没有关系,所以我们的double类型的数据存储到float类型的变量中,发生截断。
我们写一串代码,观察产生的现象
int main()
{
double d = 3.6;
printf("%.50fn", 3.6);
}
这里的%.50表示小数点后保留50个有效数字,我们进行运行,查看结果
可以看到答案保留了50位有效数字,但是后面的有效数字中竟然出现了一个1,原因是什么?
答:这里是产生了精度损失,我们可以发现,精度损失既能使我们的数字变大,又能使我们的数字变小,更多细节的话,涉及到浮点型数据在内存中的存储。
接下来,我们看看更多的精度损失的例子
int main()
{
double x = 1.0;
double y = 0.1;
printf("%.50fn", x-0.9);
printf("%.50fn", y);
return 0;
}
正常情况下,两个式子打印的结果都应该是0.1,我们进行编译
我们可以发现,两个式子打印的结果都不是我们预料的结果,这就是精度损失的例子
我们把上面的例子扩展一下
int main()
{
double x = 1.0;
double y = 0.1;
printf("%.50fn", x-0.9);
printf("%.50fn", y);
if ((x - 0.9) == 0.1)
{
printf("you can se me!");
}
else
{
printf("oops!");
}
return 0;
}
正常情况下,x-0.9的结果应该是0.1,屏幕上应该打印you can se me!我们进行编译
可以发现,结果是oops,x-0.9的结果并不是0.1
总结:在进行浮点型比较的时候,一定不能用==号
浮点型本身有精度损失,进而导致各种结果可能有细微的差别
那么,两个相同的浮点数又该如何判断和比较
答:
if ((x - y) > -精度 && (x - y) < 精度)
{
}
判断条件如上图代码所示,需要注意的是,这个精度通常是我们自己设置的,非常小的数字,例如
#define EPSILON 0.0000001
所以要满足下列条件:(x - y) > -EPSILON && (x - y) < EPSILON
满足的情况下,可以判断x=y
还有一个更加简洁的写法
if (fabs(x - y) < 精度)
{
}
注意:这里的fabs是浮点数求绝对值的意思,要使用fabs需要用的math.h的头文件
精度除了可以自己设置,也可以采用系统的
DBL_EPSILON FLT_EPSILON
上面的一个是系统的double类型的精度,下面一个是系统的float类型的精度,注意:使用这两种系统的精度的时候,需要使用头文件#include
下面,我们写一个例子
#include#define EPS 0.000000001 int main() { double x = 1.0; double y = 0.1; printf("%.50fn", x-0.9); printf("%.50fn", y); if (fabs((x-0.9)-y) 注意:使用fabs求浮点型绝对值必须带头文件,我们上次写的if语句是if ((x - 0.9) == 0.1),这种显示是错误,正确的写法就是下面的这种写法,如果我们的写法正确,程序编译应该会打印出you can se me
可以发现,程序运行成功
我们上面写的是自己设置的精度,接下来,我们使用系统设计的精度
#includeint main() { double x = 1.0; double y = 0.1; printf("%.50fn", x-0.9); printf("%.50fn", y); if (fabs((x - 0.9) - y) 注意:在使用系统给的精度DBL_EPSILON时,需要引头文件#include
系统给的精度到底是多大呢?我们转到定义进行查看
这段绿色的英文是什么意思呢?
答:1.0加很多数字结果都不是1.0,而这个精度是能够和1.0相加之后不是1.0的最小值,很拗口,简而言之就是这个精度是最小的吗,但是这个精度+1.0也比1.0大
我们进行编译
上面,我们讲了判断两个浮点性数据相等的办法,接下来,我们来讲一下判断浮点型数据和0相等的办法,我们运用到了类比
if (fabs((x - 0.9) - y)这是我们判断两个浮点型相等的条件,也就是x-0.9==y,我们把这里的y换成0即可,也就是
if (fabs(x)这就是我们类比后的结果,我们把x-0.9再简化一下,简化为x
if (fabs(x)所以判断一个浮点型数据x是否等于0时,需要用浮点型求绝对值的方法求出浮点型数据x的绝对值,用得出来的结果和精度进行比较,这里的精度既可以是我们自己设置的,也可以是系统自带的



