端数処理
「丸め」と「四捨五入」はよく混同される。
というか混同していた。
厳密には、「丸め」は丸め単位(10進であるとは限らないわけだ)の中間点の場合は偶数にすること*1。
四捨五入
1.5=>2
2.5=>3
丸め
1.5=>2
2.5=>2
ROUNDは直訳すれば「丸め」なのだが、関数になるとなぜか「四捨五入」になる。
OracleとJavaのROUND関数は実際は「四捨五入」だ。
SQL> select round(1.5) from dual; ROUND(1.5) ---------- 2 SQL> select round(2.5) from dual; ROUND(2.5) ---------- 3
System.out.println("Math.round(1.5)="+Math.round(1.5)); System.out.println("Math.round(2.5)="+Math.round(2.5));
実行結果
Math.round(1.5)=2 Math.round(2.5)=3
Javaで「丸め」が必要な場合はjava.lang.Math#rint()やjava.math.BigDecimalを使用する*2
MathContext mc = new MathContext(1, RoundingMode.valueOf("HALF_EVEN")); System.out.println("BigDecimal(1.5)="+new BigDecimal(1.5, mc)); System.out.println("BigDecimal(2.5)="+new BigDecimal(2.5, mc)); System.out.println("Math.rint(1.5)="+Math.rint(1.5)); System.out.println("Math.rint(2.5)="+Math.rint(2.5));
実行結果
BigDecimal(1.5)=2 BigDecimal(2.5)=2 Math.rint(1.5)=2.0 Math.rint(2.5)=2.0
ざっと調べてみると、AccessやVBではROUND()は「丸め」をしてくれるらしい。
でもExcelでは「四捨五入」みたいだなぁ。
ROUND関数が「丸め」の場合に「四捨五入」にするのはこんな感じらしい*3。
Round() がこういう挙動をする言語で四捨五入を実現する方法も常套手段があって、
1)四捨五入したい位が1の位になるよう、(10のn乗)をかける。
2)四捨五入したい値が正の数だったら 0.5 を足す。負の数だったら 0.5 を引く。
3)小数点以下を切り捨てる(Int関数やFloor関数など)
4)1)で使った数字の逆数をかける。(桁数を元に戻す)
という処理です。(キャストや変数の型による精度も要注意)
例えば、java.lang.Math#round(double a)の説明にはこう記述してある。
引数にもっとも近い long を返します。結果は 1/2 を加えて floor メソッドで取り int にキャストして整数に丸められます。すなわち、結果は次の式の値になります。
(long)Math.floor(a + 0.5d)
1円の誤差でも100万回繰り返せば100万円だし、お金の絡むところでは注意しておかないとな。
*1:http://ja.wikipedia.org/wiki/Round%E9%96%A2%E6%95%B0
*2:java.math.BigDecimal#round()もあるが、コンストラクタでも丸め処理ができるらしい