C++sin cos tan三角函数使用
C++里用sin/cos/tan?别再传弧度=角度×3.14159了,这坑我踩过三次
刚学C++数学函数那会儿,我写了个小工具算三角形边长,输入30度,调用sin(30),结果输出–0.988…
我盯着控制台愣了两秒:这sin30°不是0.5吗?
后来翻文档、查手册、重装编译器(真干过),才明白——C++标准库的三角函数只认弧度,不认度数。这不是个冷知识,是每个初学者必撞的南墙。
但问题来了:为什么非得用弧度?
因为弧度制让微积分“长得自然”:d(sin x)/dx = cos x 这个漂亮关系,只有在x是弧度时才成立。C++沿用了数学世界的底层约定,没给“友好模式”开关。你得自己转。
弧度怎么算?别硬背公式,用常量更稳
有人记π ≈ 3.1415926,手敲六位小数;有人写#define PI 3.1415926——这其实埋了隐患。
C++17起,<numbers>头文件提供了高精度、跨平台的数学常量:
#include <numbers>
#include <cmath>
#include <iostream>
int main() {
double deg = 30.0;
double rad = deg * std::numbers::pi / 180.0; // ✅ 推荐:用std::numbers::pi
std::cout << std::sin(rad) << "\n"; // 输出 0.5
}
std::numbers::pi 是long double精度,比手写3.141592653589793更准,也比M_PI(非标准宏)更可移植。
记住:别再用M_PI,它不在C++标准里,某些编译器默认不开启,一换环境就报错。
tan有个“脾气”,得提前打招呼
sin和cos很温和,输入任意实数都返回[-1,1]间的值。
tan不一样——它在π/2、3π/2这些点上根本不存在(趋向无穷)。C++不会帮你拦着,而是返回inf或nan:
double r = std::numbers::pi / 2;
std::cout << std::tan(r) << "\n"; // 可能输出 inf 或 -inf(取决于浮点舍入)
实际项目中,比如做图形旋转或物理引擎,如果用户输入角度接近90°,直接调tan可能让后续计算崩掉。
稳妥做法是加个安全检查:
double safe_tan(double rad) {
const double eps = 1e-10;
double mod = std::fmod(std::abs(rad), std::numbers::pi);
if (std::abs(mod - std::numbers::pi/2) < eps) {
throw std::domain_error("tan undefined near π/2");
}
return std::tan(rad);
}
这不是过度设计——去年我修过一个CAD插件bug,根源就是没拦住tan(89.9999999°)导致坐标溢出。
角度与弧度混用?用类型系统帮你防错
写多了容易忘:这个变量是度还是弧度?尤其多人协作时,注释可能过期,代码却照跑。
C++20起,可以用std::chrono式的思路,自定义单位类型:
struct degrees { double val; };
struct radians { double val; };
inline radians to_radians(degrees d) {
return {d.val * std::numbers::pi / 180.0};
}
// 现在函数签名自带语义:
double compute_height(double base, radians angle) {
return base * std::tan(angle.val);
}
// compute_height(10.0, degrees{30}); // 编译失败!必须显式转换
类型安全不能消灭所有错误,但能拦住“手滑输错单位”的低级失误。小项目可能觉得麻烦,但一旦逻辑变复杂,这种约束反而省调试时间。
实战提醒:浮点误差不是bug,是常态
你可能试过:
std::cos(std::numbers::pi / 2) // 期望0,实际输出约6.12e-17
这不是函数不准,而是π/2本身在二进制浮点里无法精确表示。
关键不是追求“绝对零”,而是理解误差量级:
sin(π)≈1e-16,属于正常浮点舍入范围;- 若得到
1e-3,那大概率是你单位搞错了,或者角度计算链有累积误差。
调试时,别急着改算法,先打印中间弧度值,确认它真是你想要的那个角。
C++的sin/cos/tan没有魔法,也不藏技巧。它们只是忠实执行数学定义——而数学世界从不迁就人类的习惯。
我们绕不开弧度,但可以绕开那些反复踩过的坑:用std::numbers::pi代替手写π,用类型区分单位,对tan保持敬畏,把浮点误差当作常识而非异常。
写完这段代码,我顺手改掉了自己旧项目的三处M_PI——不是为了炫技,是不想下次交接时,新人再对着sin(45)输出0.7071067811865475发呆。
毕竟,工具该让人少想“为什么不对”,多想“接下来怎么更好”。


还没有评论,来说两句吧...