float_backend 設計
このページでは float_backend が Complex[Double] 向けに実装する式を導出し、それぞれがオーバーフロー、アンダーフロー、桁落ちをどう回避するかを説明し、分岐切断と主値を示し、スカラーの能力を 3 つのトレイトに分けた理由を説明します。
設計目標
Complex[Double] に対して C \mathbb C C の初等関数を提供します。文書化された分岐切断上での主値、Double の全範囲で数値的に安定な式、そして重要な箇所での IEEE 特殊値の処理を備え、これらすべてをジェネリックな core から切り離します。
数学的背景
すべての z = x + i y ≠ 0 z = x + iy \ne 0 z = x + i y = 0 は、r = ∣ z ∣ = x 2 + y 2 r = |z| = \sqrt{x^2 + y^2} r = ∣ z ∣ = x 2 + y 2 として極形式 z = r e i θ z = r e^{i\theta} z = r e i θ を持ちます。角度 θ \theta θ は 2 π 2\pi 2 π を法として定まります。主偏角 Arg z \operatorname{Arg} z Arg z は ( − π , π ] (-\pi, \pi] ( − π , π ] に入る代表元で、負の実軸以外では atan2 ( y , x ) \operatorname{atan2}(y, x) atan2 ( y , x ) に等しくなります。
主値の対数とその分岐切断
e w = z e^w = z e w = z の解は w = ln ∣ z ∣ + i ( Arg z + 2 k π ) w = \ln|z| + i(\operatorname{Arg} z + 2k\pi) w = ln ∣ z ∣ + i ( Arg z + 2 k π ) です。主値の対数は k = 0 k = 0 k = 0 をとります:
Log z = ln ∣ z ∣ + i Arg z . \operatorname{Log} z = \ln|z| + i\operatorname{Arg} z . Log z = ln ∣ z ∣ + i Arg z .
Arg \operatorname{Arg} Arg は負の実軸をまたぐと 2 π 2\pi 2 π だけ跳ぶため、Log \operatorname{Log} Log は C ∖ ( − ∞ , 0 ] \mathbb C \setminus (-\infty, 0] C ∖ ( − ∞ , 0 ] 上で解析的であり、( − ∞ , 0 ] (-\infty, 0] ( − ∞ , 0 ] がその分岐切断 です。他の多価関数はすべて Log \operatorname{Log} Log を通じて定義され、分岐切断をそこから受け継ぎます。1 1 W. Kahan, “Branch cuts for complex elementary functions, or much ado about nothing’s sign bit”, in The State of the Art in Numerical Analysis , Clarendon Press, 1987. 符号付きゼロによって分岐切断のどちら側かを選べることについても論じています。
他の関数の主値
z = e 1 2 Log z , z w = e w Log z , asin z = − i Log ( i z + 1 − z 2 ) , acos z = π 2 − asin z , atan z = i 2 ( Log ( 1 − i z ) − Log ( 1 + i z ) ) , asinh z = − i asin ( i z ) , acosh z = 2 Log ( z + 1 2 + z − 1 2 ) , atanh z = 1 2 ( Log ( 1 + z ) − Log ( 1 − z ) ) . \begin{aligned}
\sqrt z &= e^{\frac12 \operatorname{Log} z}, &
z^w &= e^{w \operatorname{Log} z}, \\
\operatorname{asin} z &= -i\operatorname{Log}\big(iz + \sqrt{1 - z^2}\big), &
\operatorname{acos} z &= \tfrac{\pi}{2} - \operatorname{asin} z, \\
\operatorname{atan} z &= \tfrac{i}{2}\big(\operatorname{Log}(1 - iz) - \operatorname{Log}(1 + iz)\big), &
\operatorname{asinh} z &= -i\operatorname{asin}(iz), \\
\operatorname{acosh} z &= 2\operatorname{Log}\Big(\sqrt{\tfrac{z + 1}{2}} + \sqrt{\tfrac{z - 1}{2}}\Big), &
\operatorname{atanh} z &= \tfrac12\big(\operatorname{Log}(1 + z) - \operatorname{Log}(1 - z)\big).
\end{aligned} z asin z atan z acosh z = e 2 1 Log z , = − i Log ( i z + 1 − z 2 ) , = 2 i ( Log ( 1 − i z ) − Log ( 1 + i z ) ) , = 2 Log ( 2 z + 1 + 2 z − 1 ) , z w acos z asinh z atanh z = e w Log z , = 2 π − asin z , = − i asin ( i z ) , = 2 1 ( Log ( 1 + z ) − Log ( 1 − z ) ) .
関数 分岐切断 主値の範囲 log( − ∞ , 0 ] (-\infty, 0] ( − ∞ , 0 ] Im ∈ ( − π , π ] \operatorname{Im} \in (-\pi, \pi] Im ∈ ( − π , π ] sqrt( − ∞ , 0 ) (-\infty, 0) ( − ∞ , 0 ) Re ≥ 0 \operatorname{Re} \ge 0 Re ≥ 0 powz z z について ( − ∞ , 0 ] (-\infty, 0] ( − ∞ , 0 ] (w w w が整数でない場合)Log \operatorname{Log} Log からasin( − ∞ , − 1 ) ∪ ( 1 , ∞ ) (-\infty, -1) \cup (1, \infty) ( − ∞ , − 1 ) ∪ ( 1 , ∞ ) Re ∈ [ − π / 2 , π / 2 ] \operatorname{Re} \in [-\pi/2, \pi/2] Re ∈ [ − π /2 , π /2 ] acos( − ∞ , − 1 ) ∪ ( 1 , ∞ ) (-\infty, -1) \cup (1, \infty) ( − ∞ , − 1 ) ∪ ( 1 , ∞ ) Re ∈ [ 0 , π ] \operatorname{Re} \in [0, \pi] Re ∈ [ 0 , π ] atani ( − ∞ , − 1 ) ∪ i ( 1 , ∞ ) i(-\infty, -1) \cup i(1, \infty) i ( − ∞ , − 1 ) ∪ i ( 1 , ∞ ) Re ∈ [ − π / 2 , π / 2 ] \operatorname{Re} \in [-\pi/2, \pi/2] Re ∈ [ − π /2 , π /2 ] asinhi ( − ∞ , − 1 ) ∪ i ( 1 , ∞ ) i(-\infty, -1) \cup i(1, \infty) i ( − ∞ , − 1 ) ∪ i ( 1 , ∞ ) Im ∈ [ − π / 2 , π / 2 ] \operatorname{Im} \in [-\pi/2, \pi/2] Im ∈ [ − π /2 , π /2 ] acosh( − ∞ , 1 ) (-\infty, 1) ( − ∞ , 1 ) Re ≥ 0 \operatorname{Re} \ge 0 Re ≥ 0 , Im ∈ [ − π , π ] \operatorname{Im} \in [-\pi, \pi] Im ∈ [ − π , π ] atanh( − ∞ , − 1 ) ∪ ( 1 , ∞ ) (-\infty, -1) \cup (1, \infty) ( − ∞ , − 1 ) ∪ ( 1 , ∞ ) Im ∈ [ − π / 2 , π / 2 ] \operatorname{Im} \in [-\pi/2, \pi/2] Im ∈ [ − π /2 , π /2 ]
逆数系の関数は合成です: sec z = 1 / cos z \sec z = 1/\cos z sec z = 1/ cos z 、asec z = acos ( 1 / z ) \operatorname{asec} z = \operatorname{acos}(1/z) asec z = acos ( 1/ z ) など。
実部と虚部
三角関数と双曲線関数は、cos ( i y ) = cosh y \cos(iy) = \cosh y cos ( i y ) = cosh y と sin ( i y ) = i sinh y \sin(iy) = i\sinh y sin ( i y ) = i sinh y を用いた加法定理によって分解されます:
sin ( x + i y ) = sin x cosh y + i cos x sinh y , cos ( x + i y ) = cos x cosh y − i sin x sinh y , sinh ( x + i y ) = sinh x cos y + i cosh x sin y , cosh ( x + i y ) = cosh x cos y + i sinh x sin y . \begin{aligned}
\sin(x + iy) &= \sin x\cosh y + i\cos x\sinh y, &
\cos(x + iy) &= \cos x\cosh y - i\sin x\sinh y, \\
\sinh(x + iy) &= \sinh x\cos y + i\cosh x\sin y, &
\cosh(x + iy) &= \cosh x\cos y + i\sinh x\sin y .
\end{aligned} sin ( x + i y ) sinh ( x + i y ) = sin x cosh y + i cos x sinh y , = sinh x cos y + i cosh x sin y , cos ( x + i y ) cosh ( x + i y ) = cos x cosh y − i sin x sinh y , = cosh x cos y + i sinh x sin y .
設計上の決定
3 つの能力トレイト
問題。 アルゴリズムは実スカラーに対して luna-generic や arithmetic のトレイト以上のものを必要としますが、すべてのスカラー型があらゆる追加能力を持つわけではありません。
選択肢。 1 つの大きな「浮動小数点実数」トレイト、トレイトを使わない(Double をハードコードする)、階層化されたトレイト群。
選択。 それぞれ別々の関心事を扱う 3 つのトレイト:
FloatingAnalyticScalar は代数的・解析的な能力(Num、Compare、定数、実数の初等関数とその逆関数を備えた Field)に名前を付けます。IEEE 754 については何も仮定しないため、厳密な型や区間型でも満たすことができます。
FloatingSpecialValues は IEEE 754 の層に名前を付けます: NaN、符号付き無限大、ゼロの符号です。これらを持たない型にとっては意味がないため、解析トレイトには含めていません。
FloatingBackendScalar は両者を組み合わせ、以下の安定なアルゴリズムが使うプリミティブを追加します: hypot(オーバーフローしない絶対値)、log1p(1 付近の対数)、trunc と to_int(pow での整数の指数の検出)、from_double(定数)。
これにより、コードは自身の要件を表す最小のトレイトを要求できます。Luna Flow は単一の「実数」トレイトよりもこの方式を好みます。3 つとも Float と Double に対して実装されています。公開関数は依然として Complex[Double] 向けに書かれており、Double のプリミティブを直接呼び出します。これらのトレイトについてジェネリックな関数はまだありません。
自由関数
MoonBit では、パッケージが他のパッケージで定義された型にメソッドやトレイトインスタンスを追加できないため、解析関数を Complex[T] のメソッドにすることはできません。これらは @fb.log(z) のような自由関数であり、ジェネリックなコアは浮動小数点のセマンティクスから切り離されたままです。
オーバーフローしない絶対値
直接計算した x 2 + y 2 \sqrt{x^2 + y^2} x 2 + y 2 は、∣ z ∣ |z| ∣ z ∣ が表現可能であっても ∣ x ∣ > 1.34 × 10 154 |x| > 1.34 \times 10^{154} ∣ x ∣ > 1.34 × 1 0 154 でオーバーフローし、非常に小さい入力ではアンダーフローします。m = max ( ∣ x ∣ , ∣ y ∣ ) m = \max(|x|, |y|) m = max ( ∣ x ∣ , ∣ y ∣ ) 、t = min ( ∣ x ∣ , ∣ y ∣ ) / m ∈ [ 0 , 1 ] t = \min(|x|, |y|)/m \in [0, 1] t = min ( ∣ x ∣ , ∣ y ∣ ) / m ∈ [ 0 , 1 ] とすると:
∣ z ∣ = m 1 + t 2 , ln ∣ z ∣ = ln m + 1 2 ln ( 1 + t 2 ) , ∣ z ∣ 2 = m 2 ( ( x / m ) 2 + ( y / m ) 2 ) . |z| = m\sqrt{1 + t^2}, \qquad
\ln|z| = \ln m + \tfrac12 \ln(1 + t^2), \qquad
|z|^2 = m^2\big((x/m)^2 + (y/m)^2\big). ∣ z ∣ = m 1 + t 2 , ln ∣ z ∣ = ln m + 2 1 ln ( 1 + t 2 ) , ∣ z ∣ 2 = m 2 ( ( x / m ) 2 + ( y / m ) 2 ) .
abs はこの種のスケーリングを使う hypot に委譲します。abs_log は 2 番目の形を使うため、ゼロでない有限の z z z すべてに対して ln ∣ z ∣ \ln|z| ln ∣ z ∣ は有限です。abs_sqr は 3 番目の形を使い、∣ z ∣ 2 |z|^2 ∣ z ∣ 2 自体がオーバーフローする場合にのみオーバーフローします。
安定な平方根
教科書どおりの式
Re z = ∣ z ∣ + x 2 , Im z = sign ( y ) ∣ z ∣ − x 2 \operatorname{Re}\sqrt z = \sqrt{\frac{|z| + x}{2}}, \qquad
\operatorname{Im}\sqrt z = \operatorname{sign}(y)\sqrt{\frac{|z| - x}{2}} Re z = 2 ∣ z ∣ + x , Im z = sign ( y ) 2 ∣ z ∣ − x
は壊滅的な桁落ちを起こします: x > 0 x > 0 x > 0 かつ ∣ y ∣ ≪ x |y| \ll x ∣ y ∣ ≪ x では ∣ z ∣ − x |z| - x ∣ z ∣ − x がすべての桁を失い、x < 0 x < 0 x < 0 では ∣ z ∣ + x |z| + x ∣ z ∣ + x が同様になります。このパッケージは桁落ちのない量だけを計算します
w = ∣ x ∣ + ∣ z ∣ 2 = { ∣ x ∣ 1 2 ( 1 + 1 + t 2 ) , ∣ x ∣ ≥ ∣ y ∣ , t = ∣ y ∣ / ∣ x ∣ , ∣ y ∣ 1 2 ( t + 1 + t 2 ) , ∣ x ∣ < ∣ y ∣ , t = ∣ x ∣ / ∣ y ∣ , w = \sqrt{\frac{|x| + |z|}{2}} =
\begin{cases}
\sqrt{|x|}\,\sqrt{\tfrac12\big(1 + \sqrt{1 + t^2}\big)}, & |x| \ge |y|,\ t = |y|/|x|, \\
\sqrt{|y|}\,\sqrt{\tfrac12\big(t + \sqrt{1 + t^2}\big)}, & |x| < |y|,\ t = |x|/|y|,
\end{cases} w = 2 ∣ x ∣ + ∣ z ∣ = ⎩ ⎨ ⎧ ∣ x ∣ 2 1 ( 1 + 1 + t 2 ) , ∣ y ∣ 2 1 ( t + 1 + t 2 ) , ∣ x ∣ ≥ ∣ y ∣ , t = ∣ y ∣/∣ x ∣ , ∣ x ∣ < ∣ y ∣ , t = ∣ x ∣/∣ y ∣ ,
ここでスケーリングした形はオーバーフローを避けます。もう一方の部分は Re z ⋅ Im z = y / 2 \operatorname{Re}\sqrt z \cdot \operatorname{Im}\sqrt z = y/2 Re z ⋅ Im z = y /2 から復元します。x ≥ 0 x \ge 0 x ≥ 0 では根は w + y 2 w i w + \frac{y}{2w}i w + 2 w y i です。実際、w 2 = ( x + ∣ z ∣ ) / 2 w^2 = (x + |z|)/2 w 2 = ( x + ∣ z ∣ ) /2 とすると、
( w + y 2 w i ) 2 = w 2 − y 2 4 w 2 + y i = ( x + ∣ z ∣ ) 2 − y 2 2 ( x + ∣ z ∣ ) + y i = 2 x 2 + 2 x ∣ z ∣ 2 ( x + ∣ z ∣ ) + y i = x + y i . \Big(w + \frac{y}{2w}i\Big)^2 = w^2 - \frac{y^2}{4w^2} + yi
= \frac{(x + |z|)^2 - y^2}{2(x + |z|)} + yi
= \frac{2x^2 + 2x|z|}{2(x + |z|)} + yi = x + yi . ( w + 2 w y i ) 2 = w 2 − 4 w 2 y 2 + y i = 2 ( x + ∣ z ∣ ) ( x + ∣ z ∣ ) 2 − y 2 + y i = 2 ( x + ∣ z ∣ ) 2 x 2 + 2 x ∣ z ∣ + y i = x + y i .
x < 0 x < 0 x < 0 では、∣ x ∣ |x| ∣ x ∣ を使った同じ計算により、根は y y y の符号に応じて ∣ y ∣ 2 w ± w i \frac{|y|}{2w} \pm wi 2 w ∣ y ∣ ± w i です。主枝が要求するとおり、実部が負になることはありません。分岐切断上では y = − 0 y = -0 y = − 0 は y = + 0 y = +0 y = + 0 と同様に扱われるため、両側とも + ∣ x ∣ i +\sqrt{|x|}\,i + ∣ x ∣ i に写ります。
Smith の除算
教科書どおりの商は c 2 + d 2 c^2 + d^2 c 2 + d 2 で割るため、core の設計 で述べたオーバーフローの問題があります。Smith の方法は大きい方の成分で先に割ります。2 2 R. L. Smith, “Algorithm 116: Complex division”, Communications of the ACM 5(8), 1962. ∣ c ∣ ≥ ∣ d ∣ |c| \ge |d| ∣ c ∣ ≥ ∣ d ∣ のとき r = d / c r = d/c r = d / c とすると ∣ r ∣ ≤ 1 |r| \le 1 ∣ r ∣ ≤ 1 です:
a + b i c + d i = ( a + b i ) ( c − d i ) c 2 + d 2 = ( a + b i ) ( 1 − r i ) c ( 1 + r 2 ) = ( a + b r ) + ( b − a r ) i c ( 1 + r 2 ) , \frac{a + bi}{c + di}
= \frac{(a + bi)(c - di)}{c^2 + d^2}
= \frac{(a + bi)(1 - ri)}{c(1 + r^2)}
= \frac{(a + br) + (b - ar)i}{c(1 + r^2)} , c + d i a + bi = c 2 + d 2 ( a + bi ) ( c − d i ) = c ( 1 + r 2 ) ( a + bi ) ( 1 − r i ) = c ( 1 + r 2 ) ( a + b r ) + ( b − a r ) i ,
∣ d ∣ > ∣ c ∣ |d| > |c| ∣ d ∣ > ∣ c ∣ のときは r = c / d r = c/d r = c / d として対称的に計算します。2 乗されるのは r 2 ≤ 1 r^2 \le 1 r 2 ≤ 1 だけなので、分母がオーバーフローするのは商がオーバーフローする場合に限ります。div は 1 / c 1/c 1/ c を一度だけ計算し、それを掛けます。w w w に無限大の部分があり、z z z に NaN の部分がない場合、div は C99 Annex G に従います: 有限の分子はゼロの結果を与え、無限大の分子は無限大の符号の商を与えます。
厳密な整数べき
e n Log z e^{n\operatorname{Log} z} e n Log z による z n z^n z n は角度 n θ n\theta n θ と絶対値 e n ln ∣ z ∣ e^{n\ln|z|} e n l n ∣ z ∣ を丸めるため、( 1 + i ) 2 (1 + i)^2 ( 1 + i ) 2 でさえちょうど 2 i 2i 2 i にはなりません。∣ n ∣ ≤ 2 31 − 1 |n| \le 2^{31} - 1 ∣ n ∣ ≤ 2 31 − 1 の実整数の指数に対しては、pow と pow_real は代わりに二進累乗法を使います: O ( log ∣ n ∣ ) O(\log |n|) O ( log ∣ n ∣ ) 回の複素乗算で、小さなガウス整数に対しては厳密であり、z − n = ( z − 1 ) n z^{-n} = (z^{-1})^n z − n = ( z − 1 ) n です。その他の指数では e w Log z e^{w\operatorname{Log} z} e w Log z の極形式を使います: abs_log による ℓ = ln ∣ z ∣ \ell = \ln|z| ℓ = ln ∣ z ∣ と θ = arg z \theta = \arg z θ = arg z を用いて、
z w = e ( u + i v ) ( ℓ + i θ ) = e u ℓ − v θ ( cos ( u θ + v ℓ ) + i sin ( u θ + v ℓ ) ) , w = u + i v . z^w = e^{(u + iv)(\ell + i\theta)} = e^{u\ell - v\theta}\big(\cos(u\theta + v\ell) + i\sin(u\theta + v\ell)\big),
\qquad w = u + iv . z w = e ( u + i v ) ( ℓ + i θ ) = e u ℓ − v θ ( cos ( u θ + v ℓ ) + i sin ( u θ + v ℓ ) ) , w = u + i v .
z = 0 z = 0 z = 0 では、0 0 = 1 0^0 = 1 0 0 = 1 、実数 w > 0 w > 0 w > 0 に対して 0 w = 0 0^w = 0 0 w = 0 となり、それ以外の指数はすべて NaN を与えます。
オーバーフローしない正接
cos 2 x + sinh 2 y = 1 2 ( cos 2 x + cosh 2 y ) \cos^2 x + \sinh^2 y = \frac12(\cos 2x + \cosh 2y) cos 2 x + sinh 2 y = 2 1 ( cos 2 x + cosh 2 y ) を用いると tan ( x + i y ) = sin 2 x + i sinh 2 y cos 2 x + cosh 2 y \tan(x + iy) = \dfrac{\sin 2x + i\sinh 2y}{\cos 2x + \cosh 2y} tan ( x + i y ) = cos 2 x + cosh 2 y sin 2 x + i sinh 2 y です。∣ y ∣ |y| ∣ y ∣ が大きいと、tan z → ± i \tan z \to \pm i tan z → ± i であるにもかかわらず sinh 2 y \sinh 2y sinh 2 y と cosh 2 y \cosh 2y cosh 2 y がともにオーバーフローします。d = e − 2 ∣ y ∣ d = e^{-2|y|} d = e − 2∣ y ∣ として分子と分母に 2 d 2d 2 d を掛け、2 d cosh 2 y = 1 + d 2 2d\cosh 2y = 1 + d^2 2 d cosh 2 y = 1 + d 2 、2 d sinh 2 y = sign ( y ) ( 1 − d 2 ) 2d\sinh 2y = \operatorname{sign}(y)(1 - d^2) 2 d sinh 2 y = sign ( y ) ( 1 − d 2 ) を使うと:
tan ( x + i y ) = 2 d sin 2 x + i sign ( y ) ( 1 − d 2 ) 1 + d 2 + 2 d cos 2 x . \tan(x + iy) = \frac{2d\sin 2x + i\operatorname{sign}(y)(1 - d^2)}{1 + d^2 + 2d\cos 2x} . tan ( x + i y ) = 1 + d 2 + 2 d cos 2 x 2 d sin 2 x + i sign ( y ) ( 1 − d 2 ) .
tan は ∣ y ∣ ≥ 1 |y| \ge 1 ∣ y ∣ ≥ 1 でこの形を使い、それ未満では精度のよい直接の形を使います。tanh は x x x と y y y の役割を入れ替えて同じ導出を適用します。
Hull、Fairgrieve、Tang による逆正弦アルゴリズム
x , y ≥ 0 x, y \ge 0 x , y ≥ 0 に対し、r = ∣ z + 1 ∣ r = |z + 1| r = ∣ z + 1∣ 、s = ∣ z − 1 ∣ s = |z - 1| s = ∣ z − 1∣ 、A = r + s 2 ≥ 1 A = \frac{r + s}{2} \ge 1 A = 2 r + s ≥ 1 、B = x / A ≤ 1 B = x/A \le 1 B = x / A ≤ 1 とします。このとき3 3 T. E. Hull, T. F. Fairgrieve and P. T. P. Tang, “Implementing the complex arcsine and arccosine functions using exception handling”, ACM Transactions on Mathematical Software 23(3), 1997. 切り替えの値 1.5 1.5 1.5 と 0.6417 0.6417 0.6417 は同論文によるものです。
asin z = arcsin B + i ln ( A + A 2 − 1 ) , acos z = arccos B − i ln ( A + A 2 − 1 ) , \operatorname{asin} z = \arcsin B + i\ln\big(A + \sqrt{A^2 - 1}\big),
\qquad
\operatorname{acos} z = \arccos B - i\ln\big(A + \sqrt{A^2 - 1}\big), asin z = arcsin B + i ln ( A + A 2 − 1 ) , acos z = arccos B − i ln ( A + A 2 − 1 ) ,
であり、他の象限は各部分の奇関数性から得られます。どちらの式も 2 つの領域で精度を失うため、アルゴリズムはそれらを別扱いします:
B B B が 1 1 1 に近い(B > 0.6417 B > 0.6417 B > 0.6417 )とき、arcsin B \arcsin B arcsin B は悪条件です。実部は、r + x + 1 r + x + 1 r + x + 1 と s ± ( 1 − x ) s \pm (1 - x) s ± ( 1 − x ) から減算なしで作った量 D D D を用いて arctan ( x / D ) \arctan(x/\sqrt D) arctan ( x / D ) として計算します。
A A A が 1 1 1 に近い(A ≤ 1.5 A \le 1.5 A ≤ 1.5 )とき、ln ( A + A 2 − 1 ) \ln(A + \sqrt{A^2 - 1}) ln ( A + A 2 − 1 ) は A 2 − 1 A^2 - 1 A 2 − 1 の影響を受けます。アルゴリズムは y 2 / ( r + x + 1 ) y^2/(r + x + 1) y 2 / ( r + x + 1 ) と s ± ( 1 − x ) s \pm (1 - x) s ± ( 1 − x ) から桁落ちなしに A − 1 A - 1 A − 1 を計算し、log1p ( ( A − 1 ) + ( A − 1 ) ( A + 1 ) ) \operatorname{log1p}\big((A - 1) + \sqrt{(A - 1)(A + 1)}\big) log1p ( ( A − 1 ) + ( A − 1 ) ( A + 1 ) ) を使います。
∣ x ∣ |x| ∣ x ∣ または ∣ y ∣ |y| ∣ y ∣ が 10 150 10^{150} 1 0 150 を超え、r r r と s s s がオーバーフローする場合、asin は 1 − z 2 ≈ − i z \sqrt{1 - z^2} \approx -iz 1 − z 2 ≈ − i z から得られる漸近形 asin z ≈ atan2 ( x , y ) + i ( ln 2 + ln ∣ z ∣ ) \operatorname{asin} z \approx \operatorname{atan2}(x, y) + i(\ln 2 + \ln|z|) asin z ≈ atan2 ( x , y ) + i ( ln 2 + ln ∣ z ∣ ) を使います。そこでは acos は π / 2 − asin z \pi/2 - \operatorname{asin} z π /2 − asin z を使います。
逆正接と逆双曲線正接
z = x + i y z = x + iy z = x + i y として q = ( 1 + i z ) / ( 1 − i z ) q = (1 + iz)/(1 - iz) q = ( 1 + i z ) / ( 1 − i z ) と書くと:
q = ( 1 − y ) + i x ( 1 + y ) − i x , ∣ q ∣ 2 = x 2 + ( 1 − y ) 2 x 2 + ( 1 + y ) 2 , arg q = atan2 ( 2 x , 1 − x 2 − y 2 ) , q = \frac{(1 - y) + ix}{(1 + y) - ix}, \qquad
|q|^2 = \frac{x^2 + (1 - y)^2}{x^2 + (1 + y)^2}, \qquad
\arg q = \operatorname{atan2}\big(2x,\ 1 - x^2 - y^2\big), q = ( 1 + y ) − i x ( 1 − y ) + i x , ∣ q ∣ 2 = x 2 + ( 1 + y ) 2 x 2 + ( 1 − y ) 2 , arg q = atan2 ( 2 x , 1 − x 2 − y 2 ) ,
となり、atan z = 1 2 i Log q \operatorname{atan} z = \frac{1}{2i}\operatorname{Log} q atan z = 2 i 1 Log q から次が得られます
atan z = 1 2 atan2 ( 2 x , 1 − x 2 − y 2 ) + i 4 ln x 2 + ( 1 + y ) 2 x 2 + ( 1 − y ) 2 . \operatorname{atan} z = \tfrac12\operatorname{atan2}(2x, 1 - x^2 - y^2) +
\tfrac{i}{4}\ln\frac{x^2 + (1 + y)^2}{x^2 + (1 - y)^2} . atan z = 2 1 atan2 ( 2 x , 1 − x 2 − y 2 ) + 4 i ln x 2 + ( 1 − y ) 2 x 2 + ( 1 + y ) 2 .
対数の中の比は、u = 2 y / ( 1 + ∣ z ∣ 2 ) u = 2y/(1 + |z|^2) u = 2 y / ( 1 + ∣ z ∣ 2 ) として ( 1 + u ) / ( 1 − u ) (1 + u)/(1 - u) ( 1 + u ) / ( 1 − u ) に等しくなります。∣ u ∣ < 0.1 |u| < 0.1 ∣ u ∣ < 0.1 のとき、実軸付近での精度を保つため、このパッケージはこれを log1p ( u ) − log1p ( − u ) \operatorname{log1p}(u) - \operatorname{log1p}(-u) log1p ( u ) − log1p ( − u ) として評価します。∣ z ∣ |z| ∣ z ∣ が大きいときは、m = max ( ∣ x ∣ , ∣ y ∣ ) m = \max(|x|, |y|) m = max ( ∣ x ∣ , ∣ y ∣ ) として実部を x / m , y / m x/m, y/m x / m , y / m 上で評価します。atanh は atanh z = − i atan ( i z ) \operatorname{atanh} z = -i\operatorname{atan}(iz) atanh z = − i atan ( i z ) から、x x x と y y y を入れ替えた同じ計算であり、∣ 4 x / ( ( 1 − x ) 2 + y 2 ) ∣ < 1 / 4 |4x/((1 - x)^2 + y^2)| < 1/4 ∣4 x / (( 1 − x ) 2 + y 2 ) ∣ < 1/4 のときに log1p \operatorname{log1p} log1p に切り替えます。
acosh は安定な平方根から組み立てた 2 Log ( ( z + 1 ) / 2 + ( z − 1 ) / 2 ) 2\operatorname{Log}\big(\sqrt{(z + 1)/2} + \sqrt{(z - 1)/2}\big) 2 Log ( ( z + 1 ) /2 + ( z − 1 ) /2 ) を使います。Log ( z + z 2 − 1 ) \operatorname{Log}(z + \sqrt{z^2 - 1}) Log ( z + z 2 − 1 ) とは異なり、各平方根の分岐切断はその引数が負の実数となる場所にあるため、追加の符号調整なしで正しい分岐切断 ( − ∞ , 1 ) (-\infty, 1) ( − ∞ , 1 ) を持ちます。
厳密な実数の高速パス
sin と cos は y = 0 y = 0 y = 0 ちょうどのとき実関数の値を返します。asin、acos、asinh、acosh、atanh は、実数の入力を _real 関数へ、純虚数の入力を y y y の実逆関数へ振り分けます。これにより実数直線上の結果は厳密に実数のままとなり、_real 関数は Double から始める呼び出し側にも役立ちます。
コアの逆数を通じた逆数系の関数
sec、csc、cot、それらの双曲線版、および逆数系の逆関数は、core の Complex::inv との合成です。そのスケーリングしない式と、絶対値がゼロのときの中断を受け継ぎ、極で無限大を返すことはありません。acot は z = 0 z = 0 z = 0 を特別扱いして π / 2 \pi/2 π /2 を返します。
正しさと不変条件
テストスイートで確認している恒等式
第 1 象限のサンプル点における exp(log z) = z、sin(asin z) = z、cos(acos z) = z、tan(atan z) = z、sinh(asinh z) = z、tanh(atanh z) = z(許容誤差 10 − 10 10^{-10} 1 0 − 10 ~ 10 − 12 10^{-12} 1 0 − 12 )。sqrt(-3 + 4i) = 1 + 2i。非常に大きな asin の引数、atan の分岐切断、無限大の atanh と acosh の入力、無限大による除算、0 0 0^0 0 0 、0 − 1 0^{-1} 0 − 1 に対する回帰テスト。
主値からの既知の逸脱
実装は、主値では π \pi π が必要な箇所で定数 2 π 2\pi 2 π (tau)を使っています:
関数と入力 返される値 主値 arg(z), y = ± 0 y = \pm 0 y = ± 0 , x < 0 x < 0 x < 0 2 π 2\pi 2 π π \pi π (C99: y y y の符号により ± π \pm\pi ± π )log(z)、同じ入力ln ∣ x ∣ + 2 π i \ln\lvert x\rvert + 2\pi i ln ∣ x ∣ + 2 π i ln ∣ x ∣ + π i \ln\lvert x\rvert + \pi i ln ∣ x ∣ + π i pow、pow_real、負の実数の底、整数でない指数角度 2 π 2\pi 2 π 角度 π \pi π acos(z), x < 0 x < 0 x < 0 , y ≠ 0 y \ne 0 y = 0 2 π − ρ + … 2\pi - \rho + \dots 2 π − ρ + … π − ρ + … \pi - \rho + \dots π − ρ + … acos_real(x), x < − 1 x < -1 x < − 1 2 π − i acosh ∣ x ∣ 2\pi - i\operatorname{acosh}\lvert x\rvert 2 π − i acosh ∣ x ∣ π − i acosh ∣ x ∣ \pi - i\operatorname{acosh}\lvert x\rvert π − i acosh ∣ x ∣ asec_real(x), − 1 < x < 0 -1 < x < 0 − 1 < x < 0 2 π − i acosh ∣ 1 / x ∣ 2\pi - i\operatorname{acosh}\lvert 1/x\rvert 2 π − i acosh ∣ 1/ x ∣ π − i acosh ∣ 1 / x ∣ \pi - i\operatorname{acosh}\lvert 1/x\rvert π − i acosh ∣ 1/ x ∣ acosh_real(x), x < − 1 x < -1 x < − 1 acosh ∣ x ∣ + 2 π i \operatorname{acosh}\lvert x\rvert + 2\pi i acosh ∣ x ∣ + 2 π i acosh ∣ x ∣ + π i \operatorname{acosh}\lvert x\rvert + \pi i acosh ∣ x ∣ + π i
e 2 π i = 1 e^{2\pi i} = 1 e 2 π i = 1 であるのに対し e π i = − 1 e^{\pi i} = -1 e π i = − 1 なので、これらの値は入力の対数や逆関数の値ですらありません: exp(log(-1)) は 1 1 1 であり、x < 0 x < 0 x < 0 では cos(acos(z)) は − z -z − z です。テストスイートは現在、負の実軸上での arg の値 2 π 2\pi 2 π を検証しています。これらは実装で修正すべき欠陥であり、このマニュアルは現在の振る舞いを記録しています。
その他の精度に関する注意
asin は A ≤ 1.5 A \le 1.5 A ≤ 1.5 の分岐で A 2 − 1 \sqrt{A^2 - 1} A 2 − 1 を評価しますが、Hull–Fairgrieve–Tang アルゴリズム(およびここでの acos)は ( A − 1 ) ( A + 1 ) \sqrt{(A - 1)(A + 1)} ( A − 1 ) ( A + 1 ) を使います。分岐点 ± 1 \pm1 ± 1 の近くではこれにより桁が失われます: 1 + 10 − 10 i 1 + 10^{-10}i 1 + 1 0 − 10 i では虚部の相対誤差が 4 × 10 − 8 4 \times 10^{-8} 4 × 1 0 − 8 程度になります。
exp は cos y \cos y cos y と sin y \sin y sin y を掛ける前に e x e^x e x でオーバーフローするため、exp(710 + 0i) の虚部は NaN になります(∞ ⋅ 0 \infty \cdot 0 ∞ ⋅ 0 )。
log1p の Float インスタンスは ln ( 1 + x ) \ln(1 + x) ln ( 1 + x ) であり、∣ x ∣ ≪ 1 |x| \ll 1 ∣ x ∣ ≪ 1 で相対精度が失われます。これを使う公開関数はまだありません。
採用しなかった代替案
Complex のメソッド。 別パッケージからは不可能であり、関数をコアに移すとジェネリック型に IEEE のセマンティクスが持ち込まれます。
単一の浮動小数点実数トレイト。 あらゆる解析スカラーに IEEE の特殊値を強制することになります。
どこでも教科書どおりの式。 より単純ですが、上で導出したとおり ∣ z ∣ ≳ 10 154 |z| \gtrsim 10^{154} ∣ z ∣ ≳ 1 0 154 でオーバーフローし、分岐切断の近くで桁落ちを起こします。
C99 Annex G の特殊値表の完全な実装。 API に記載したケースだけを処理し、残りの無限大と NaN は通常の算術を通じて伝播します。
範囲外
解析関数は Complex[Double] 向けのみです。トレイトは Float に対して実装されていますが、Complex[Float] 向けの関数はありません。
arg を除き、符号付きゼロによる分岐切断の側の選択は行いません。
逆数系の関数は極で無限大を返すのではなく中断します。
誤差限界の保証はありません。精度は回帰テストで確認しています。
検査付きや文脈付き(Result)の版はありません。