Cogito Ergo Sum.

我思う故に我あり

銀行型丸め

 Visual Basic 2008 Express Editionを使ってプログラミングしていて、些細なところで落とし穴にハマッた。CInt()の「銀行型丸め」というヤツだ(おそらくVisual Basic 2008だけでなく、Visual Studio 2008、Visual Studio 2010の他の言語(C++C#、F#、J++)を用いても同様だろうと思う。また、Javaもある種のクラスのメソッドでは「銀行型丸め」を行うようだ)。

 CInt()は、実数を引数にとり整数を返すメソッドだが、単に切り捨てた値を返すのではなく、四捨五入に近い処理をした整数を返す。この「四捨五入に近い処理」というのがヤッカイで、小数点以下が「.5」ピッタリだった場合、「最も近い偶数の整数」を返す。

 つまり、

CInt(-9.5) = -10
CInt(-8.5) = -8
CInt(-7.5) = -8
CInt(-6.5) = -6
CInt(-5.5) = -6
CInt(-4.5) = -4
CInt(-3.5) = -4
CInt(-2.5) = -2
CInt(-1.5) = -2
CInt(-0.5) = 0
CInt(0.5) = 0
CInt(1.5) = 2
CInt(2.5) = 2
CInt(3.5) = 4
CInt(4.5) = 4
CInt(5.5) = 6
CInt(6.5) = 6
CInt(7.5) = 8
CInt(8.5) = 8
CInt(9.5) = 10

 となる。

 ちなみに、CInt()する前にInt()で切捨てを行うことにより、小数点以下を切り捨てた整数を得ることができる…、と思ったら大間違い! 正の数はいいが、負の数は違う。

CInt(Int(-9.5)) = -10
CInt(Int(-8.5)) = -9
CInt(Int(-7.5)) = -8
CInt(Int(-6.5)) = -7
CInt(Int(-5.5)) = -6
CInt(Int(-4.5)) = -5
CInt(Int(-3.5)) = -4
CInt(Int(-2.5)) = -3
CInt(Int(-1.5)) = -2
CInt(Int(-0.5)) = -1
CInt(Int(0.5)) = 0
CInt(Int(1.5)) = 1
CInt(Int(2.5)) = 2
CInt(Int(3.5)) = 3
CInt(Int(4.5)) = 4
CInt(Int(5.5)) = 5
CInt(Int(6.5)) = 6
CInt(Int(7.5)) = 7
CInt(Int(8.5)) = 8
CInt(Int(9.5)) = 9

 そこで、Int()の代わりにFix()を使うと…、

CInt(Fix(-9.5)) = -9
CInt(Fix(-8.5)) = -8
CInt(Fix(-7.5)) = -7
CInt(Fix(-6.5)) = -6
CInt(Fix(-5.5)) = -5
CInt(Fix(-4.5)) = -4
CInt(Fix(-3.5)) = -3
CInt(Fix(-2.5)) = -2
CInt(Fix(-1.5)) = -1
CInt(Fix(-0.5)) = 0
CInt(Fix(0.5)) = 0
CInt(Fix(1.5)) = 1
CInt(Fix(2.5)) = 2
CInt(Fix(3.5)) = 3
CInt(Fix(4.5)) = 4
CInt(Fix(5.5)) = 5
CInt(Fix(6.5)) = 6
CInt(Fix(7.5)) = 7
CInt(Fix(8.5)) = 8
CInt(Fix(9.5)) = 9

 僕みたいな素人はこういうところでハマッちゃうんだよな。