方法定义
// 计算单个值的反正切(主值)
public static double atan(double a)
// 计算两个坐标的反正切(全值域)
public static double atan2(double y, double x)
功能说明
方法 | 数学表达 | 返回值范围 | 特点 |
---|---|---|---|
atan(a) |
tan⁻¹(a) | [-π/2, π/2] | 单参数,输出受限 |
atan2(y,x) |
tan⁻¹(y/x) | [-π, π] | 双参数,保留象限信息 |
核心差异
象限处理能力:
atan(a)
:无法区分第二/第四象限(如输入 -1 都返回 -π/4)atan2(y,x)
:根据坐标自动判断象限(如 (-1,-1) 返回 -3π/4)
零点处理:
atan(0)
返回 0.0atan2(0,0)
返回 0.0(但实际应避免此输入)
特殊值处理:
| 输入 |atan()
|atan2()
| |-----------------------|---------------|------------------------| |NaN
|NaN
|NaN
| |±0.0
| ±0.0 | 根据坐标符号确定 | |±Infinity
| ±π/2 | 根据坐标计算角度 |
示例代码
// atan() 基础用法
double a = Math.atan(1); // π/4 ≈ 0.7854
double b = Math.atan(Double.POSITIVE_INFINITY); // π/2 ≈ 1.5708
// atan2() 象限演示
double q1 = Math.atan2(1, 1); // 第一象限: π/4 ≈ 0.7854
double q2 = Math.atan2(1, -1); // 第二象限: 3π/4 ≈ 2.3562
double q3 = Math.atan2(-1, -1); // 第三象限: -3π/4 ≈ -2.3562
double q4 = Math.atan2(-1, 1); // 第四象限: -π/4 ≈ -0.7854
// 角度转换
double degrees = Math.toDegrees(Math.atan2(1, 1)); // 45°
使用技巧
坐标系转换:
// 笛卡尔坐标 → 极坐标 double r = Math.sqrt(x*x + y*y); double theta = Math.atan2(y, x);
角度差计算:
// 计算两点间角度差 double angleDiff = Math.atan2(Math.sin(θ1-θ2), Math.cos(θ1-θ2));
方向判断:
// 判断目标方位 (E, NE, N, NW...) double angle = Math.toDegrees(Math.atan2(dy, dx)); String direction = getDirection(angle); // 自定义方向映射
常见错误
混淆参数顺序:
// 错误:参数顺序应为 (y, x) double error = Math.atan2(x, y);
错误处理零点:
// 危险:atan2(0,0) 返回0.0(数学上未定义) if (x == 0 && y == 0) throw new IllegalArgumentException();
忽略返回值范围:
// 错误假设:atan() 输出范围 [0, 2π] double angle = Math.atan(slope); // 实际范围 [-π/2, π/2]
注意事项
计算精度:
- 极端值(如 10²⁰)可能导致精度丢失
- 使用
StrictMath
版本保证跨平台一致性
性能考量:
atan2()
比atan()
慢约 30%(因额外象限计算)- 密集循环中可缓存结果或近似计算
角度缠绕:
- 处理 -π/π 边界时需归一化:
double normalizeAngle(double angle) { return angle - 2*Math.PI * Math.floor((angle + Math.PI)/(2*Math.PI)); }
- 处理 -π/π 边界时需归一化:
最佳实践
优先选择 atan2():
// 更安全的斜率计算 double angle = Math.atan2(y2 - y1, x2 - x1);
防御性编程:
double safeAtan2(double y, double x) { if (Double.isNaN(y) || Double.isNaN(x)) return Double.NaN; if (x == 0 && y == 0) return 0.0; // 或抛出自定义异常 return Math.atan2(y, x); }
近似优化(精度要求低时):
// Pade 近似 (|x| < 1 时误差 < 0.005) double approxAtan(double x) { double x2 = x * x; return x*(0.999866 + x2*(-0.3302995 + x2*(0.180141 - x2*0.085133))); }
总结
维度 | atan() |
atan2() |
---|---|---|
输入 | 单参数 (斜率) | 双参数 (y,x 坐标) |
输出范围 | [-π/2, π/2] | [-π, π] |
象限识别 | ❌ 无法识别 | ✅ 自动识别 |
零点安全 | ✅ | ❌ 需额外检查 (0,0) |
性能 | 较快 | 较慢(约+30%耗时) |
推荐场景 | 已知斜率的主值计算 | 坐标系转换、方向判断 |
实践口诀:
反正切分两兄弟,
atan
简单atan2
强;
单参输出半圆周,双参全域辨方向;
坐标转换选atan2
,性能关键用近似;
零点处理要警惕,象限信息保周全。
在图形计算、导航系统和物理仿真中优先使用 atan2()
保证方向正确性;在已知角度主值的数学计算中使用 atan()
更高效。始终检查边界条件以避免未定义行为。