HOWTO · C++

C++ 中的三角函数

本文演示了如何在 C++ 中使用 STL 的三角函数

本页内容

C++ 在标准头文件 <cmath> 中提供正弦、余弦、正切、反三角函数和双曲函数。普通三角函数的输入是以弧度表示的角度,返回浮点值。使用带 std:: 限定的名称,可以明确表示调用的是标准库中的函数。

使用 std::sin、std::cos 和 std::tan 计算弧度角

调用 std::sin(angle)、std::cos(angle) 和 std::tan(angle),分别计算角度的正弦、余弦和正切。包含 <cmath> 以获取这些函数的声明。这些函数针对浮点类型提供了重载;返回值使用相应的浮点类型(整数实参会转换后传给浮点重载)。

运行以下示例:

本节中的代码以及显示的标签或输出仍为英文。

#include <cmath>
#include <iomanip>
#include <iostream>

int main() {
  const double angle = 1.0; // radians
  std::cout << std::fixed << std::setprecision(6)
            << "sin(" << angle << ") = " << std::sin(angle) << '\n'
            << "cos(" << angle << ") = " << std::cos(angle) << '\n'
            << "tan(" << angle << ") = " << std::tan(angle) << '\n';
}

本次运行观察到的输出如下:

sin(1.000000) = 0.841471
cos(1.000000) = 0.540302
tan(1.000000) = 1.557408

实参表示 1 弧度。std::fixed 和 std::setprecision(6) 会将每个返回值格式化为小数点后六位。

使用反三角函数求回角度

使用 std::asin(x) 根据正弦值求角度,使用 std::acos(x) 根据余弦值求角度,使用 std::atan(x) 根据正切值求角度。它们的结果都以弧度表示。asin 的输入范围是 -1 到 1,返回角度范围为 [-π/2, π/2];acos 的输入范围相同,返回角度范围为 [0, π]。atan 接受任意有限实数,返回角度范围为 (-π/2, π/2)。

如果方向由两个坐标共同描述,请使用 std::atan2(y, x)。与 atan(y / x) 不同,它会根据两个实参的符号判断所在象限,无需先将坐标相除。其结果是弧度角,通常位于 [-π, π];具体采用哪个端点表示,可能取决于输入中的带符号零。

反函数返回的是主值角,并非所有可能产生原始值的角度。例如,多个角度可能具有相同的正弦值,因此仅使用 asin 无法还原其主值范围之外的原始角度。确定最终角度时,请结合问题中的几何关系和象限信息。

用双曲函数计算双曲值

std::sinh、std::cosh 和 std::tanh 分别计算双曲正弦、双曲余弦和双曲正切。它们由指数函数定义,不能替代 std::sin、std::cos 和 std::tan:双曲函数的输入是实数,而不是圆上的角度,且值域也不同。例如,cosh(x) 始终大于或等于 1,而普通余弦的取值介于 -1 和 1 之间。

反双曲函数是 std::asinh、std::acosh 和 std::atanh。它们在实数范围内的定义域各不相同:asinh 接受任意实数输入,acosh 要求输入大于或等于 1,而 atanh 要求输入严格介于 -1 和 1 之间。处理双曲关系时应选择这些函数;不要只是在普通三角函数名称前加上字母 a。

处理角度单位、定义域和浮点结果

C++ <cmath> 中的三角函数要求输入以弧度表示。将角度转换为弧度时,可使用 radians = degrees * π / 180;例如,90 度等于 π/2 弧度。在可移植的 C++ 代码中,可以通过 std::acos(-1.0) 获取 π,也可以自行定义所需常量,因为 M_PI 并非标准 C++ 名称。

反函数的输入必须位于相应的实数定义域内。只有在符合应用数学含义时,才检查或截取输入值:将略微超出 [-1, 1] 的值截取到范围内,可能有助于处理累积的舍入误差,但不应借此掩盖真正超出范围的输入。域错误的处理遵循 C++ 数学库的错误行为,并可能因实现而异;这不属于未定义行为。如果应用需要区分有效结果与数学错误,请查阅 math_errhandling,并检查该实现支持的相关错误指示方式。

在 π/2 的奇数倍附近,std::tan 的值会变得非常大;在这些数学极点处,正切没有有限的实数值。浮点数对极点的近似表示可能产生很大的有限值,而不是明确的错误信号。因此,如果近极点行为会影响结果,应根据应用需求和容差检查输入。

浮点计算都是近似值。像 std::sin(std::acos(-1.0)) 这样的结果可能接近零,但不一定恰好为零。应根据应用场景选择合适的容差来比较计算结果,而不要要求精确相等。一般计算使用 double;只有在确实需要且实现支持时,才选择精度更高的类型。优先使用标准库函数,而不是手写近似算法;重复使用某个计算结果时,应将它存储起来。