C++11 最近接偶数への丸め

C++11では<cmath>にいろいろ関数が追加されていますが、丸め演算も増えています。

C++11で最近接偶数への丸めを使いたい場合は、std::nearbyint() (near by int)という関数がありますので、それを使いましょう。

#include <iostream>
#include <cmath>

int main()
{
    std::cout << std::nearbyint(2.5) << std::endl; // 2が出力される
}

四捨五入も最近接偶数への丸めも、どちらも大きなくくりでは「round to nearest integer (最も近い整数への丸め)」に該当します。この2つの丸め方式は、中間値(0.5)の場合に動作が異なります:

  • 四捨五入は中間値の場合に、ゼロから遠い方向に丸められる (2.5だったら3になる)
  • 最近接偶数への丸めは中間値の場合に、偶数方向に丸められる (2.5だったら2になる)

最近接偶数への丸めの必要性は、「「銀行家の丸め」とは何か - 会計SEのメモ」このあたりの記事がわかりやすいでしょう。

std::nearbyint()関数の実際の動作として、四捨五入になるか最近接偶数への丸めになるかは、ISO/IEC 60559 (IEEE 754)規格の推奨によって決まります。この規格ではround to nearestの丸め方式として最近接偶数への丸めを推奨しているため、この規格に準拠した環境では、std::nearbyint()関数は最近接偶数への丸めとして動作します。

補足として、

  • std::nearbyint()関数は、スレッドローカルな丸めモード状態に依存して丸め方式が変わるので注意
  • 似た動作の関数としてstd::rint()というものもあるが、丸めが発生したときに浮動小数点例外が発生するので使いにくそう。ISO/IEC 60559 (IEEE 754)規格で、std::nearbyint()関数とstd::rint()関数両方の動作が定義されているらしい

その他C++11での丸め方式

  • 昔からあるstd::ceil()std::floor()は切り上げ、切り下げと呼ばれるもので、より正確な動作の説明としては「正の無限大方向への丸め」「負の無限大方向への丸め」と言う
  • C++11から追加されたstd::trunc()は切り捨てだが、std::floor()と違って「ゼロ方向への丸め」というものになっている。この2つは、負の値に対する動作が違うので注意
  • C++11から追加されたstd::round()は四捨五入と決まっている。最近接偶数への丸めではないので注意