目錄

名稱

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) 沒有明確定義。

acscacosecasecacotacotan

雙曲正弦、餘弦和正切

sinhcoshtanh

雙曲正弦、餘弦和正切的反餘弦函數(cosech/csch 和 cotanh/coth 是別名)

cschcosechsechcothcotanh

雙曲正弦、餘弦和正切的區域(也稱為反函數)

asinhacoshatanh

雙曲正弦、餘弦和正切的區域反餘弦函數(acsch/acosech 和 acoth/acotanh 是別名)

acschacosechasechacothacotanh

三角常數 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 的複數。

平面角度轉換

(平面,2 維)角度可以使用下列函數轉換。

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 平面向上指向。

3D 角度轉換

提供球面和圓柱座標的轉換。請注意,由於等式(例如 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_direction 的別名 'great_circle_bearing' 也可用。

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.3 度,西經 0.5 度)和東京(北緯 35.7 度,東經 139.8 度)之間的距離(公里)

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 度,東經 89 度,位於西伯利亞的普托拉納高原。

注意:您無法像這樣從 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 <zefram@fysh.org>

授權

此函式庫為免費軟體;您可以在與 Perl 相同的條款下重新散布或修改它。