Marwan02
Marwan02

Reputation: 67

Multiply Double with BigDecimal

I have a BigDecimals that's always have 30 digits after the decimal points.

And I want to multiply them with Double and get a BigDecimal with 30 digits after decimal point.

For exemple I have:

    val double = 4.0
    val bd = 0.111111111111111111111111111111

    
    def multiply(d : Double, bd : BigDecimal, scale: Int) = {
    
     BigDecimal.valueOf(d).setScale(scale).*(bd)

    }

// multiply(double,bd,30) => 0.4444444444444444000000000000000000


I expected to get 0.444444444444444444444444444444 (30 times 4 after the point)

What is wrong with my method?

Upvotes: 0

Views: 842

Answers (2)

Levi Ramsey
Levi Ramsey

Reputation: 20551

Your bd isn't a BigDecimal, it's a Double:

scala> val bd = 0.111111111111111111111111111111
val bd: Double = 0.1111111111111111

It gets implicitly converted to a BigDecimal (after losing precision from Double) when you call multiply.

To create the BigDecimal, you seek, it's probably best to parse a string representation:

val bd = BigDecimal("0.111111111111111111111111111111")
// bd.scale is 30

It's also probably a good idea to explicitly set the scale again in multiply after the multiplication, as it's possible for multiplying two numbers, even with the same scale, to have greater scale than either number.

def multiply(d: Double, bd: BigDecimal, scale:Int): BigDecimal =
  (BigDecimal.valueOf(d).setScale(scale) * bd).setScale(scale)

Upvotes: 3

ELinda
ELinda

Reputation: 2821

Scala's BigDecimal is similar to Java's BigDecimal.

  • When you multiply two BigDecimals together (using the * method on the left one), you get a new BigDecimal whose scale is the sum of the scale of its operands (inputs).
  • The variable bd is not a BigDecimal, so its name is misleading. It is actually a double. In order to instantiate a BigDecimal, you should use a constructor, for example: BigDecimal("0.111111111111111111111111111111").
val bd = BigDecimal("0.111111111111111111111111111111")
val double = 4.0

// There is no need to call `setScale` on `d` due to the first point noted above. Set it after multiplying:
def multiply(d : Double, bd : BigDecimal, scale: Int) =   
  (BigDecimal.valueOf(d) * bd).setScale(scale)

val result = multiply(double, bd, 30)
println(result)
println(result.scale)

Result:

0.444444444444444444444444444444
30

Upvotes: 3

Related Questions