内容

名称

Math::Trig - 三角函数

概要

use Math::Trig;

$x = tan(0.9);
$y = acos(3.7);
$z = asin(2.4);

$halfpi = pi/2;

$rad = deg2rad(120);

# Import constants pi2, pi4, pip2, pip4 (2*pi, 4*pi, pi/2, pi/4).
use Math::Trig ':pi';

# Import the conversions between cartesian/spherical/cylindrical.
use Math::Trig ':radial';

    # Import the great circle formulas.
use Math::Trig ':great_circle';

描述

Math::Trig 定义了许多核心 Perl 未定义的三角函数,核心 Perl 只定义了 sin()cos()。常数 pi 也被定义,还有几个用于角度转换的便捷函数,以及用于球面运动的 *大圆公式*。

三角函数

正切

tan

正弦、余弦和正切的余函数(cosec/csc 和 cotan/cot 是别名)

csc, cosec, sec, sec, cot, cotan

正弦、余弦和正切的反正切函数(也称为反函数)

asin, acos, atan

y/x 的反正切函数的主值

atan2(y, x)

正弦、余弦和正切的反正切余函数(acosec/acsc 和 acotan/acot 是别名)。注意 atan2(0, 0) 没有定义。

acsc, acosec, asec, acot, acotan

双曲正弦、余弦和正切

sinh, cosh, tanh

双曲正弦、余弦和正切的余函数(cosech/csch 和 cotanh/coth 是别名)

csch, cosech, sech, coth, cotanh

双曲正弦、余弦和正切的面积函数(也称为反函数)

asinh, acosh, atanh

双曲正弦、余弦和正切的面积余函数(acsch/acosech 和 acoth/acotanh 是别名)

acsch, acosech, asech, acoth, acotanh

三角常数 pi 及其一些方便的倍数也被定义。

pi, pi2, pi4, pip2, pip4

由于除以零而产生的错误

以下函数

acoth
acsc
acsch
asec
asech
atanh
cot
coth
csc
csch
sec
sech
tan
tanh

无法计算所有参数,因为这将意味着除以零或对零取对数。这些情况会导致致命运行时错误,如下所示

cot(0): Division by zero.
(Because in the definition of cot(0), the divisor sin(0) is 0)
Died at ...

atanh(-1): Logarithm of zero.
Died at...

对于 csccotasecacscacotcschcothasechacsch,参数不能为 0(零)。对于 atanhacoth,参数不能为 1(一)。对于 atanhacoth,参数不能为 -1(负一)。对于 tansectanhsech,参数不能为 pi/2 + k * pi,其中 k 是任何整数。

注意 atan2(0, 0) 没有定义。

简单(实数)参数,复杂结果

请注意,一些三角函数可能会从实轴扩展到复平面。例如,asin(2) 对普通实数没有定义,但对复数有定义。

在 Perl 术语中,这意味着将通常的 Perl 数字(也称为标量,请参阅 perldata)作为三角函数的输入,可能会产生不再是简单实数的输出结果:而是复数。

Math::Trig 通过使用 Math::Complex 包来处理这种情况,该包知道如何处理复数,请参阅 Math::Complex 获取更多信息。在实践中,您无需担心获得复数作为结果,因为 Math::Complex 会处理诸如如何显示复数之类的细节。例如

print asin(2), "\n";

应该产生类似于以下内容(取舍最后几位小数)

1.5707963267949-1.31695789692482i

也就是说,一个实部约为 1.571,虚部约为 -1.317 的复数。

平面角转换

可以使用以下函数转换(平面,二维)角度。

deg2rad
$radians  = deg2rad($degrees);
grad2rad
$radians  = grad2rad($gradians);
rad2deg
$degrees  = rad2deg($radians);
grad2deg
$degrees  = grad2deg($gradians);
deg2grad
$gradians = deg2grad($degrees);
rad2grad
$gradians = rad2grad($radians);

整个圆周为 2 pi 弧度或 360 度或 400 梯度。默认情况下,结果将被包裹到 [0, {2pi,360,400}] 圆圈内。如果您不希望这样,请提供一个真实的第二个参数

$zillions_of_radians  = deg2rad($zillions_of_degrees, 1);
$negative_degrees     = rad2deg($negative_radians, 1);

您也可以通过 rad2rad()、deg2deg() 和 grad2grad() 显式地进行包裹。

rad2rad
$radians_wrapped_by_2pi = rad2rad($radians);
deg2deg
$degrees_wrapped_by_360 = deg2deg($degrees);
grad2grad
$gradians_wrapped_by_400 = grad2grad($gradians);

径向坐标转换

径向坐标系球面柱面系统,稍后将详细解释。

您可以使用 :radial 标签导入径向坐标转换函数

use Math::Trig ':radial';

