1. Introduction
In Kotlin, performing arithmetic operations is straightforward. However, when it comes to calculating percentages, developers may encounter unexpected results due to the nature of integer division.
This tutorial explores correctly calculating percentages in Kotlin, ensuring accurate results whether working with integers or floating-point numbers.
2. Understanding Integer Division in Kotlin
Kotlin, like many programming languages, differentiates between integer and floating-point division. When dividing two integers, the result is truncated to produce another integer. This behavior can lead to inaccuracies when calculating percentages:
val count = 5
val totalCount = 10
var result = count / totalCount
In the example above, count divided by totalCount evaluates to zero instead of 0.5, leading to an unexpected arithmetic calculation.
To achieve the expected fractional result, one or both operands must be converted to a floating-point type before performing the division:
var accurateResult = count.toDouble() / totalCount
This conversion ensures the division operation yields a floating-point result, preserving the expected accuracy.
3. Calculating Percentages Accurately
To calculate percentages accurately in Kotlin, it’s crucial to address the challenge created by integer division. Kotlin’s robust type system allows for seamless conversions between numeric types, ensuring that operations yield the expected results. The formula for calculating a percentage involves dividing the part by the whole and multiplying by 100.
Now, we’ll delve into the nuances of ensuring precise percentage calculations, showcasing the adaptability of Kotlin in handling such tasks with precision and clarity.
3.1. Converting to Floating Point for Consistent Results
For consistency and to avoid the quirks of integer division, it’s advisable to convert all numbers involved in the division to floating-point types:
var percentage = (count.toDouble() / totalCount.toDouble()) * 100.0
Let’s ensure this logic is correct with a simple test:
@Test
fun `should return accurate division result`() {
val count = 5
val totalCount = 10
val expected = 50.0
val result = (count.toDouble() / totalCount.toDouble()) * 100.0
assertEquals(expected, result)
}
This ensures our percentage calculations are based on accurate division results.
3.2. Extension Functions for Percentage Calculation
We can also create an extension function on the Number class to allow our function to accept any numeric type, providing flexibility and enhancing usability:
fun Number.divideToPercent(divideTo: Number): Double {
if (divideTo.toDouble() == 0.0) return 0.0
return (this.toDouble() / divideTo.toDouble()) * 100.0
}
Converting the result to an Int or a Long truncates the decimal part, so we return a Double instead.
To verify the correctness of our extension function divideToPercent(), we can write a JUnit test:
@Test
fun `when dividing 10 by 20, should return 50`() {
val result = 10.divideToPercent(20)
assertEquals(50.0, result)
}
This test checks that the divideToPercent() function correctly calculates 50% when 10 is divided by 20.
3.3. Infix Functions for Readability
Infix functions in Kotlin provide a way to call single-argument functions without requiring the parentheses. We can define an infix function for calculating percentages:
infix fun Number.percentOf(value: Number): Double {
return if (this.toDouble() == 0.0) 0.0
else (value.toDouble() / this.toDouble())
}
Subsequently, we can test our infix function to ensure its functionality:
@Test
fun `when using infix function, 10 percentOf 200 should return 20`() {
val result = 10 percentOf 200
assertEquals(20.0, result)
}
This test verifies that percentOf() accurately computes 10 percent of 200 as 20%.
3.4. Utilizing BigDecimal for Precision
Additionally, thanks to Kotlin’s Java interoperability, we can use BigDecimal for calculations requiring high precision:
fun BigDecimal.percentOf(total: BigDecimal): BigDecimal {
return if (total == BigDecimal.ZERO) BigDecimal.ZERO
else this.divide(total, 5, BigDecimal.ROUND_HALF_UP) * BigDecimal(100)
}
BigDecimal ensures precision in our percentage calculations, which is especially useful for financial applications. In this example, we’ll round to five decimal points of precision and follow natural mathematic rounding rules with ROUND_HALF_UP.
Let’s also write a unit test to verify this approach:
@Test
fun `calculate percentage using BigDecimal for high precision`() {
val part = BigDecimal("25")
val whole = BigDecimal("200")
val expectedPercentage = BigDecimal("12.50")
val resultPercentage = part.percentOf(whole)
assertTrue { resultPercentage.compareTo(expectedPercentage) == 0 }
}
4. Formatting Percentage Output
Finally, after calculating a percentage, formatting the output to indicate a percentage can enhance readability. Let’s define a formatting function, and then use one of our percent functions and print the result:
fun Number.formatPercent() = "$this%"
val percentage: Double = 10 percentOf 200
println(percentage.formatPercent())
This simple extension function appends a percent symbol to our percentage and will print “50.0%”, making it clear that the value represents a percentage.
5. Conclusion
Calculating percentages in Kotlin can lead to inaccuracies if not handled correctly due to integer division. We can ensure precise calculations by converting operands to floating-point numbers. Kotlin provides many ways to create readable ways to handle this calculation. Finally, we discussed how to format percentages to help convey intent when displaying the result.
As always, the code used in this article is available over on GitHub.