2014年2月18日火曜日

浮動小数点数型と正弦関数とπについてのコラムみたいなこと

1. 浮動小数点数型を扱う正弦関数にπを与えると何が起こるか


こうなります。

連続した完全な数を扱う数学では正弦関数に`sin(2π*0.5)`を与えると、ちょうどピッタリ気持ちの良い`0`が得られます。同様に`sin(2π*1)`を与ええても、ちょうどピッタリ気持ちの良い`0`が得られます。

でも、現在一般的な計算機の扱う浮動小数点数型(実装の詳細はIEEE754を確認しましょう)は離散的で丸め込みを伴います。その結果、上図の様な現象が発生します。

通常、この値をほぼ直接用いる場合は一般的なスケールでの用途では「ほぼ限りなくゼロ」ですから、実用上問題にならないことがほとんどでしょう。

2. このような状況で正弦関数を用いて矩形波を生成すると何が起こるか


こうなります。

浮動小数点数型を扱う正弦関数の出力はちょうど0になる事は無く、丸め誤差によってごくわずかに正負の値を持ちます。

この値が綺麗に交互に出現してくれるなら矩形波にするだけであれば問題は小さいのですが、`6 6.5 7`の3つに対して負の値が連続している為に、ほんのごく僅かに偏りが生じます。

このような偏りは、上図の上部に表示している様に、長い周期で見ればほぼ均衡が保たれますが、部分的にはごく僅かに偏りが生じます。

ちなみに上図の一番右の綺麗に50%:50%が確認できる関数はもとのtimeを周期で剰余算したものが周期の1/2未満であるかを判定して矩形波を生成する場合の例で、そうすると、気持ちの良い矩形波を生成できます。(一般的に単に気持ち良いだけです。

これがシビアに問題になる例は一般にはほとんど無いのでしょうけれど、知識として、浮動小数点数型について考えるお題としては少しは面白いかな?

Appendix.A: floor関数による美しい矩形波の実装方法

ふと記事を書いた後に、Wikipedia.enで矩形波の記事を見たらfloorでも定義できるよって書いてありました。そこで記事で紹介されていたfloorを使う手法を基に、振幅 a = 1 or -1 の矩形波を周波数fで時刻tに対する応答として得るサンプルコードを書いてみました。


C++で矩形波の生成器を実装するならこれが一番美しいかな?

0 件のコメント:

コメントを投稿