3. 布尔代数
在第 1 节 “if 语句”讲过, a<b<c 不表示 b 既大于 a 又小于 c ,那么如果想表示这个含义该怎么写呢?可以这样:
if (a < b) {
if (b < c) {
printf("b is between a and c.\n");
}
}
我们也可以用逻辑与(Logical AND)运算符表示这两个条件同时成立。逻辑与运算符在 C 语言中写成两个&号(Ampersand),上面的语句可以改写为:
if (a < b && b < c) {
printf("b is between a and c.\n");
}
对于 a < b && b < c 这个控制表达式,要求“ a < b 的值非 0”和“ b < c 的值非 0”这两个条件同时成立整个表达式的值才为 1,否则整个表达式的值为 0。也就是只有两个条件都为真,它们做逻辑与运算的结果才为真,有一个条件为假,则逻辑与运算的结果为假,如下表所示:
表 4.2. AND 的真值表
| A | B | A AND B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
这种表称为真值表(Truth Table)。注意逻辑与运算的操作数以非 0 表示真以 0 表示假,而运算结果以 1 表示真以 0 表示假(类型是 int ),我们忽略这些细微的差别,在表中全部以 1 表示真以 0 表示假。C 语言还提供了逻辑或(Logical OR)运算符,写成两个|线(Pipe Sign),逻辑非(Logical NOT)运算符,写成一个!号(Exclamation Mark),它们的真值表如下:
表 4.3. OR 的真值表
| A | B | A OR B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 1 |
表 4.4. NOT 的真值表
| A | NOT A |
|---|---|
| 0 | 1 |
| 1 | 0 |
逻辑或表示两个条件只要有一个为真,它们做逻辑或运算的结果就为真,只有两个条件都为假,逻辑或运算的结果才为假。逻辑非的作用是对原来的逻辑值取反,原来是真的就是假,原来是假的就是真。逻辑非运算符只有一个操作数,称为单目运算符(Unary Operator),以前讲过的加减乘除、赋值、相等性、关系、逻辑与、逻辑或运算符都有两个操作数,称为双目运算符(Binary Operator)。
关于逻辑运算的数学体系称为布尔代数(Boolean Algebra),以它的创始人布尔命名。在编程语言中表示真和假的数据类型叫做布尔类型,在 C 语言中通常用 int 型来表示,非 0 表示真,0 表示假1。布尔逻辑是写程序的基本功之一,程序中的很多错误都可以归因于逻辑错误。以下是一些布尔代数的基本定理,为了简洁易读,真和假用 1 和 0 表示,AND 用*号表示,OR 用+号表示(从真值表可以看出 AND 和 OR 运算确实有点像乘法和加法运算),NOT 用¬表示,变量 x 、 y 、 z 的值可能是 0 也可能是 1。
¬¬x=x
x*0=0
x+1=1
x*1=x
x+0=x
x*x=x
x+x=x
x*¬x=0
x+¬x=1
x*y=y*x
x+y=y+x
x*(y*z)=(x*y)*z
x+(y+z)=(x+y)+z
x*(y+z)=x*y+x*z
x+y*z=(x+y)*(x+z)
x+x*y=x
x*(x+y)=x
x*y+x*¬y=x
(x+y)*(x+¬y)=x
¬(x*y)=¬x+¬y
¬(x+y)=¬x*¬y
x+¬x*y=x+y
x*(¬x+y)=x*y
x*y+¬x*z+y*z=x*y+¬x*z
(x+y)*(¬x+z)*(y+z)=(x+y)*(¬x+z)
除了第 1 行之外,这些公式都是每两行一组的,每组的两个公式就像对联一样:把其中一个公式中的换成+、+换成、0 换成 1、1 换成 0,就变成了与它对称的另一个公式。这些定理都可以通过真值表证明,更多细节可参考有关数字逻辑的教材,例如[数字逻辑基础]。我们将在本节的练习题中强化训练对这些定理的理解。
目前为止介绍的这些运算符的优先级顺序是:!高于* / %,高于+ -,高于> < >= <=,高于== !=,高于&&,高于||,高于=。写一个控制表达式很可能同时用到这些运算符中的多个,如果记不清楚运算符的优先级一定要多套括号。我们将在第 4 节 “运算符总结”总结 C 语言所有运算符的优先级和结合性。
习题
1、把代码段
if (x > 0 && x < 10);
else
printf("x is out of range.\n");
改写成下面这种形式:
if (____ || ____)
printf("x is out of range.\n");
____应该怎么填?
2、把代码段:
if (x > 0)
printf("Test OK!\n");
else if (x <= 0 && y > 0)
printf("Test OK!\n");
else
printf("Test failed!\n");
改写成下面这种形式:
if (____ && ____)
printf("Test failed!\n");
else
printf("Test OK!\n");
____应该怎么填?
3、有这样一段代码:
if (x > 1 && y != 1) {
...
} else if (x < 1 && y != 1) {
...
} else {
...
}
要进入最后一个 else ,x 和 y 需要满足条件____ || ____。这里应该怎么填?
4、以下哪一个 if 判断条件是多余的可以去掉?这里所谓的“多余”是指,某种情况下如果本来应该打印 Test OK! ,去掉这个多余条件后仍然打印 Test OK! ,如果本来应该打印 Test failed! ,去掉这个多余条件后仍然打印 Test failed! 。
if (x<3 && y>3)
printf("Test OK!\n");
else if (x>=3 && y>=3)
printf("Test OK!\n");
else if (z>3 && x>=3)
printf("Test OK!\n");
else if (z<=3 && y>=3)
printf("Test OK!\n");
else
printf("Test failed!\n");
-
C99 也定义了专门的布尔类型_Bool,但目前没有被广泛使用。 ↩