Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 10210] ファイルの概要

このコミットは、Go言語の標準ライブラリmathパッケージにおけるTan(タンジェント)関数の精度向上を目的としています。具体的には、タンジェントの計算に使用されるアルゴリズムが、より高精度なCephes Math Libraryのコードベースを基にしたものに置き換えられました。

コミット

commit cefee3c919221a38d6eb93c8199d3d88ad5ae0b7
Author: Charles L. Dorian <cldorian@gmail.com>
Date:   Wed Nov 2 14:01:21 2011 -0400

    math: improved accuracy for Tan
    
    R=rsc
    CC=golang-dev
    https://golang.org/cl/5298087

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/cefee3c919221a38d6eb93c8199d3d88ad5ae0b7

元コミット内容

math: improved accuracy for Tan

このコミットは、Go言語のmathパッケージに含まれるTan関数の精度を向上させることを目的としています。

変更の背景

浮動小数点演算における三角関数(特にタンジェント)の計算は、数値計算の精度に大きく影響します。初期のGo言語のmathパッケージにおけるTan関数の実装は、特定の入力値に対して十分な精度を提供していなかった可能性があります。このコミットは、より信頼性が高く、広範囲の入力に対して高精度な結果を保証するために、計算アルゴリズムを改善する必要があったという背景があります。

コミットメッセージに記載されているように、この変更はR=rsc(おそらくRuss Cox氏によるレビュー)とCC=golang-dev(Go開発者メーリングリストへの通知)を経ており、Go言語の標準ライブラリの品質向上に向けた通常の開発プロセスの一環として行われました。特に、https://golang.org/cl/5298087というChangeListへのリンクは、Goの開発におけるコードレビューと変更管理のプロセスを示しています。

前提知識の解説

浮動小数点数と精度

コンピュータにおける数値表現には、整数と浮動小数点数があります。浮動小数点数は、実数を近似的に表現するための形式であり、IEEE 754規格が広く用いられています。浮動小数点数は、限られたビット数で広範囲の数値を表現できる一方で、精度には限界があります。特に、無限小数や無理数を正確に表現することはできず、丸め誤差が発生します。

三角関数(タンジェント)

タンジェント(tan)は、直角三角形における対辺と隣辺の比で定義される三角関数です。数学的には、tan(x) = sin(x) / cos(x)と表されます。タンジェント関数は、x = (n + 1/2)π(nは整数)の点で特異点(無限大)を持ちます。コンピュータでタンジェントを計算する際には、これらの特異点の近くでの挙動や、広範囲の入力値に対する精度が重要になります。

数値計算ライブラリと精度

科学技術計算やグラフィックスなど、高精度な数値計算が求められる分野では、専用の数値計算ライブラリが利用されます。これらのライブラリは、浮動小数点演算の特性を考慮し、丸め誤差を最小限に抑えつつ、効率的に高精度な結果を出すためのアルゴリズムを実装しています。

Cephes Math Library

Cephes Math Libraryは、Stephen L. Moshierによって開発された、C言語で書かれた数値計算関数のライブラリです。このライブラリは、三角関数、指数関数、対数関数、特殊関数など、幅広い数学関数を高精度で提供することで知られています。多くの科学技術計算ソフトウェアやプログラミング言語の標準ライブラリで、そのアルゴリズムや実装が参考にされてきました。このコミットでは、Tan関数の実装にCephes Math Libraryの知見が取り入れられています。

レンジリダクション (Range Reduction)

三角関数のような周期関数を計算する際、入力値xが非常に大きい場合、直接計算すると精度が低下したり、オーバーフローが発生したりする可能性があります。これを避けるために、「レンジリダクション」という手法が用いられます。これは、入力値xを関数の周期性を利用して、より小さな「基本区間」内の値x'に変換するプロセスです。例えば、tan(x)の場合、x[-π/4, π/4]のような基本区間にマッピングすることで、この区間内で高精度な近似計算を行い、その結果を元のxに対する値として利用します。

技術的詳細

このコミットにおけるTan関数の精度向上は、主に以下の技術的変更によって実現されています。

  1. Cephes Math Libraryに基づくアルゴリズムの採用: 以前のTan関数は、Hart & Cheneyの係数(おそらく多項式近似)を使用していたようですが、このコミットではCephes Math Libraryのtan.cのアルゴリズムが導入されました。Cephesのアルゴリズムは、より広範囲の入力値に対して高い精度を保証するように設計されています。

  2. 多項式近似の係数変更: 新しい実装では、_tanP_tanQという2つのfloat64型配列で定義された新しい係数が導入されています。これらは、基本区間[0, π/4]におけるタンジェント関数の有理関数近似(多項式の比)に使用されます。

    • _tanP: 分子多項式の係数
    • _tanQ: 分母多項式の係数
  3. 改良されたレンジリダクション: 入力xπ/4の倍数で割ることで、基本区間[0, π/4]にマッピングするレンジリダクションがより堅牢に行われるようになりました。

    • j := int64(x * M4PI): xπ/4で割った整数部分を計算します。ここでM4PI4/πの近似値です。
    • z := ((x - y*PI4A) - y*PI4B) - y*PI4C: xからy * (π/4)を引くことで、基本区間内の値zを計算します。ここでPI4A, PI4B, PI4Cπ/4を複数に分割して表現したもので、浮動小数点演算の精度を保つためのテクニックです。
  4. 特異点と特殊値のハンドリング:

    • Tan(±0)±0を返します。
    • Tan(±Inf)(無限大)はNaN(非数)を返します。
    • Tan(NaN)NaNを返します。 これらの特殊なケースは、関数の冒頭で明示的に処理されます。
  5. テストケースの変更: src/pkg/math/all_test.goでは、TestTan関数内のテストアサーションがcloseからverycloseに変更されています。これは、新しい高精度な実装に合わせて、より厳密な比較が必要になったことを示唆しています。また、Tan(Pi/2)のパニックに関するコメントアウトされたテストコードが削除されています。これは、新しい実装がこのケースを適切に処理できるようになったため、もはや不要になったことを意味します。

