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
的複數。
(平面,2 維)角度可以使用下列函數轉換。
$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_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 表示正東。
如果你知道起點、方向和距離,你可以反向計算目的地
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.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() 即使實數就足夠且正確,也可能會傳回複數,這是因為浮點數不精確。例如,透過嘗試這些,您可以看到這些不精確之處
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 <zefram@fysh.org>
此函式庫為免費軟體;您可以在與 Perl 相同的條款下重新散布或修改它。