2014年2月15日土曜日

absの罠

こないだ、@kumagiさんがJubatusのクラスタリングのテスト書いたらNaNになるというので、デバッグしてたらabsにハマってたという恐ろしいバグを発見したので書いておきます。

C++で絶対値を求める関数は3つあります。

  • ::abs Cの関数でintを引数に取る
  • ::fabs Cの関数でdoubleを引数に取る
  • std::abs C++の関数でint引数とdouble引数でオーバーロードされている

さて、大事なのは std::abs はオーバーロードされているので、doubleを渡すと::fabs相当の処理をしてくれる、ところが::absはCの関数なのでdoubleを渡してdoubleで結果を受け取ろうとすると、intにキャストして絶対値を計算してからdoubleに戻す、という恐ろしい挙動を示すことです。さて、std::absを呼んでるつもりで、absと書くとどうなるか。usingしていればもちろんstd::absになりますが、そうでない場合には::absになる可能性があります。すると、渡されたdobule値はintにキャストされて、華麗にオーバーフローして、もう残りは目も当てられません。 素直にfabsを使うか、absを使うときは必ずstd::absと面倒でも明示的に書くのがいいようです。不正確なabsという書き方はほんとうに怖いので、grep "[^:f]abs(" で簡単にチェックできるので、活用するのをおすすめします。

サンプルコード

0 件のコメント:

コメントを投稿