#java #kotlin #format #bigdecimal #decimalformat
#java #kotlin #формат #bigdecimal #десятичный формат
Вопрос:
Я попытался поискать, но у меня возникли проблемы с поиском полного решения этой проблемы: я хочу отформатировать an Int
так, чтобы общее количество цифр всегда было 3. Несколько примеров:
1000000 -> 1,00m
678945 -> 678k
65432 -> 65,4k
5437 -> 5,43k
числа никогда не должны быть меньше 1000 или больше 1 миллиарда, поэтому другие случаи не имеют большого значения
это самое близкое, к чему я пришел:
@JvmStatic
fun formatPointsTop3(points: Int?): String {
if (points == null) return ""
val formatter = NumberFormat.getInstance(Locale.ITALIAN)
val mathContext = MathContext(3, RoundingMode.DOWN)
return when {
points < 1000 -> {
"$points"
}
points < 1000000 -> {
val bigDecimal = BigDecimal(points / 1000.0, mathContext)
"${formatter.format(bigDecimal)}k"
}
else -> {
val bigDecimal = BigDecimal(points / 1000000.0, mathContext)
"${formatter.format(bigDecimal)}m"
}
}
}
это работает нормально для большинства случаев, за исключением 1000000, который выводит 1 м (я хочу 1,00м). Добавление formatter.minimumFractionDigits = 2
добавляет десятичные дроби ко всем числам.
Есть ли способ добиться этого, не делая странных вещей непосредственно в строке?
Ответ №1:
Должно быть. Во-первых, выясните, как вы хотите его отобразить, что, похоже, у вас другое представление о том, как именно per log(n) (например, в зависимости от количества цифр во входных данных). Для 7 цифр вы хотите отобразить значение, разделенное на миллион, с 2 дробными цифрами. Для 8 цифр требуется значение div million с 1 дробью и т.д. Это будет много кода, возможно, манипулирование строками проще.
Ответ №2:
В итоге я сделал это:
fun formatPointsTop3(points: Int?): String {
if (points == null) return ""
if (points == 0) return "0"
val maxNumberOfDigits = 3
val multiplierExponent = log(points.toDouble(), 1000.0).toInt()
val bigPoints = BigDecimal(points)
val bigDivider = BigDecimal(1000).pow(multiplierExponent)
val reducedPoints = bigPoints.divide(bigDivider)
val intPart = reducedPoints.toBigInteger().toInt()
val decimalPart = reducedPoints.subtract(BigDecimal(intPart)).toDouble()
val numberOfDecimals = maxNumberOfDigits - (log10(intPart.toDouble()).toInt() 1)
var formattedString = "$intPart"
if (numberOfDecimals > 0) {
val multiplier = 10.0.pow(numberOfDecimals)
val formatter = NumberFormat.getIntegerInstance()
formatter.minimumIntegerDigits = numberOfDecimals
formatter.maximumIntegerDigits = numberOfDecimals
val multiplied = (decimalPart * multiplier).toInt()
formattedString = ",${formatter.format(multiplied)}"
}
formattedString = when (multiplierExponent) {
0 -> ""
1 -> "k"
2 -> "m"
3 -> "b"
else -> "" //this is not possible as max int is 2 billions
}
return formattedString
}
это довольно некрасиво, но выглядит лучше, чем манипулирование строками, imo