世界を動かす技術を、日本語で。

ターンはラジアンより優れている (2022)

概要

π(パイ)やτ(タウ)を使うよりも、そもそも不要にできるケースが多い 多くのコードはπやτでラジアン変換し、すぐに逆変換している [0,1]のターン(turns)表現が計算効率・精度ともに優れる sinやcosの引数をラジアンからターンに切り替えるだけで多くの問題が解決 既存の数学ライブラリでもターンやハーフターンをサポートしているものがある

πやτの置き換えより「削除」が有効な理由

  • πやτは多くの場合、角度変換のためだけに使われている

  • ほとんどのコードでは、値h(0~1の周期的な値)をsinやcosの入力に使う際、無意味にπやτで変換

  • 数学ライブラリ側でも、入力値を内部で4/πなどの定数で再変換している

  • 結果として、πやτで変換→すぐ逆変換という無駄な計算が発生

    • 例:sin(h * 2 * π) → ライブラリ内部でy = (4 / π) * x
  • この無駄を排除し、[0,1]のターン表現をそのまま使うことで計算が簡潔に

[0,1]ターン表現の利点

  • 0が0度、0.25が90度、0.5が180度、1が360度という直感的な表現
  • 90度=0.25のように、2進数で正確に表現できる角度が多い
  • ラジアンでは90度=π/2であり、どれだけビット数を増やしても正確には表せない
  • [0,1]ターンは計算効率が高く、典型的な値の精度も高い

ターン(turns)やハーフターン(half-turns)への切り替え方法

  • sinやcos関数の引数をラジアンからターンに変更するだけでOK

  • 既存コードとの互換性が必要なら、新しい関数名でターン版を用意し、旧関数は内部で変換

  • ターン以外にも[0,2]のハーフターン(full circleが2)を使う方法もあり

  • CUDAのsincospiのように、π倍で計算する関数も既に存在

    • これらを活用すればπやτを使わずに済む

心理的ハードルと数学的正当性

  • 「ラジアンを使わないのは間違い」という先入観は不要
  • ターンは数学的にも正式な表現であり、既に定義されている
  • 0が0度、0.5が180度、1が360度という明快な対応関係

実際の運用例とメリット

  • 実際にラジアンを排除したコードベースでは、πやτが消え、可読性・保守性が向上
  • sinやcosだけでなく、他の三角関数も同様にターン対応にできる
  • 多くの数学ライブラリは内部でラジアン変換を行っているため、ターンやハーフターンへの切り替えは簡単
  • πやτを使わないことで、計算の無駄と誤差が減る

まとめ

  • πやτを置き換えるより「削除」する方が効果的
  • [0,1]ターンや[0,2]ハーフターンで角度を扱うことで、計算効率と精度が向上
  • 既存の数学ライブラリやプラットフォームでもサポートが進んでいる
  • 心理的な抵抗を捨て、より合理的な角度表現へ移行するメリット

Hackerたちの意見

自分のコードでは角度を回転数として保存するのが好きなんだ。そうすれば、四分の一回転の計算が丸めずにできるからね。一方で、例えば十二分の一回転が必要な場合は、度数で保存した方がいいかもしれない。だって、それが一般的だから。マイケル・スピバックは『Calculus』(第3版 p. 301)で、単位の選択は関数の特性だと考えて、最初にsin°とsinʳを定義して、最終的にはsinはsinʳを意味することに落ち着いたんだ。「sin x°」や「sin xラジアン」は誤解を招くと言っていて、‘数値xは単なる数値であって、「度数」や「ラジアン」であることを示すバナーは持っていない’って。正直、この主張はよく分からない。科学や工学では、常に量に単位を持ち歩いているからね。

ラジアンも度数も、長さの比率であり、次元がないからだ。どう測っても、すべての角度は単位なしなんだ。ラジアンで見ると最も明らかだけど、度数でも同じことが言える。ラジアンを使えば、角度を再スケールするために変な余分な項を導入することがないから、他の角度のスケールを使うと余分な項を追跡しなきゃいけなくなる。それがやっていることによって役立つかもしれない。自分は度数をよく使うけど、2π/360の項を常に気にしているよ。グレード測定では2π/400の項を、回転数では2π/1の項を追跡しなきゃいけない。それが必要かどうかは、やっていることによるけどね。一般的に、スケーリング項が2π/2πのとき、数学は簡単に解決するから、面倒な1のスケールファクターを気にしなくて済むんだ。

一般的に、次元の単位に関数を適用することはできないんだ。単位ができることは、掛け算か割り算だけ。だから、質量を距離で掛けたり、距離を速度で割ったりはできるけど、距離のサインを取ったり、時間の対数を取ったり、質量を指数化することはできない。そういうのはスカラーに対してだけできるんだ。「でも待って!」って言うかもしれないけど、「横波の公式は距離のサインで変わる!」って言うかもしれないね。だけど、そうじゃなくて、距離(横の変位)のサインを別の距離(波長)で割って、さらに2πで割るんだ。距離がキャンセルされてスカラーだけが残る。サインはその純粋なスカラーに対して取られるから、結果は純粋なスカラーになる。そして、それを別の距離(振幅)で掛けて、縦の変位を得るんだ。サインは純粋な関数なんだよ。もう一つ考慮すべきことは、単位とスカラーを掛け合わせて次元量を作る方法が掛け算であること。サインの積の簡単な公式なんてないから、sin(ab)をaとbのサインや他の関数で表すことはできない。だから、例えば「度」が何らかの次元単位だったら、sin(90°)は計算できないんだ。sin(90)は知ってるけど、sin(°)はわからないからね。たとえそれを知っても、sin(90°)を求めることには近づかない。°が単にπ/180に等しい数学的定数だと気づくことで、かなり解決するんだ。

