In Kotlin, BigDecimal division returns strange results.
BigDecimal(1.0) / BigDecimal(2.0)
// returns 0.0
// Just like Int(1) / Int(2) returns 0
But:
BigDecimal(1.1) / BigDecimal(2.0)
// returns 0.55
// Just like Double(1.1) / Double(2.0) returns 0.55
So why does that happen and how can I make 1.0 / 2.0
returns 0.5 with BigDecimal without using divide()
giving a scale parameter?
UPDATES:
Here are the complete codes:
Welcome to Kotlin version 1.2.41 (JRE 1.8.0_172-b11)
Type :help for help, :quit for quit
>>> import java.math.BigDecimal
>>> BigDecimal(1.0) / BigDecimal(2.0)
0
>>> BigDecimal(1.1) / BigDecimal(2.0)
0.550000000000000044408920985006261616945266723632812
UPDATES 2:
According to @user2864740
BigDecimal(1.0).divide(BigDecimal(2.0))
// returns 0.5
and
BigDecimal("1.0") / BigDecimal(2.0)
// returns 0.5
So the results are confusing. For BigDecimals, why do 1.0 / 2.0
returns 0.0, 1.0.divide(2.0)
returns 0.5, and "1.0" / 2.0
returns 0.5?
This limits it to 15 to 17 decimal digits of accuracy. BigDecimal can grow to any size you need it to. Double operates in binary which means it can only precisely represent numbers which can be expressed as a finite number in binary. For example, 0.375 in binary is exactly 0.011.
A BigDecimal is an exact way of representing numbers. A Double has a certain precision. Working with doubles of various magnitudes (say d1=1000.0 and d2=0.001 ) could result in the 0.001 being dropped alltogether when summing as the difference in magnitude is so large. With BigDecimal this would not happen.
56 if you use BigDecimal newValue = myBigDecimal. setScale(2, RoundingMode. DOWN); " This statement is true for HALF_DOWN not for DOWN mode.
Since BigDecimal is immutable, these operations do not modify the existing objects. Rather, they return new objects.
If you write divide
explicitly, it will work the same way as it does in Java:
val a = BigDecimal(1.0)
val b = BigDecimal(2.0)
val x = a.divide(b) // 0.5
When you use the /
operator, that translates to the BigDecimal.div
extension from the standard library, which does the following:
Enables the use of the / operator for BigDecimal instances.
The scale of the result is the same as the scale of this (divident), and for rounding the RoundingMode.HALF_EVEN rounding mode is used.
You can take a look at how the different RoundingMode
constants work here.
1.1
is a double
literal
A floating-point literal is of type float if it ends with the letter F or f; otherwise its type is double and it can optionally end with the letter D or d.
https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html
Therefore by the time the value is passed to BigDecimal
you already lost precision due to the double
value. BigDecimal(1.1)
is equivalent to double d = 1.1; BigDecimal(d)
. You need to pass the value as string
BigDecimal("1.1")
unless the value is exactly representable as a double like 1.5
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With