关系运算符基础知识
关系运算符允许你比较两个值。共有 6 个关系运算符:
运算符 | 符号 | 形式 | 操作 |
---|---|---|---|
大于 | > | x > y | 如果 x 大于 y 则为 true ,否则为 false |
小于 | < | x < y | 如果 x 小于 y 则为 true ,否则为 false |
大于等于 | >= | x >= y | 如果 x 大于或等于 y 则为 true ,否则为 false |
小于等于 | <= | x <= y | 如果 x 小于或等于 y 则为 true ,否则为 false |
等于 | == | x == y | 如果 x 等于 y 则为 true ,否则为 false |
不等于 | != | x != y | 如果 x 不等于 y 则为 true ,否则为 false |
这些运算符的工作方式大部分你已经见过,并且相当直观。每个运算符都会求值为布尔值 true
(1) 或 false
(0)。
关系运算符示例
以下是一个使用这些运算符与整数的示例代码:
#include <iostream>
int main()
{
std::cout << "Enter an integer: ";
int x{};
std::cin >> x;
std::cout << "Enter another integer: ";
int y{};
std::cin >> y;
if (x == y)
std::cout << x << " equals " << y << '\n';
if (x != y)
std::cout << x << " does not equal " << y << '\n';
if (x > y)
std::cout << x << " is greater than " << y << '\n';
if (x < y)
std::cout << x << " is less than " << y << '\n';
if (x >= y)
std::cout << x << " is greater than or equal to " << y << '\n';
if (x <= y)
std::cout << x << " is less than or equal to " << y << '\n';
return 0;
}
运行结果示例:
Enter an integer: 4
Enter another integer: 5
4 does not equal 5
4 is less than 5
4 is less than or equal to 5
在比较整数时,这些运算符的使用极其简单直接。
布尔条件值使用指南
默认情况下,if
语句、条件运算符(以及其他一些地方)中的条件会求值为布尔值。
常见的布尔条件写法
许多新程序员会这样写语句:
if (b1 == true) ...
这是冗余的,因为 == true
实际上并没有为条件增加任何价值。相反,我们应该写成:
if (b1) ...
类似地,下面的写法:
if (b1 == false) ...
最好写成:
if (!b1) ...
最佳实践
避免在条件中添加不必要的
==
或!=
。这会使它们更难阅读,却不会提供任何额外价值。
浮点数比较的挑战与解决方案
浮点数比较的基本问题
考虑以下程序:
#include <iostream>
int main()
{
constexpr double d1{ 100.0 - 99.99 }; // 数学上应该等于 0.01
constexpr double d2{ 10.0 - 9.99 }; // 数学上应该等于 0.01
if (d1 == d2)
std::cout << "d1 == d2" << '\n';
else if (d1 > d2)
std::cout << "d1 > d2" << '\n';
else if (d1 < d2)
std::cout << "d1 < d2" << '\n';
return 0;
}
浮点数比较的特殊情况
小于和大于比较
当小于 (<
)、大于 (>
)、小于等于 (<=
) 和大于等于 (>=
) 运算符用于浮点值时,在大多数情况下(当操作数的值不相似时)它们会产生可靠的结果。然而,如果操作数几乎相同,这些运算符应被视为不可靠。
等于和不等于比较
等于运算符 (==
和 !=
) 则要麻烦得多。考虑以下示例:
#include <iostream>
int main()
{
std::cout << std::boolalpha << (0.3 == 0.2 + 0.1); // 打印 false
return 0;
}
浮点数比较的最佳实践
基本的近似相等比较
#include <cmath> // 为了 std::abs()
bool approximatelyEqualAbs(double a, double b, double absEpsilon)
{
return std::abs(a - b) <= absEpsilon;
}
Knuth算法实现
#include <algorithm> // 为了 std::max
#include <cmath> // 为了 std::abs
bool approximatelyEqualRel(double a, double b, double relEpsilon)
{
return (std::abs(a - b) <= (std::max(std::abs(a), std::abs(b)) * relEpsilon));
}
综合解决方案
bool approximatelyEqualAbsRel(double a, double b, double absEpsilon, double relEpsilon)
{
if (std::abs(a - b) <= absEpsilon)
return true;
return approximatelyEqualRel(a, b, relEpsilon);
}
C++23中的constexpr支持
现代C++实现
// C++23 版本
#include <algorithm>
#include <cmath>
constexpr bool approximatelyEqualRel(double a, double b, double relEpsilon)
{
return (std::abs(a - b) <= (std::max(std::abs(a), std::abs(b)) * relEpsilon));
}
constexpr bool approximatelyEqualAbsRel(double a, double b, double absEpsilon, double relEpsilon)
{
if (std::abs(a - b) <= absEpsilon)
return true;
return approximatelyEqualRel(a, b, relEpsilon);
}
C++14/17/20的替代方案
#include <algorithm>
#include <iostream>
template <typename T>
constexpr T constAbs(T x)
{
return (x < 0 ? -x : x);
}
constexpr bool approximatelyEqualRel(double a, double b, double relEpsilon)
{
return (constAbs(a - b) <= (std::max(constAbs(a), constAbs(b)) * relEpsilon));
}
constexpr bool approximatelyEqualAbsRel(double a, double b, double absEpsilon, double relEpsilon)
{
if (constAbs(a - b) <= absEpsilon)
return true;
return approximatelyEqualRel(a, b, relEpsilon);
}