($rho, $theta, $z)     = cartesian_to_cylindrical($x, $y, $z);
($rho, $theta, $phi)   = cartesian_to_spherical($x, $y, $z);
($x, $y, $z)           = cylindrical_to_cartesian($rho, $theta, $z);
($rho_s, $theta, $phi) = cylindrical_to_spherical($rho_c, $theta, $z);
($x, $y, $z)           = spherical_to_cartesian($rho, $theta, $phi);
($rho_c, $theta, $z)   = spherical_to_cylindrical($rho_s, $theta, $phi);

所有角度都以弧度表示。.

坐标系

笛卡尔坐标系是常用的直角(x, y, z)坐标系。

球面坐标系,(rho, theta, phi),是三维坐标系,用于定义三维空间中的点。它们基于球面。球体的半径为rho,也称为径向坐标。xy平面(绕z轴)的角度为theta,也称为方位角坐标。从z轴的角度为phi,也称为极角坐标。因此,北极是rho, 0, 0,几内亚湾(想想非洲缺失的大块)是rho, 0, pi/2。在地理学上,phi是纬度(向北为正,向南为负),theta是经度(向东为正,向西为负)。

注意:一些文本将thetaphi定义为相反,一些文本将phi定义为从水平面开始,一些文本使用r代替rho

柱面坐标系,(rho, theta, z),是三维坐标系,用于定义三维空间中的点。它们基于圆柱面。圆柱体的半径为rho,也称为径向坐标。xy平面(绕z轴)的角度为theta,也称为方位角坐标。第三个坐标是z,指向theta平面的上方。

3-D 角度转换

提供球面坐标和柱面坐标之间的转换。请注意,由于pi角度等于-pi角度之类的等式,转换不一定可逆。

cartesian_to_cylindrical
($rho, $theta, $z) = cartesian_to_cylindrical($x, $y, $z);
cartesian_to_spherical
($rho, $theta, $phi) = cartesian_to_spherical($x, $y, $z);
cylindrical_to_cartesian
($x, $y, $z) = cylindrical_to_cartesian($rho, $theta, $z);
cylindrical_to_spherical
($rho_s, $theta, $phi) = cylindrical_to_spherical($rho_c, $theta, $z);

注意,当$z不为 0 时,$rho_s不等于$rho_c

spherical_to_cartesian
($x, $y, $z) = spherical_to_cartesian($rho, $theta, $phi);
spherical_to_cylindrical
($rho_c, $theta, $z) = spherical_to_cylindrical($rho_s, $theta, $phi);

注意,当$z不为 0 时,$rho_c不等于$rho_s

大圆距离和方向

大圆是包含圆直径的圆的一部分:球面上两点(非对跖点)之间的最短距离沿着连接这两点的圆弧。

great_circle_distance

返回球面上两点之间的球面距离。

$distance = great_circle_distance($theta0, $phi0, $theta1, $phi1, [, $rho]);

其中 ($theta0, $phi0) 和 ($theta1, $phi1) 分别是两点的球坐标。距离以 $rho 单位表示。$rho 是可选的,默认值为 1(单位球体)。

如果您使用的是地理坐标(纬度和经度),您需要调整纬度为零在赤道,向北增加,向南减少的事实。假设 ($lat0, $lon0) 和 ($lat1, $lon1) 是两点的地理坐标(以弧度表示),则距离可以计算为

$distance = great_circle_distance($lon0, pi/2 - $lat0,
                                  $lon1, pi/2 - $lat1, $rho);

great_circle_direction

您必须沿着大圆弧行进的方向(也称为方位角)可以通过 great_circle_direction() 函数计算

use Math::Trig 'great_circle_direction';

$direction = great_circle_direction($theta0, $phi0, $theta1, $phi1);

great_circle_bearing

别名 'great_circle_bearing' 也可用于 'great_circle_direction'。

use Math::Trig 'great_circle_bearing';

$direction = great_circle_bearing($theta0, $phi0, $theta1, $phi1);

great_circle_direction 的结果以弧度表示,零表示正北,pi 或 -pi 表示正南,pi/2 表示正西,-pi/2 表示正东。

great_circle_destination

您可以反过来计算目的地,如果您知道起点、方向和距离

use Math::Trig 'great_circle_destination';

# $diro is the original direction,
# for example from great_circle_bearing().
# $distance is the angular distance in radians,
# for example from great_circle_distance().
# $thetad and $phid are the destination coordinates,
# $dird is the final direction at the destination.

($thetad, $phid, $dird) =
  great_circle_destination($theta, $phi, $diro, $distance);

或者中点,如果您知道终点

great_circle_midpoint

use Math::Trig 'great_circle_midpoint';

($thetam, $phim) =
  great_circle_midpoint($theta0, $phi0, $theta1, $phi1);

great_circle_midpoint() 只是

great_circle_waypoint

use Math::Trig 'great_circle_waypoint';

