How do you round a number to N decimal places

So I saw this post about my problem(Print floats with certain amount of decimal numbers)

And I was wondering I it possible to use a methood or something else rather “%.2f”.format(value) in order to achive the same thing

2 Likes

You should explain better you problem.

Technically you cannot round the IEEE 754 floating point 0.1 to the first decimal point.

However you can use

fun Double.round(decimals: Int): Double {
    var multiplier = 1.0
    repeat(decimals) { multiplier *= 10 }
    return round(this * multiplier) / multiplier
}
7 Likes

I’m just trying to short the number to lets say 2 decimal places.

for example I want to turn:
pi=3.14159265359
to just
pi=3.14

I hope you can understand me know, or at least more clear to understand.

1 Like

If you want to round a double value to specific decimal places and print it, you can use java.math.BigDecimal.

import java.math.BigDecimal
import java.math.RoundingMode
val decimal = BigDecimal(3.14159265359).setScale(2, RoundingMode.HALF_EVEN)
println(decimal) // 3.14

Or if you just want to compare it with the rounded value, you can use round method.

import kotlin.math.round
println(round(3.14159265359 * 100) / 100 == 3.14) // true

You can do same thing with @fvasco’s extension method.

3.14159265359.round(2) // 3.14
3 Likes

On this * multiplier it shows:

Required: Int, Found: Double

Please consider to import round(Double) from kotlin.math.round

2 Likes

fun Double.round(decimals: Int = 2): Double = "%.${decimals}f".format(this).toDouble()

3 Likes

You need to realize that there is a difference between rounding for output, which you can do with String.format and other methods and having a value that exactly equals 3.14. If you use the double type you will NEVER, EVER have a value that exactly equals 3.14. Even if you have a statement like:

val a = 3.14

The variable a does not actually equal the value 3.14 exactly. It actually equals 3.140000000000000124344978758017532527446746826171875 [Edit: I originally said 3.1400001049041748046875 which is the exact value of the float value 3.14f].

If you want a value that exactly equals 3.14 the ONLY way to get it (for the JVM) is with BigDecimal.

3 Likes

That would be maybe the case with floats (I didn’t checked this), but doubles are much more precise. But of course it won’t be exactly 3.14 either.

It is the same for both float and double that neither can exactly represent 3.14. But I did accidentally show the float representation not the double one. 3.14 as a double is exactly equal to 3.140000000000000124344978758017532527446746826171875.

The only difference between float and double is how close you can get to the number. Float and double can only represent values that are exactly equal to m * 2 ^ n, where m and n are taken from a subset of the set of integers. The difference between float and double is merely how many bits are allocated for m and n and thus how precise you can be.

Try as hard as you want you will not find any integer values for m and n that give you exactly 3.14.

BigDecimal on the other hand represents numbers of the form m * 10 ^ n where m and n are integers and are essentially unbounded. m=314 and n=-2 give you the exact value of 3.14.

This is why the best advice when representing money is never use float or double and always use BigDecimal. You can get away with int or long to represent number of pennies as long as you know that the range is limited. See Java Practices->Representing money

The downside of BigDecimal is that it is slower and more cumbersome to use (less so in Kotlin) as there isn’t built in hardware support for it.

Hi;
How do you get that exact value of 3.14, I tried to get it as follow:

val pi = 3.14
println(pi) // I got: 3.14

Why?

For converting numbers to text, I would recommend using java.text.NumberFormat for JVM and Intl.NumberFormat for JS

Those will additionally handle localization for decimal and thousands separators.

The string representation of floating point values in many languages is truncated like that. Even if the value is not exactly 3.14, the output can look like that. This does not mean that it is essentially equal to 3.14. When using the value in computations the exact value is used.

1 Like

Basically when converting for output Java (which then carries over to Kotlin) will output the shortest string representation that is closer to the exact value than it is to the next representable floating point value. That way if you tried to parse that string representation you will get the same exact value.

The literal 3.14 is converted to a double that has the exact value of 3.140000000000000124344978758017532527446746826171875.

The representable double values on either side of this value are:
3.13999999999999968025576890795491635799407958984375
and
3.1400000000000005684341886080801486968994140625

When converting the value to string it outputs 3.14 because that is the shortest representation that is closest to that exact value than it is to either of these 2 surrounding values.

The fact that it prints 3.14 does not mean that 3.14 is its exact value. Note that this code also prints 3.14:

val pi = 3.140000000000000124344978758017532527446746826171875
println(pi)

There are in fact an infinite number of text number representations you can put in that code and still get 3.14 out (for example any digits you append to this will not change anything).

FYI, if you want to see what the exact value is, convert it to BigDecimal:

println(BigDecimal(pi))
2 Likes

Take a look for this method, in my case it works:

fun Double.roundTo(numFractionDigits: Int): Double {
  val factor = 10.0.pow(numFractionDigits.toDouble())
  return (this * factor).roundToInt() / factor
}

i borrow this from: java - Round Double to 1 decimal place kotlin: from 0.044999 to 0.1 - Stack Overflow

1 Like

That may return the nearest Double value to the decimal number you want. But it still won’t be exactly that number (because, except in a few special cases, no Double value is exactly that number).

If you care about exact decimals, don’t use a binary floating-point type like Double; use something like BigDecimal instead.

Thank you! Helped me a lot.

This is a cursed JavaScript approach. Please just use the one from @fvasco

also we can write a bit more complex fun to do that:

infix fun<T : Number> T.roundTo(decimals: Int) : Double{ return pow(10.0, decimals.toDouble()).run{ round(this@roundTo.toDouble() * this) / this } }