ちょっとベクトルを扱った計算を行っていたとき、おかしな動作をすることがあったので調べてみたら計算誤差によるものだった。
floatで計算をしていて、非常に小さい値になってしまっていた。
一応、FLT_EPSILONと比較して、0として扱うか判定していたのだが、0でないと判定したあと、その値を2乗する計算があって0になってしまっていた。
計算誤差は難しい。
たとえば、1フレームを秒で扱うとすると1/60だから0.0166667。これを60回足してもきっちり1にはならないわけで。
#include <iostream> using namespace std; int main() { float frame = 1.0f / 60.0f; cout << frame << endl; float second = 0.0f; for(int i=0; i<60; i++) { second += frame; } cout << second; if ( second == 1.0f ) { cout << "second is 1.0f" << endl; } } 実行結果 0.0166667 1
最後で1.0fと比較をしているが成立しない。まあ、そもそもfloatを等号で比較しようとすること自体が間違っているわけだが。
計算誤差を考慮したコードの書き方をきちんと勉強しないと。