2

I have a data frame which contains two columns of type BigInt. Then I have a user-defined function which performs an operation over these two columns and the final result is supposed to be of type Float.

def generateNewColumnValue(firstColumnValue: BigInt, secondColumnValue: BigInt): Float = {
   val calculated = scala.math.pow(firstColumnValue.toFloat / secondColumnValue, 1.0/3.0);
   return calculated;
}

val generateNewColumnValueUDF = udf[Float, BigInt, BigInt](generateNewColumnValue);

Inside of the body of the UDF I am doing some very simple calculations, as you can see. The problem is that I get the following error and I don't understand why it is not possible:

command-836521033094408:9: error: overloaded method value / with alternatives:
  (x: Double)Double <and>
  (x: Float)Float <and>
  (x: Long)Float <and>
  (x: Int)Float <and>
  (x: Char)Float <and>
  (x: Short)Float <and>
  (x: Byte)Float
 cannot be applied to (BigInt)
  val calculated = scala.math.pow(firstColumnValue.toFloat / secondColumnValue, 1.0/3.0);

The problem is that if I try to cast it to a lower range type (like Int) I might be losing some value after the decimal point.

Krzysztof Atłasik
  • 21,985
  • 6
  • 54
  • 76
user2128702
  • 2,059
  • 2
  • 29
  • 74
  • 2
    `new BigDecimal(firstColumnValue).divide(secondColumnValue, roundingMode).toFloat` (or better .toDouble if you can) – Thilo Feb 12 '20 at 10:58
  • 1
    Does this answer your question? [In java, how do I divide two BigIntegers and store the value in a double?](https://stackoverflow.com/questions/39762172/in-java-how-do-i-divide-two-bigintegers-and-store-the-value-in-a-double) – Thilo Feb 12 '20 at 11:00
  • @Thilo BigInteger is not part of Scala. I tried with BigInt but it doesn't work. – user2128702 Feb 12 '20 at 11:55
  • For Scala `BigDecimal` you write `BigDecimal(firstColumnValue)`, no `new` (and divide with `/`, not `divide`). – Alexey Romanov Feb 12 '20 at 13:00

1 Answers1

2

The message just says you can divide a Float by Double, Float, etc. but not by BigInt. Call toFloat on both operands, not just one:

firstColumnValue.toFloat / secondColumnValue.toFloat

But math.pow takes Doubles, not Floats, so toDouble makes more sense. If the result has to be Float, call toFloat on the result of pow, not its arguments.

Or going through BigDecimal:

(BigDecimal(firstColumnValue) / BigDecimal(secondColumnValue)).toDouble

In most cases it should give approximately the same result as the first option, but slower; the problem is that BigInts can be so large that firstColumnValue.toDouble returns Double.PositiveInfinity/NegativeInfinity. You could check for that, and only use the second option in that case.

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487