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 也被定义,还有几个用于角度转换的便捷函数,以及用于球面运动的 *大圆公式*。
正切
正弦、余弦和正切的余函数(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...
对于 csc
、cot
、asec
、acsc
、acot
、csch
、coth
、asech
、acsch
,参数不能为 0
(零)。对于 atanh
、acoth
,参数不能为 1
(一)。对于 atanh
、acoth
,参数不能为 -1
(负一)。对于 tan
、sec
、tanh
、sech
,参数不能为 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
的复数。
可以使用以下函数转换(平面,二维)角度。
$radians = deg2rad($degrees);
$radians = grad2rad($gradians);
$degrees = rad2deg($radians);
$degrees = grad2deg($gradians);
$gradians = deg2grad($degrees);
$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() 显式地进行包裹。
$radians_wrapped_by_2pi = rad2rad($radians);
$degrees_wrapped_by_360 = deg2deg($degrees);
$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是经度(向东为正,向西为负)。
注意:一些文本将theta和phi定义为相反,一些文本将phi定义为从水平面开始,一些文本使用r代替rho。
柱面坐标系,(rho, theta, z),是三维坐标系,用于定义三维空间中的点。它们基于圆柱面。圆柱体的半径为rho,也称为径向坐标。xy平面(绕z轴)的角度为theta,也称为方位角坐标。第三个坐标是z,指向theta平面的上方。
提供球面坐标和柱面坐标之间的转换。请注意,由于pi角度等于-pi角度之类的等式,转换不一定可逆。
($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);
注意,当$z
不为 0 时,$rho_s
不等于$rho_c
。
($x, $y, $z) = spherical_to_cartesian($rho, $theta, $phi);
($rho_c, $theta, $z) = spherical_to_cylindrical($rho_s, $theta, $phi);
注意,当$z
不为 0 时,$rho_c
不等于$rho_s
。
大圆是包含圆直径的圆的一部分:球面上两点(非对跖点)之间的最短距离沿着连接这两点的圆弧。
返回球面上两点之间的球面距离。
$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() 函数计算
use Math::Trig 'great_circle_direction';
$direction = great_circle_direction($theta0, $phi0, $theta1, $phi1);
别名 '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 表示正东。
您可以反过来计算目的地,如果您知道起点、方向和距离
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);
或者中点,如果您知道终点
use Math::Trig 'great_circle_midpoint';
($thetam, $phim) =
great_circle_midpoint($theta0, $phi0, $theta1, $phi1);
great_circle_midpoint() 只是
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() 可能会返回复数,即使实数就足够且正确,这是由于浮点精度问题造成的。例如,您可以通过尝试这些来查看这些不准确性
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() 的公式对这一点非常敏感,因此它们可能会意外地滑入复数平面,即使它们不应该这样做。为了解决这个问题,有两个接口保证返回实值输出。
use Math::Trig qw(asin_real);
$real_angle = asin_real($input_sin);
如果输入在 [-1, 1] 之间(包括端点),则返回实值反正弦。对于大于一的输入,返回 pi/2。对于小于负一的输入,返回 -pi/2。
use Math::Trig qw(acos_real);
$real_angle = acos_real($input_cos);
如果输入在 [-1, 1] 之间(包括端点),则返回实值反余弦。对于大于一的输入,返回零。对于小于负一的输入,返回 pi。
使用 use Math::Trig;
会在调用环境中导出许多数学例程,甚至会覆盖一些例程(sin
、cos
)。实际上,作者认为这是一种功能…… ;-)
代码没有针对速度进行优化,特别是因为我们使用了 Math::Complex
,因此即使参数不是复数,在进行计算时也会非常接近复数。但是,如果我们希望像 asin(2)
这样的表达式给出答案而不是给出致命运行时错误,则无法完全避免这种情况。
不要尝试使用这些公式进行导航。
Jarkko Hietaniemi <jhi!at!iki.fi>,Raphael Manfredi <Raphael_Manfredi!at!pobox.com>,Zefram <[email protected]>
本库是自由软件;您可以根据与 Perl 本身相同的条款重新发布和/或修改它。