简体   繁体   中英

java.math.BigDecimal division inaccuracy

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?

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) 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM