Finally I did what Andy Turner suggested, rounded to 3 decimals, then to 2 and then to 1:
Answer 1:
val number:Double = 0.0449999
val number3digits:Double = String.format("%.3f", number).toDouble()
val number2digits:Double = String.format("%.2f", number3digits).toDouble()
val solution:Double = String.format("%.1f", number2digits).toDouble()
Answer 2:
val number:Double = 0.0449999
val number3digits:Double = Math.round(number * 1000.0) / 1000.0
val number2digits:Double = Math.round(number3digits * 100.0) / 100.0
val solution:Double = Math.round(number2digits * 10.0) / 10.0
Result:
0.045 → 0.05 → 0.1
Note: I know it is not how it should work but sometimes you need to round up taking into account all decimals for some special cases so maybe someone finds this useful.
Answer from Noelia on Stack Overflowjava - Round Double to 1 decimal place kotlin: from 0.044999 to 0.1 - Stack Overflow
android - how to round a number in kotlin - Stack Overflow
How do you round a number to N decimal places - Support - Kotlin Discussions
Strange behavior of kotlin.math.round
Yeah, it can seem poorly named coming from Java. It is using Math.rint. If you want Math.round, you have to use roundToInt or roundToLong (except Kotlin, unlike the JVM lib, will error on NaN).
Finally I did what Andy Turner suggested, rounded to 3 decimals, then to 2 and then to 1:
Answer 1:
val number:Double = 0.0449999
val number3digits:Double = String.format("%.3f", number).toDouble()
val number2digits:Double = String.format("%.2f", number3digits).toDouble()
val solution:Double = String.format("%.1f", number2digits).toDouble()
Answer 2:
val number:Double = 0.0449999
val number3digits:Double = Math.round(number * 1000.0) / 1000.0
val number2digits:Double = Math.round(number3digits * 100.0) / 100.0
val solution:Double = Math.round(number2digits * 10.0) / 10.0
Result:
0.045 → 0.05 → 0.1
Note: I know it is not how it should work but sometimes you need to round up taking into account all decimals for some special cases so maybe someone finds this useful.
I know some of the above solutions work perfectly but I want to add another solution that uses ceil and floor concept, which I think is optimized for all the cases.
If you want the highest value of the 2 digits after decimal use below code.
import java.math.BigDecimal
import java.math.RoundingMode
import java.text.DecimalFormat
here, 1.45678 = 1.46
fun roundOffDecimal(number: Double): Double? {
val df = DecimalFormat("#.##")
df.roundingMode = RoundingMode.CEILING
return df.format(number).toDouble()
}
If you want the lowest value of the 2 digits after decimal use below code.
here, 1.45678 = 1.45
fun roundOffDecimal(number: Double): Double? {
val df = DecimalFormat("#.##")
df.roundingMode = RoundingMode.FLOOR
return df.format(number).toDouble()
}
Here a list of all available flags: CEILING, DOWN, FLOOR, HALF_DOWN, HALF_EVEN, HALF_UP, UNNECESSARY, UP
The detailed information is given in docs
Due to floating-point inaccuracies, 36.295f is not exactly 36.295 but rather something like 36.294998. This is the explanation for the output you received.
I believe your best option is to increase the precision in the input to start with. Use double-precision floating point i.e. lose the f for single-precision floating point.
DecimalFormat by itself cannot add precision to imprecise numbers. For example, The RoundingMode.CEILING approach offered in another answer would e.g. round 36.294 to 36.3 which might not be what you wanted.
Use this example to show you how to round:
import java.math.RoundingMode
import java.text.DecimalFormat
fun main(args: Array<String>) {
val value = 36.295f
val df = DecimalFormat("#.##")
df.roundingMode = RoundingMode.CEILING
println(df.format(value))
}
Output:
36.30
So for your code you can use:
df.format(value) as your value
Check this link for more details: Link.
kotlin.math.round(3.5) evaluates to 4.0
kotlin.math.round(4.5) evaluates to 4.0
The docs say: Rounds the given value x towards the closest integer with ties rounded towards even integer.
So I guess it is deliberate but this is surprising to me, and not consistent with java.lang.Math.round.
Yeah, it can seem poorly named coming from Java. It is using Math.rint. If you want Math.round, you have to use roundToInt or roundToLong (except Kotlin, unlike the JVM lib, will error on NaN).
That sounds like standard Gaussian (Banker's) rounding. In school, I was taught to round .5 upward (actually, away from zero, so that 3.5 would round to 4 and -3.5 would round to -4), also sometimes called 'commercial rounding'. My dad, a high-school drop-out, pointed out that if this produced a bias away from zero and showed me that Gaussian had no bias. (Actually, there is still a bias, but it's a different bias and smaller.) As a new Kotlin user, I'm glad to see that it uses this technique. I never had much luck getting away with Gaussian rounding in school and had all but forgotten it until I noticed that C# (or was it VB?) was doing the same thing you found in Kotlin. There are some interesting articles on rounding on Wikipedia.