1. Overview
In our daily work, we often encounter scenarios where we need to perform precise arithmetic operations on numeric data.
In this quick tutorial, we’ll explore dividing two Int objects and obtaining a BigDecimal result, ensuring precise calculations in our Kotlin code.
2. Introduction to the Problem
While dividing two integer objects might seem straightforward, it can lead to unexpected results if we don’t properly deal with the division operation. Let’s see an example:
val result = BigDecimal(21 / 42)
assertTrue { result compareTo BigDecimal.ZERO == 0 }
In the example above, we want to calculate 21 / 42 and get the result as a BigDecimal. Apparently, we’re expecting the result to be 0.5.
However, as the assertion shows, the result is 0 instead of 0.5.
In this tutorial, we’ll understand why this method produces the unexpected result. Of course, we’ll explore different approaches to get the correct result.
For simplicity, we’ll use unit test assertions to verify whether each approach can produce the expected result.
As we’re mentioning BigDecimal assertions, it’s worth noting that we should use compareTo() to only compare two BigDecimal values and ignore their scales.
Next, let’s understand why BigDecimal(21 / 42) produces 0.
3. Why BigDecimal(21/42) Produces 0?
Given the expression BigDecimal(21/42), first, Kotlin calculates 21/42 and then passes the result to the BigDecimal constructor to create a BigDecimal object.
We know that both 21 and 42 are Int objects. When we divide two Int objects in Kotlin, the result is automatically truncated to an integer value.
This behavior can lead to inaccuracies when dealing with fractions, as any decimal portion of the result is discarded. Therefore, the result of 21/42 is the integer 0. Then, it’s not surprising why BigDecimal(0) returns 0.
Now that we understand the cause of the problem, let’s see how to get the expected result.
4. Converting an Int to Double
One solution is to convert one Int to Double. This is because no matter (Double / Int) or (Int / Double), the result is a Double.
Then, we can pass the Double result to the BigDecimal constructor to get the expected value:
val result1 = BigDecimal(21.toDouble() / 42)
assertTrue { result1 compareTo BigDecimal("0.5") == 0 }
val result2 = BigDecimal(21 / 42.toDouble())
assertTrue { result2 compareTo BigDecimal("0.5") == 0 }
5. Converting Int to BigDecimal
As we’d like to get a BigDecimal object as the final result, we can also *convert both Int objects to BigDecimals and then use BigDecimal‘s divide() function to perform the division operation*:
val result1 = 21.toBigDecimal().divide(42.toBigDecimal())
assertTrue { result1 compareTo BigDecimal("0.5") == 0 }
So, we’ve used the convenient Int.toBigDecimal() function to convert Int to BigDecimal and got the expected result.
There are other ways to convert Int to BigDecimal, for example, calling the BigDecimal.valueOf() function or using the BigDecimal() constructor:
val result2 = BigDecimal.valueOf(21).divide(BigDecimal.valueOf(42))
assertTrue { result2 compareTo BigDecimal("0.5") == 0 }
val result3 = BigDecimal(21).divide(BigDecimal(42))
assertTrue { result3 compareTo BigDecimal("0.5") == 0 }
All these ways are pretty straightforward. But which conversion approach is better?
First, let’s look at the constructor and the valueOf() function. When we convert an Int or Long to BigDecimal, we should use BigDecimal.valueOf() over the constructor. This is because the BigDecimal class caches zero to ten values. When the integer equals one of the cached values, the valueOf() function returns the cached instance immediately. On the other hand, the BigDecimal() constructor always creates a new instance without using the cache.
Then, let’s compare BigDecimal.valueOf() and Int.toBigDecimal().
valueOf() is a Java static method, and toBigDecimal() is an Kotlin extension function, which uses the valueOf() method internally:
public inline fun Int.toBigDecimal(): BigDecimal = BigDecimal.valueOf(this.toLong())
So, basically, they’re the same. But, when writing the function call, the extension function feels more fluent and natural than the valueOf() Java static method. And it’s easier to read too.
Therefore, we recommend using the toBigDecimal() function from both readability and performance points of view.
6. Conclusion
In this article, we’ve explored two approaches of dividing two integers and obtaining a BigDecimal with the decimal portion as the result:
- Converting one Int to Double
- Converting both Ints to BigDecimal
As usual, all code snippets presented here are available over on GitHub.