コアとなるコードの変更箇所

src/pkg/math/all_test.go

  • import "runtime"が削除されました。
  • TestTan関数内で、!close(tan[i], f)!veryclose(tan[i], f)に変更されました。これは、テストにおける許容誤差がより厳しくなったことを示しています。
  • Tan(Pi/2)の挙動に関する特定のアーキテクチャ(386以外)向けのテストブロックが削除されました。これは、新しいTanの実装がPi/2のような特異点に近い値に対しても、よりロバストにNaNを返すようになったためと考えられます。

src/pkg/math/tan.go

  • 著作権表示が2009から2011に更新されました。
  • Cephes Math Libraryからのコメントブロックが追加され、tan.cの概要、精度、およびライセンス情報が詳細に記述されています。
  • _tanP_tanQという新しいfloat64型配列が導入され、タンジェントの有理関数近似のための係数が定義されました。
  • Tan関数の実装が完全に書き直されました。
    • 以前のHart & Cheneyの係数(P0からP4Q0からQ2)が削除されました。
    • PI4A, PI4B, PI4C, M4PIといった新しい定数が導入されました。これらはレンジリダクションと精度維持のために使用されます。
    • 特殊な入力値(0, NaN, Inf)に対する早期リターンが追加されました。
    • 入力値の符号を保存し、絶対値で計算を進めるロジックが導入されました。
    • xπ/4の倍数で割ることで、基本区間へのマッピングを行う新しいレンジリダクションのロジックが実装されました。
    • zzz*z)の値に基づいて、有理関数近似を行うか、単純にzを返すかの分岐が追加されました。これは、zが非常に小さい場合に不必要な計算を避けるためです。
    • 最終的な結果に符号を適用し、必要に応じて逆数を取る(1/y)ロジックが追加されました。

コアとなるコードの解説

新しいTan関数の実装は、Cephes Math Libraryの設計思想に基づいています。

  1. 特殊ケースの処理:

    switch {
    case x == 0 || x != x: // x == 0 || IsNaN():
        return x // return ±0 || NaN()
    case x < -MaxFloat64 || x > MaxFloat64: // IsInf(x, 0):
        return NaN()
    }
    

    このブロックは、入力x0NaN、または無限大(±Inf)である場合の特殊な挙動を定義しています。これにより、これらのエッジケースが正確かつ効率的に処理されます。

  2. 符号の処理:

    sign := false
    if x < 0 {
        x = -x
        sign = true
    }
    

    タンジェント関数は奇関数(tan(-x) = -tan(x))であるため、入力xの絶対値で計算を行い、最後に結果に符号を適用することで、計算を簡略化し、精度を維持します。

  3. レンジリダクション:

    j := int64(x * M4PI) // integer part of x/(Pi/4), as integer for tests on the phase angle
    y := float64(j)      // integer part of x/(Pi/4), as float
    
    /* map zeros and singularities to origin */
    if j&1 == 1 {
        j += 1
        y += 1
    }
    
    z := ((x - y*PI4A) - y*PI4B) - y*PI4C
    zz := z * z
    

    この部分は、入力xπ/4の基本区間にマッピングするレンジリダクションの核心です。

    • jxπ/4の何倍であるかを示す整数部分です。
    • j&1 == 1の条件は、jが奇数である場合(つまり、xπ/4の奇数倍に近い場合)に調整を行います。これは、タンジェントの特異点(π/2, 3π/2など)を避けるための位相調整です。
    • zは、xからy * (π/4)を引いた残りの部分であり、これが基本区間[0, π/4]内の値となります。PI4A, PI4B, PI4Cπ/4を分割することで、浮動小数点演算の精度を最大限に引き出しています。
  4. 有理関数近似:

    if zz > 1e-14 {
        y = z + z*(zz*(((_tanP[0]*zz)+_tanP[1])*zz+_tanP[2])/((((zz+_tanQ[1])*zz+_tanQ[2])*zz+_tanQ[3])*zz+_tanQ[4]))
    } else {
        y = z
    }
    

    zが十分に大きい場合(zz > 1e-14)、zの有理関数近似が適用されます。この有理関数は、_tanP_tanQで定義された多項式の比によって計算されます。これは、基本区間内でのタンジェントの値を高精度に近似するためのものです。zが非常に小さい場合(zz <= 1e-14)、tan(z)はほぼzに等しいため、単純にzが返されます。

  5. 最終調整:

    if j&2 == 2 {
        y = -1 / y
    }
    if sign {
        y = -y
    }
    return y
    
    • j&2 == 2の条件は、j2または3の倍数である場合(つまり、xπ/2または3π/2の倍数に近い場合)に適用されます。これは、タンジェントの周期性(tan(x + π) = tan(x))と、tan(x + π/2) = -cot(x) = -1/tan(x)の関係を利用して、結果を調整します。
    • 最後に、元の入力xの符号を結果yに適用します。

この新しい実装は、レンジリダクションと有理関数近似を組み合わせることで、広範囲の入力値に対して高い精度とロバスト性を持つTan関数を提供します。

関連リンク

参考にした情報源リンク