简体   繁体   中英

Kotlin BigInteger to BigDecimal conversion

I'm writing a very simple class and I'm struggling to do some decimal division.

So this is not great code but ...

class Rational (val numerator: BigInteger, val denominator: BigInteger) : Comparable <Rational> {

     //ATTEMPT 1
     //val decimalRepresentation: BigDecimal = (numerator.toBigDecimal().div(denominator.toBigDecimal()))//.setScale(5)

     //ATTEMPT 2  
     val decimalRepresentation = (BigDecimal(numerator).div(BigDecimal(denominator))) //.setScale(5)

     override fun compareTo(other: Rational): Int {
        val a = BigDecimal(1.0)
        val b = BigDecimal(2.0)
        val x = a.divide(b) // 0.5
        println ("x: " + x.toString())

        println("this val: " + this.decimalRepresentation)
        println("other val: " + other.decimalRepresentation)

        return when {
           ...
        }
    }

So I've tried two ways of converting the BigIntegers into BigDecimals to do the compare and both fail and the maths performs integer division

so

1 / 3 = 0
5 / 6 = 1

I've done a poc in case I'm going mad and x is 0.5.

Could anyone tell me how to fix this (without changing parameter types or converting to a string and back!)

Oddly 1 / 2 is returning 0 as well which seems odd to me as I would expect 0.5 to round to 1 ? This makes me worry that I'm completely missing a very simple point somewhere!

One of the problems lies within BigDecimal.div . It uses the RoundingMode.HALF_EVEN and the given scale of the used dividend BigDecimal (which is also stated in the documentation). The other problem is that the BigInteger to BigDecimal -transformation first sets the scale to 0 (check also BigDecimal(BigInteger) ) and therefore it will round without using decimal digits.

Note also that on your sample you used a.divide(b) with two BigDecimal first and on the actual transformation you used a.div(b) with two BigInteger -transformed BigDecimal . That's a completely different story ;-)

You can solve your issue with one of the following:

Either transform your BigInteger using toBigDecimal and specify a desired scale , eg:

val scale = 10 // decimal digits
val decimalRepresentation = numerator.toBigDecimal(scale) / denominator.toBigDecimal(scale)

Or you may want to use divide instead and pass the desired scale:

val decimalRepresentation = BigDecimal(numerator).divide(BigDecimal(denominator), 2, RoundingMode.HALF_UP)

In this case I used 2 decimal digits and I am rounding up on half ( RoundingMode.HALF_UP ) .

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