what is the most efficient way to round `Double` ...
# getting-started
d
what is the most efficient way to round
Double
up to certain decimal points, there is
round()
function in Kotlin but it always completely rounds up to 0 decimals? I want something like
round(1.4999,decimalPrecision = 2) // 1.50
j
If your goal is just to print such a rounded value, I would go for
"%.02f".format(1.49999)
d
I need it to be dynamic , I have given 2 decimal places just as an example
j
Still, you can put a dynamic value in the format string:
Copy code
val decimalPrecision = 2
val doubleFormat = "%.0${decimalPrecision}f"
println(doubleFormat.format(1.4999))
The question is whether you need the rounded value or just a formatted representation of it
For printing you could also use Java's
DecimalFormat
(if you're on the JVM).
d
As suggested, I created this function
Copy code
fun Double.round(decimalPrecision: Int): Double {
    return "%.0${decimalPrecision}f".format(this).toDouble()
}
but
65312.49999999.round(0)
is producing
65312.0
when it should give
63513.0
j
Why do you think it should be
63513.0
? I guess it should actually be
"65312"
d
1 decimal gives
65312.5
so rounding
65312.5
one more time should give
65313
, right?
j
That is not how rounding works AFAIK, you round the actual number, not the already rounded number to another precision
But anyway, I just realized you're converting to Double again! I specifically said that this was if you wanted to format for printing not to use the rounded value as double
1
☝️ 1
If you want this kind of precision with floating point values and make calculations like that with them, I suggest you use
BigDecimal
instead
d
ok sure, I'll have a look
Thanks a lot for your time
@Joffrey sorry to disturb again I modified by function like this
Copy code
fun Double.round(decimalPrecision: Int): Double {
    return BigDecimal(this.toString())
        .setScale(decimalPrecision, RoundingMode.HALF_UP)
        .toDouble()
}
but it's still giving me
1
for
1.4999
Note: I have used that BigDecimal constructor because of this SO answer and I'm infact handling currency
In general talking about Math, is the round of
1.4999
2
, or not? I'm doubting my basic education now 😂
j
"Rounding" is imprecise terminology, but in the most common meaning of it, 1.499 is supposed to give 1 😄 there is no tie here, it's strictly less than 1.5. Now in Java, common rounding modes starting with
HALF_
are exactly about dealing with ties (e.g. when it's exactly 1.5), but it's not the case here. You could of course set the rounding mode to
UP
but in that case even 1.0001 will be rounded to 2.
Note: I have used that BigDecimal constructor because of this SO answer and I'm infact handling currency
@Danish Ansari It seems you have misunderstood the point of this answer, and my point as well. The problem is not about the constructor of
BigDecimal
itself, it's about using
double
anywhere in the code. If you use doubles, their representation in memory will fail you. So if you pass a
double
to this function, you have already lost. You need to start from
BigDecimal
right away, or from strings. Converting
this
double value to string before passing to the constructor is unnecessary because it's too late, if any error should happen with
double
it has already happened.
👍 1
1
d
ok @Joffrey, got it
e
if you are rounding doubles for some reason (because as mentioned earlier, for most things like output there are better solutions) just apply scale yourself
Copy code
fun round(x: Double, decimalPrecision: Int): Double {
    val scale = 10.0.pow(decimalPrecision)
    return round(x * scale) / scale
}
👍 2
c
Do not use doubles or floats or anything like that for currency. Never.
☝️ 2
j
@CLOVIS I guess the message is clearer this way than in my last message 😄
d
But.. but... There is no
Cursor#getBigDecimal()
in Android SDK only
getDouble()
😅 And I am getting data from the local DB
c
What I've seen done is use an Int or Long to represent the amount in cents, and then divide by 100 right when displaying to the user (because Int and Long don't have rounding errors on operations)
2
Of course that only works if you're not expecting crazy high amounts, but that should be the case most of the time.
It's also very easy to work with 😅 all APIs you could think of support Int and Long, and they're multiplatform! 🙃
d
That would require a huge huge rework for the system 😅
c
I don't want to be rude, but that's necessary. If you do anything even half serious with currency, you're going to have huge issues if you keep floats. Please read https://en.m.wikipedia.org/wiki/Floating-point_arithmetic#Accuracy_problems
👌 1
For example, your current system cannot deal with $0.10 (or whatever your currency is).
Although the given cases for π etc are probably not a concern for you, the examples will addition will definitely be.
e
feel free to make your own value class representing fixes point decimals, or BigDecimal if you don't mind the hit. but 100% do not use floating point. https://husobee.github.io/money/float/2016/09/23/never-use-floats-for-currency.html
457 Views