摘要
算术表达式并不像阅读时那样从左到右计算,而是按照一个隐藏的结构即它的树来计算,这棵树由运算符的优先级、结合性和括号决定;在这棵树的每个节点上,操作数的类型决定进行哪种运算,因此 7 / 2 的值是 3,而 7 / 2.0 的值是 3.5。本课研究 C++ 的五个算术运算符在整数和实数上的用法;整数除法和余数,自 C++11 起它们向零截断,由此可知余数与被除数同号,并且在被除数为负时与欧几里得除法的余数不同;求欧几里得余数的方法;表达式树;操作数类型不同时结果的类型;以及整数算术表达式失去意义的两种方式:除以零和在中间计算中溢出。
学习目标
- 计算 C++ 中整数除法的商和余数(包括操作数为负的情形),并把它们与欧几里得除法的商和余数联系起来。
- 按照优先级和结合性画出算术表达式的树,并计算它的值。
- 预测不同类型操作数之间运算结果的类型。
- 用整数除法和余数分解数量:一个数的各位数字、以小时和分钟表示的时长、星期几。
算术运算符
C++ 有五个二元算术运算符:加法 +、减法 -、乘法 *、除法 / 和取余 %;此外还有一元负号,它改变其唯一操作数的符号,如 -x,以及一元正号 +x,它让操作数保持原样。前四个适用于整数和实数;取余只适用于整数。然而,同样的写法并非在所有情况下都表示同一种运算:如果 / 的两个操作数都是整数,这种除法就是整数除法,其结果是整数,即去掉小数部分的商;如果其中有一个是实数,除法就是实数除法。字符、布尔值、类型转换与常量一课展示了这条规则最明显的后果:double r{7 / 2}; 存储的是 3,因为在结果转换为实数之前,除法已经在整数之间完成了。
程序把五个运算符作用于 17 和 5,并用一个实数被除数重复除法。
#include <print>int main(){ const int a{17}; const int b{5}; std::println("{} + {} = {}", a, b, a + b); std::println("{} - {} = {}", a, b, a - b); std::println("{} * {} = {}", a, b, a * b); std::println("{} / {} = {}", a, b, a / b); std::println("{} % {} = {}", a, b, a % b); const double x{17.0}; std::println("{} / {} = {}", x, b, x / b);}17 + 5 = 2217 - 5 = 1217 * 5 = 8517 / 5 = 317 % 5 = 217 / 5 = 3.417 除以 5 得 3,余 2:这就是把 17 个物体按每组 5 个分组时的商和余数。最后一行用一个实数除以一个整数,得到 3.4。需要注意,std::println 把实数 17.0 写成“17”:空占位符写出值的最短表示,因此写出的内容不会透露类型;要看出类型,可以用 {:.1f} 要求写出小数。
运算符 % 不接受实数。写 7.5 % 2 不是程序运行时才发现的逻辑错误,而是编译错误:编译器指出,类型为 double 和 int 的操作数对该运算符无效。
#include <print>int main(){ std::println("{}", 7.5 % 2);}main.cpp: In function ‘int main()’:main.cpp:5:28: error: invalid operands of types ‘double’ and ‘int’ to binary ‘operator%’ 5 | std::println("{}", 7.5 % 2); | ~~~ ^ ~实数除法的余数是存在的,它由头文件 <cmath> 中的函数 std::fmod 计算,这将在位与数学库一课中与乘幂一起学习:C++ 没有乘幂运算符,2 ^ 3 的值不是 8,而是另外的东西,那里会加以解释。
正在加载内容…
已完成
登录账户以保存您的进度