6.2 — 算术运算符

一元算术运算符

有两种一元算术运算符:加号 (+) 和减号 (-)。提醒一下,一元运算符是只接受一个操作数的运算符。

运算符符号形式操作
一元加++xx 的值
一元减--xx 的负值

一元减运算符返回操作数乘以 -1 的值。换句话说,如果 x = 5,则 -x 为 -5。

一元加运算符返回操作数的值。换句话说,+5 是 5,+x 是 x。通常你不需要使用这个运算符,因为它是多余的。它主要是为了与一元减运算符对称而添加的。

为了可读性,这两个运算符都应该紧接在操作数之前(例如 -x,而不是 - x)。

不要将一元减运算符与使用相同符号的二元减法运算符混淆。例如,在表达式 x = 5 - -3; 中,第一个减号是二元减法运算符,第二个是一元减运算符。

二元算术运算符

有 5 种二元算术运算符。二元运算符是接受左操作数和右操作数的运算符。

运算符符号形式操作
加法+x + yx 加 y
减法-x - yx 减 y
乘法*x * yx 乘以 y
除法/x / yx 除以 y
取余%x % yx 除以 y 的余数

加法、减法和乘法运算符与现实生活中的工作方式相同,没有注意事项。

除法和取余需要一些额外的解释。我们将在下面讨论除法,在下一课中讨论取余。

整数和浮点数除法

最容易将除法运算符视为具有两种不同的“模式”。

如果操作数中的任何一个(或两个)是浮点值,则除法运算符执行浮点数除法。浮点数除法返回一个浮点值,并保留小数部分。例如,7.0 / 4 = 1.757 / 4.0 = 1.757.0 / 4.0 = 1.75。与所有浮点数算术运算一样,可能会发生舍入误差。

如果两个操作数都是整数,则除法运算符执行整数除法。整数除法会舍弃任何小数部分并返回一个整数值。例如,7 / 4 = 1,因为结果的小数部分被舍弃了。类似地,-7 / 4 = -1,因为小数部分被舍弃了。

使用 static_cast<> 对整数执行浮点数除法

上面提出了一个问题——如果我们有两个整数,并且希望在不丢失小数的情况下进行除法,我们该怎么做?

在课程 4.12 — 类型转换和 static_cast 简介中,我们展示了如何使用 static_cast<> 运算符将字符转换为整数,使其作为整数而不是字符打印。

我们也可以类似地使用 static_cast<> 将整数转换为浮点数,以便我们可以执行浮点数除法而不是整数除法。考虑以下代码:

#include <iostream>

int main()
{
    constexpr int x{ 7 };
    constexpr int y{ 4 };

    std::cout << "int / int = " << x / y << '\n';
    std::cout << "double / int = " << static_cast<double>(x) / y << '\n';
    std::cout << "int / double = " << x / static_cast<double>(y) << '\n';
    std::cout << "double / double = " << static_cast<double>(x) / static_cast<double>(y) << '\n';

    return 0;
}

这会产生结果

int / int = 1
double / int = 1.75
int / double = 1.75
double / double = 1.75

以上说明,如果任何一个操作数是浮点数,结果将是浮点数除法,而不是整数除法。

除以 0 和 0.0

除数为 0 的整数除法将导致未定义行为,因为结果在数学上是未定义的!

#include <iostream>

int main()
{
	constexpr int apples { 12 };
	std::cout << "You have " << apples << " apples. Enter how many people to divide them between: ";
	int x {};
	std::cin >> x;

	std::cout << "Each person gets " << apples / x << " whole apples.\n"; // apples and x are int, so this is integer division

	return 0;
}

如果您运行上述程序并输入 0,您的程序很可能会崩溃。去试试吧,它不会损害您的电脑。

除以浮点值 0.0 的结果是实现定义的(意味着行为由编译器/架构决定)。在支持 IEEE754 浮点格式的架构上,结果将是 NaNInf。在其他架构上,结果很可能是未定义行为。

相关内容

我们在 4.8 — 浮点数 课程中讨论 NaNInf

您可以通过运行以下程序并输入 00.0 来查看您的程序会做什么

#include <iostream>

int main()
{
	constexpr int apples { 12 };
	std::cout << "You have " << apples << " apples. Enter how many servings of apples you want: ";

	double d {};
	std::cin >> d;

	std::cout << "Each serving is " << apples / d << " apples.\n"; // d is double, so this is floating point division

	return 0;
}

算术赋值运算符

运算符符号形式操作
加法赋值+=x += y将 y 加到 x
减法赋值-=x -= y从 x 减去 y
乘法赋值*=x *= yx 乘以 y
除法赋值/=x /= yx 除以 y
取余赋值%=x %= y将 x / y 的余数放入 x

到目前为止,当你需要给一个变量加 4 时,你很可能做了以下操作

x = x + 4; // add 4 to existing value of x

这可行,但有点笨拙,并且需要两个运算符才能执行(operator+ 和 operator=)。

因为像 x = x + 4 这样的语句非常常见,C++ 为了方便提供了五种算术赋值运算符。你不再需要写 x = x + 4,你可以写 x += 4。不再是 x = x * y,你可以写 x *= y

因此,上面变成了

x += 4; // add 4 to existing value of x

修改和非修改运算符

能够修改其操作数之一值的运算符,非正式地称为修改运算符。在 C++ 中,大多数运算符都是非修改的——它们只是使用操作数来计算并返回一个值。但是,有两类内置运算符确实修改其左操作数(并返回值)

  • 赋值运算符,包括标准赋值运算符 (=)、算术赋值运算符 (+=-=*=/=%=),以及位赋值运算符 (<<=>>=&=|=^=)。
  • 增量和减量运算符(分别为 ++--)。我们将在 6.4 — 增量/减量运算符和副作用 课程中讨论这些。

此列表中不包括运算符 ==!=<=>=,因为这些是非修改的关系(比较)运算符(= 表示“等于”)。我们将在 6.7 — 关系运算符和浮点数比较 课程中讨论这些。

致进阶读者

重载运算符可以重新定义以具有与内置运算符不同的行为,这可能包括修改左操作数,即使内置版本不修改(反之亦然)。例如,用于输出的 operator<< 的重载版本会修改其左操作数(输出流对象)。

guest
您的电子邮箱地址将不会被显示
发现错误?请在上方留言!
与勘误相关的评论在处理后将被删除,以帮助减少混乱。感谢您帮助使网站对每个人都更好!
来自 https://gravatar.com/ 的头像与您提供的电子邮箱地址相关联。
有回复时通知我:  
380 条评论
最新
最早 最多投票
内联反馈
查看所有评论