2013年10月8日火曜日

浮動小数点の罠:「a==b」を「fabs(a-b)<E」に書き換えるは間違い。</pp>



a==bで比較してはいけない理由は計算精度都合で「1/10*10 != 1/2*2」となる場合があるからです。



その対策として、微小値E(doulbeだと約1E-15,float 1E-7ぐらい)を使って、


「fabs(a-b)<E」と実装しなおしている人が多いかと思います。



(サラリーマンとしてコード書いていると、a==bってコードは機械的に禁止されてる。)


多くの場合は上のやり方で動くんです。でも以下の例を見て下さい。



fabs( (a-b)*1.0E+100) <E



実はこないだ、ぼーっとコードを書いていてやってしまったんですがこいつは正しく動かない可能性が高いです。だって1.E-15*1.0E+100=1.0E+85ですから。


私の場合は、数学的にはf(x)<g(x)をやりたくてf(x)-g(x)<Eと書いていました。そして同じ問題にぶつかりました。



実際にはf(x)もしくはg(x)のオーダに合わせてEを定数倍する必要があるんですね。


さらに、浮動小数点を「==」だけじゃなく「<」でも考えなきゃいけないんです。



ただ、厄介なのはオーダってどないして調べようという話があります。例えば「a-b == c-d」においてEの定数倍を考える時必要なオーダはaやbのオーダであってa-bのオーダではない。という問題があります。


この問題は、大きな値同士を引き算(or足し算)した結果が元のオーダより小さくなる場合(桁落ち)の時に起きます。


かけ算しかないような場所なら桁落ちの心配はいらないので、単純に以下の様にしてOKです。



fabs(a-b)<E*max(fabs(a),fabs(b))



ここで、再び桁落ちについて考えます。計算途中に桁落ちでおちる桁数をdとすると以下の数式のようにも解釈できます。



fabs(a-b)<E*1.0E+[桁落ちした桁数] *max(fabs(a),fabs(b))


桁落ちした分だけ誤差範囲Eを定数倍して、さらに比較対象のオーダにあわせてEを定数倍する。



上の様に浮動小数点の比較(==だけじゃなく<も)ってのは計算を追わないと解らない根が深い問題なんです。世の中のコーディング規約(MISRA-C) なんかではさくっと無視されたりする問題だけど、すっごい希に見つかるので謎のバグとして頭なやます事になります。気をつけてね。














書いていて自信がなくなったぞ、、、いつもは深い事考えずにEは許される精度の範囲でできるだけ大きくとって逃げてるので。。。orz。だれか詳しい人まともな解説お願い。





2013年10月6日日曜日

上限・下限制限つき最小二乗を実装した



最小二乗といってもy=ax+bに近似するタイプではないです。


ベクトルA1,A2,A3・・・を適当な比率x1,x2,x3,・・・で足し合わせて、入力されたベクトルBを近似しようというものです。



B≒x1*A1 + x2*A2 +x3*A3



このときにx1~x3が取り得る範囲をそれぞれ制限してあげようというのがこのアルゴリズムです。





論文とかあたってると、飛行機だとか自動車の制御等で、ラダーや各タイヤの出力を制限範囲内で最適に配分するってのに使われてるらしいんですが・・・・制御系の人間じゃないので、興味わかず。


純粋に音声などの信号の解析に使えるかな~と思って作りました。


音声はMFCC等の20次元ぐらいのベクトルで表す事ができて、それが時系列で変化していきます。でコレが「あ」とか判断するのが普通なんですが、「あ」と「い」の中間って普通に考えるとあるわけじゃないですか。だから、「あ」20%+「い」80%とかも有り得るのかなと。


これで制限なしの最小二乗で解いちゃうと「あ」1000%+「い」-9900%とかとんちんかんな事言い出したりするんですね。これだけなら非負という制限かければいいんですが、前後の関係から「あ」は20±20%、「い」は80±20%ぐらいだな~ってあたりが付いてることもあるんですね。そんなときに上限・下限制限つきの最小二乗が必要になっちゃうんです。