問題は、三角関数が幾何学だけでなく、もっと多くの分野で使われていることだ。入力が必ずしもユークリッド空間の点周りの角度とは限らなくて、周期信号の位相角であることもある。回転数を使う代替の三角関数を作ることはできるけど、オリジナルの三角関数をいじると、多くの人を怒らせることになるよ。

どこかで2πの因子を持ち込まなきゃいけない。逃げられないよ。sintが角度を回転数で与えたsin関数なら、d/dx sint(x) = 2π cost(x)になる。sin(x)は小さいxに対してはxに近いけど、sint(x)は小さいxに対しては2πxに近い。

波を扱うときは、しばしばターン、つまりその世界ではサイクルを扱ってることが多い。サイクルはターンで、τは2πだよ。結局、周波数のSI単位はヘルツ、つまりサイクル毎秒なんだけど、実際には2π s^-1と考えるべきなんだ。でも、複雑な理由でそうなってないことが多いし、周波数を含むほとんどの公式は「サイクル」を無視してるか、波長やプランク定数の定義の中に隠れていてキャンセルされちゃう。ちなみに、角速度のSI単位はラジアン毎秒で、これは次元的にはs^-1と等しいんだ。とはいえ、離散イベントの発生率を測るベクレルも次元的にはs^-1なんだよ。(次回、ウェブサイトのトラフィックを測るときは、リクエスト毎秒を測るための適切なSI単位、つまりベクレルを使ってみてね。)だから、次元的な等価性は単なる等価性とは違うんだ。周波数にレートを足すことはないし、エネルギーの量にトルクを足すべきじゃないのと同じだね。

すごく大胆なタイトルだね!回転数は便利だけど、変化率を計算する必要があるときは困る。だって、d/dx sin(2π x) = 2π cos(2π x)だから。残念ながら、これはよくある問題だから、ラジアンを使い続けるつもりだよ。

なんか、自分が数学を学んだ感じに近い気がする。幾何学や三角法では度数や回転数、他の単位を使えるけど、ラジアンは書くのが難しいからほとんど使わない。微積分を学ぶとすぐにラジアンに切り替えて、もう戻らないんだよね。

この考えにはある程度同意するけど、実際の答えはアプリケーション依存だと思う。もし低レベルの三角ライブラリを書いていて、どちらかを選ばなきゃいけないなら、回転数がラジアンに勝つとは思えない。三角法を使う多くのシステムは、効率のためや一般的なケースにブートストラップするために小角近似を使うことがあると思う。ここでテイラー級数を使うのが自然だよね。つまり、cos(x) = 1 - x^2/2 + ...、sin(x) = x - x^3/6 + ...。もしすべての三角法を「回転」単位で表現することに決めたら、代わりにこうなる:cos(2π t) = 1 - (2π t)^2/2 + ...、sin(2π t) = (2π t) - (2π t)^3/6 + ...。この場合、ラジアンで作業する必要があるなら、すべてを回転数に強制するのは精度や効率が低くなる。これに密接に関連して、三角関数の導関数が必要な場合(例えば数値最適化で)、ラジアンを使った方がいい。そうしないと、適用する余分な因子が導関数の式に現れて、結局それに対処しなきゃいけなくなるから。基本的にその理由から、数学的に言えばラジアンの三角法が「正しい」慣習だってことは明らかだよね(コンピュータを離れて)。そう考えると、どちらかの慣習を選ばなきゃいけないなら...どこでも同じものを使った方が混乱しないんじゃない?とはいえ、両方のバージョンを提供するインターフェースもあるし、記事が指摘しているように回転数のバージョンが効率的な場合もあるから、それが正しい方向かもしれないね。

ここでの経験はそんなに広くないし、数値解析は専門じゃないけど、見てきたほとんどの三角関数の実装(ソフトウェアとハードウェア両方)では、ルックアップテーブルや他のショートカットを多用しているよ。一般的な実装でテイラー級数が使われているのは見たことがない。どこかには存在するかもしれないけど、自分が知っているほとんどのケースでは、異なるルックアップテーブルで回転数をサポートするのが簡単だと思う。

「ターン」が本当に素晴らしいのは、やってることの大半がフェーズアキュムレーターのときだよね。

でも、数学はサインとコサインがラジアンの引数を取る必要があるとは決めてないよ!ラジアンを使わないと、微積分をするためにあちこちに変換係数を追加しなきゃならない。サインやコサインの自然な単位はラジアンなんだ。Eが対数や指数関数の自然な基数であるのと同じようにね。

Hacker Newsで議論の続きを見る