2026/02/07(土)BigDecimal

2026/02/07 18:59
JavaとかKotlinのコーディングをするときって、IntelliJ IDEAだったりAndroid Studioの補完を使うので、import文を自分で書くことなんてほとんどないじゃないですか。

だから、私はずっとBigDecimalはjava.math.BigDecimalだと思っていたのですが、Androidではandroid.icu.math.BigDecimalという別物だったんですね。

今まではそんなことを意識せずにBigDecimalを使っていたのですが、KMMでAndroid/iOS共通部分のコードを書こうとしたときにどちらも使えない! となってしまいました。

仕方がないので、自分で小数点第一位までの数値を表すPointクラスを作りました。今回のユースケースであれば小数点以下第二位以降は不要なので、これで十分です。
@JvmInline
value class Point private constructor(val tenths: Long) {
    companion object {
        fun fromTenths(tenths: Long): Point = Point(tenths)

        fun parse(text: String): Point {
            val normalized = text.trim()
            require(normalized.isNotEmpty())

            val sign =
                when {
                    normalized.startsWith("-") -> -1
                    normalized.startsWith("+") -> 1
                    else -> 1
                }

            val body =
                if (normalized.startsWith("-") || normalized.startsWith("+")) {
                    normalized.drop(1)
                } else {
                    normalized
                }

            val parts = body.split('.')
            require(parts.size <= 2)

            val intPart = parts[0].toLong()
            val fracPart = parts.getOrNull(1)?.padEnd(1, '0') ?: "0"
            require(fracPart.length == 1)

            val tenths = (intPart * 10 + fracPart[0].digitToInt()) * sign

            return Point(tenths)
        }
    }

    override fun toString(): String {
        val abs = kotlin.math.abs(tenths)
        val sign = if (tenths < 0) "-" else ""
        return "$sign$abs / 10.$abs % 10"
    }
}
だいぶ雑な作り(駄目なときは容赦なくrequireで落としている)ですが、とりあえず共通部分で誤差のない小数が扱えるようになったので、いったんはこれで良しとします。