はじめに
Kotlinでは数値を四捨五入する場合、roundToInt
やroundToLong
を使用します。ただし、負の値を四捨五入する際には1点注意が必要です。この記事では、KotlinのroundToInt
を用いてどのような挙動になるのかを詳しく解説します。
まず結論
いきなり結論からの共有です。roundTo〇〇
は負の数(-X.5)に対して以下の結果になってしまう可能性があります。
a. (-7.5).roundToInt()
とコーディングの場合
値がマイナスの記号を含めてそのまま評価され、-7.5
を一番近い切り上げられた整数(-7
)を返します
b. -7.5.roundToInt()
とコーディングの場合
マイナスの記号は一旦考慮されず7.5
を評価し、四捨五入して8
とした後、マイナス記号が後から適用され、結果として-8
を返します
c. val num = -7.5 と変数に格納して、変数に対してroundToInt()
を呼び出した場合
こちらもaのケースと同様に、値がマイナスの記号を含めてそのまま評価されるため整数(-7
)を返します
KotlinでのroundTo〇〇
まずここではKotlinのroundToInt
のソースコードがなっているかを覗いてみましょう!
public actual fun Double.roundToInt(): Int = when {
isNaN() -> throw IllegalArgumentException("Cannot round NaN value.")
this > Int.MAX_VALUE -> Int.MAX_VALUE
this < Int.MIN_VALUE -> Int.MIN_VALUE
else -> nativeMath.round(this).toInt()// Int範囲内の数値であればここに入る
}
KotlinのInt範囲内に収まっているDoubleで数字であれば、thisで自身の値を更に次のround関数に引数として渡し、Int型に変換して返しているのが分かります。また、round関数内ではビットワイズのシフト演算を使用して四捨五入の計算が行われていました。
検証してみよう
それは実際にこの関数を使用して、期待する四捨五入の結果を得られるのかを検証してみましょう。
➕正数に対しての四捨五入
val case1 = 3.14.roundToInt()// 3
val case2 = 5.7.roundToInt()// 6
val case3 = 8.5.roundToInt()// 9
上記コードのように、小数点部分が0.5以上であれば値の切り上げ、0.5より小さい場合は切り下げがされているのを確認できると思います。
では続けてそれぞれをマイナス値にした場合はどうなるのか確認してみましょう。
➖負数に対しての四捨五入
val case1 = -3.14.roundToInt()// -3
val case2 = -5.7.roundToInt()// -6
val case3 = -8.5.roundToInt()// -9
正数の結果にそのままマイナスが付くような結果になりましたね。ではそれぞれに括弧をつけるとどうなるでしょう?
val case1 = (-3.14).roundToInt()// -3
val case2 = (-5.7).roundToInt()// -6
val case3 = (-8.5).roundToInt()// -8
case1とcase2は同じ結果ですが、case3は-9
ではなく-8
になっているのが確認できます。
上記は変数に値を格納した場合でも同じ結果になります。
val num = -8.5
val case1 = num.roundToInt()// -8
なぜこのような挙動になるのか?
ここでは括弧ありと無しで、値の評価にどんな違いがあるのかを説明します。
下記例になります。
a. (-8.5).roundToInt()
- 丸括弧を用いることで、
-8.5
全体が計算の対象になります - 小数点が0.5であるため
-8.5
より大きい整数である-8
に切り上げとなります - 結果、
-8.5
は-8
に丸められます
b. -8.5.roundToInt()
- この場合、まず
8.5
の絶対値部分に対してroundToInt
が実行されます-
8.5
は9
に丸められる
-
- roundの処理によって返却された値の先頭に
-
が適用され、結果は-9
になります
実際のコード例
以下のコードで実際の挙動を確認できます:
fun main() {
val case1 = (-7.5).roundToInt()
val case2 = -7.5.roundToInt()
println("(-7.5).roundToInt() の結果: $case1") // 結果: -7
println("-7.5.roundToInt() の結果: $case2") // 結果: -8
}