第4章 计算表达式
1 常量是具有一定大小内存空间的实体,不是字面值。
2 逗号表达式的值是最后一个子表达式的值,求值顺序为从左到右。
3 单目操作符、条件操作符、赋值复合赋值操作符为的结合性为右结合,其他操作符为左结合。
4 不要用float,要用double,因为浮点运算在内部都是先转化为double再计算,使用float最后还得转化回来,反而更慢。
5 float的表示范围大于整型,但因为与整数有相同的数据表示位数,故有效位要少于整数。即float较之于int:范围大、位数同、精度低。当将double赋给float和int时,float的精度损失有时反而更大。
6 如果一个int型数和一个usigned long型数运算,则先将两个数转换成double型再运算。
7 double的比较用邻域比较技术。abs(d1-d2) < 1e-05
8 float 的数据表示范围比整型大,但与整型有同样长度的数据表示,其有效位要少于整型数。下面的情况float比int的精度损失反而更大。
double d = 123456789.9*9;
int a;
float f;
a = f = d;
cout<<fixed<<a<<endl<<d<<endl<<f<<endl;
1111111109
1111111109.100000
1111111168.000000
9 显式转换
(1)静态显示转换的目的:
a. 为了维护维护整型数运算的一致性,没有必要转换为double.
b. 为了得到正确的结果,为了防止整型中间结果的溢出,可以将整型转换为double.再转换回整型。
double d = sqrt(123456.0);
int a = static_cast<int>(d) * 8 + 5;
int b = d * 8 + 5;
cout <<a<<endl<<b<<endl; //2813 2815
a = 2000000000;
b = 1000000000;
int c = (a+b)/2;
int e = (static_cast<double>(a)+b)/2;
cout<<c<<endl<<e<<endl;//-647483648 1500000000
(2)static_cast<type>(a),将a转换成type类型;
reinterpret_cast<type>(a),并不对被转换的表达式a求值,而是强制逃避编译类型检查,一般用来转换不同类型的指针,对需要求值计算的表达式它会拒绝。
double d = 3.2;
int a = static_cast<int>(d);
a = reinterpret_cast<int>(d);//error C2440: 'reinterpret_cast' : cannot convert from 'double' to 'int'
int * ip = reinterpret_cast<int*>(&d);
ip = static_cast<int*>(&d);//error C2440: 'static_cast' : cannot convert from 'double *' to 'int *'
10 条件表达式中的赋值
体味:if((x=func1())==func2()) y = x;
11位操作:
左移”<<” :不管是否有符号,都将整数的最高位挤掉,末端补零。相当于乘2。
右移”>>” :对无符号数,高位挤进0,末位去掉;对有符数,若高位是1则挤进1,若高位是0,挤进0,末位挤掉。
右移相当于除以2.
Eg:用位操作解人员派遣问题:
Question:
某项任务由A、B、C、D、E五个人去完成,但人员派遣受限于以下条件:
(1) 若A去,则B跟去
(2) D、E两人中必有人去
(3) B、C两人中必有人去,但只去一人
(4) CD两人要么都去,要么都不去
(5) 若E去,则AB都不去
answer:
将约束条件用逻辑运算表达式表示如下:
(1) A->B,即:!A||B
(2) D||E
(3) (B&&!C)||(!B&&C),即:B!=C
(4) (!C||D)&&(C||!D),即:C==D
(5) !E||(A&&B)
如果将每个人的去与不去表示5位整数中的1位,其中A对应最高位,E对应最低位。那么所有的派遣方案位从全部不派遣00000到都派遣11111之间变化。共32种方案,对之进行判断,符合条件的即为合适的派遣方案。
将以上逻辑表达式取反:、
(1) A&&!B
(2) !D && !E
(3) B==C
(4) C!=D
(5) E&&!(A&&B)
程序如下:
12 增量操作
(1)前增量(++a)的意义:先将变量增1,使实体发生变化,再将变量对应的实体作为表达式的结果;
(2)后增量(a++)的意义:将变量的值作为表达式的值,再将变量加1,使实体值发生变化。
故:
前增返回的是实体,是左值,后增量返回的不是左值,是右值。
{
const int d = 8;
//d++;//error C2105: '++' needs l-value
//++d;//error C2105: '++' needs l-value
//3++;//error C2105: '++' needs l-value
int a = 3;
int b = ++a;
int c = a++;
//a++ -= 2;// a++不是左值!
++a -= 2;
++(++a);
//a++ ++;
++a++;//error 单目右结合,a++不是左值
13 表达式的副作用
表达式在求值的过程中引发了多一个的实体值发生改变,成为表达式的副作用。如果一个改变了的左值在表达式中出现了多于一次,则该表达式有不良副作用,可能导致因求值顺序而引起的表达式最终结果的不确定。
如:int c = a*b + ++b; c的值可能因求值顺序的不同而不同。
表达式副作用的根本原因是充当操作数的模块可能影响同一个表达式中另一个操作数模块的计算值,从而导致表达式的值受求值顺序的不同而不同。
解决表达式副作用的方法是将表达式拆分成几个子表达式。