($thetai, $phii) =
  great_circle_waypoint($theta0, $phi0, $theta1, $phi1, $way);

其中 $way 表示航路点沿经过起点 ($theta0, $phi0) 和终点 ($theta1, $phi1) 的大圆弧的位置,相对于起点到终点的距离。因此,$way = 0 表示起点,$way = 1 表示终点,$way < 0 表示起点“后面”的点,$way > 1 表示终点“后面”的点。如果没有给出,$way 默认值为 0.5。

请注意,对跖点(它们之间的距离为pi 弧度)在它们之间没有唯一的航路点,因此在这种情况下会返回 undef。如果点相同,则它们之间的距离为零,所有航路点都与起点/终点相同。

上述中的 theta、phi、方向和距离都以弧度表示。

您可以通过以下方法导入所有大圆公式:

use Math::Trig ':great_circle';

请注意,如果您查看的是平面世界地图,则结果方向可能会有些令人惊讶:在这样的地图投影中,大圆通常看起来不像最短路线——但例如,从欧洲或北美到亚洲的最短路线通常会穿过极地地区。(常见的墨卡托投影不会将大圆显示为直线:墨卡托投影中的直线是恒定方位线。)

示例

计算伦敦(51.3N 0.5W)和东京(35.7N 139.8E)之间的距离(公里)

use Math::Trig qw(great_circle_distance deg2rad);

# Notice the 90 - latitude: phi zero is at the North Pole.
sub NESW { deg2rad($_[0]), deg2rad(90 - $_[1]) }
my @L = NESW( -0.5, 51.3);
my @T = NESW(139.8, 35.7);
my $km = great_circle_distance(@L, @T, 6378); # About 9600 km.

从伦敦到东京的方向(以弧度表示,正北为零,正东为 pi/2)。

use Math::Trig qw(great_circle_direction);

my $rad = great_circle_direction(@L, @T); # About 0.547 or 0.174 pi.

伦敦和东京之间的中点为

use Math::Trig qw(great_circle_midpoint rad2deg);

my @M = great_circle_midpoint(@L, @T);
sub SWNE { rad2deg( $_[0] ), 90 - rad2deg( $_[1] ) }
my @lonlat = SWNE(@M);

大约 69 N 89 E,位于西伯利亚的普托拉纳高原。

注意:您不能像这样从 A 到 B

Dist = great_circle_distance(A, B)
Dir  = great_circle_direction(A, B)
C    = great_circle_destination(A, Dist, Dir)

并期望 C 为 B,因为从 A 到 B 的方位角会不断变化(除了像子午线或纬度圈这样的特殊情况),而在 great_circle_destination() 中,给出了一个恒定方位角来遵循。

大圆公式的注意事项

由于地球形状不规则(略微扁球形),答案可能会有几个百分点的误差。最大误差约为 0.55%,但通常低于 0.3%。

实值 asin 和 acos

对于较小的输入,asin() 和 acos() 可能会返回复数,即使实数就足够且正确,这是由于浮点精度问题造成的。例如,您可以通过尝试这些来查看这些不准确性

print cos(1e-6)**2+sin(1e-6)**2 - 1,"\n";
printf "%.20f", cos(1e-6)**2+sin(1e-6)**2,"\n";

这将打印类似于以下内容

-1.11022302462516e-16
0.99999999999999988898

即使预期结果当然正好是零和一。用于计算 asin() 和 acos() 的公式对这一点非常敏感,因此它们可能会意外地滑入复数平面,即使它们不应该这样做。为了解决这个问题,有两个接口保证返回实值输出。

asin_real
use Math::Trig qw(asin_real);

$real_angle = asin_real($input_sin);

如果输入在 [-1, 1] 之间(包括端点),则返回实值反正弦。对于大于一的输入,返回 pi/2。对于小于负一的输入,返回 -pi/2。

acos_real
use Math::Trig qw(acos_real);

$real_angle = acos_real($input_cos);

如果输入在 [-1, 1] 之间(包括端点),则返回实值反余弦。对于大于一的输入,返回零。对于小于负一的输入,返回 pi。

错误

使用 use Math::Trig; 会在调用环境中导出许多数学例程,甚至会覆盖一些例程(sincos)。实际上,作者认为这是一种功能…… ;-)

代码没有针对速度进行优化,特别是因为我们使用了 Math::Complex,因此即使参数不是复数,在进行计算时也会非常接近复数。但是,如果我们希望像 asin(2) 这样的表达式给出答案而不是给出致命运行时错误,则无法完全避免这种情况。

不要尝试使用这些公式进行导航。

另请参阅

Math::Complex

作者

Jarkko Hietaniemi <jhi!at!iki.fi>,Raphael Manfredi <Raphael_Manfredi!at!pobox.com>,Zefram <[email protected]>

许可证

本库是自由软件;您可以根据与 Perl 本身相同的条款重新发布和/或修改它。