ちなみにMatlabには搭載されてるらしいです。C++の実装がみつかんなかったので、実装してみました。





このアルゴリズムは以下の論文の内容を実装したものです。


http://www.nt.ntnu.no/users/skoge/prost/proceedings/acc08/data/papers/0854.pdf


ソースはこちら。(行列ライブラリとして「Eigen」使ってます、別途DLしてください。)


https://drive.google.com/folderview?id=0B2MvWvAFndBdNG9YY0tOenRZejQ&usp=sharing





2013年10月4日金曜日

道具に拘るエンジニアは無能なのか?



道具に拘るエンジニアはだいたい無能だという主張があるらしい。


引用:http://anond.hatelabo.jp/20131005004542


しかしながら本文中にもあるように、深く考えるために、落ち着く「環境」は大切だと思う。



出来るエンジニアが最も求めるのは、深く考える事が出来る環境と、


周到な議論を繰り返せる優れた同僚に他ならない。



環境というと、静けさだとか暑さ・寒さとかだけを指す言葉のような気がするけれども、目的は「深く考える」ためで、私の場合はそれは「落ち着く」事でなんです。そのための「環境」が必要。その上で、その「環境」に「道具」が含まれるか否かだけでの話にすぎないだけだと思う。


ちなみに多くの工学部の人は、自分の研究とかに対して「何故その手法を用いたのですか?」という質問をすると、最初は理性的な答え(速度が速いから等)を返してくる。その答えに対してさらに、何故その答えなのか?と細かく突き詰めていくと、結構な頻度で「xxでもできるのですが、ooの方が美しいからです」という答えが出たりする。多くの場合、これはコンセンサスを得られる答えではない。しかしながら、これは責められる事ではなくて、大切な個性、所謂その人のセンスだと思う。


表面上は理論武装してても、一皮一皮丁寧に向いていけば、「好きだから」「美しいから」といった本能むき出しな価値観で仕事に取り組む。それが工学系の実態だし、だからこそ多様性のある技術進化の模索ができると信じてる。


だから、大まじめには他人の道具(環境)にケチ付けないほうがいいと思うんだ。emacs派とvi派は犬猿の仲に見えて同じ穴の狢なのです。もちろん、気の知れた中でお互いの道具の自慢(≒ケチの付け合い)をするのは楽しいってのはわかりますよ。えぇ。


ちなみに私の場合


私は信号処理のソフト開発がメインなので、引用元が言っているエンジニアに近い仕事だと思う。


そんな私の落ち着く環境は思いつく限り以下のようなもの。




  • OS:FreeBSD メモリを使い過ぎた時も、ディスク溢れさせた時もそっと動いてくれる頼もしい存在。

  • エディタ:emacs ぶっちゃけオートインデントが付いていればどんなエディタでも良いと思いながら、手に馴染んでるのはコレしかない。

  • グラフ描画:gnuplot 100ぐらいの大きさの信号中の0.1ぐらいの変動を目視で見たい!って感じなので、拡大縮小が気持ちよく動く事は個人的に大切。一度だけソース覗いた事あるけど、データ入力・保持周りを頑張ればもうちょっと描画速度あげれるよね・・・・という不満はあるんだけどね。

  • キーボード: Realfoce 89 フルサイズのキーボードはマウスが遠いのが気になる。

  • ボールペン:インクどばどばでちゃう感じのをサラサラインク系のボールペン

  • 紙:薄いノートorプリンタからパクってきた紙。基本殴り書きでグラフ書いてる時間が長い。分厚いノートは苦手。偶に数式解くけど、Maxima(数式処理ソフト)に出来るだけやるようにしてる。

  • 音楽:コーディング中等アウトプット作業中は音楽があると集中できる、論文読んだりのインプット作業中は音楽なしが集中できる。考え中はどっちでも。自分でも不思議なぐらい作業によって効用が違う。