Skip to content

Commit 8f88412

Browse files
clockflycloud-fan
authored andcommitted
[SPARK-17617][SQL] Remainder(%) expression.eval returns incorrect result on double value
## What changes were proposed in this pull request? Remainder(%) expression's `eval()` returns incorrect result when the dividend is a big double. The reason is that Remainder converts the double dividend to decimal to do "%", and that lose precision. This bug only affects the `eval()` that is used by constant folding, the codegen path is not impacted. ### Before change ``` scala> -5083676433652386516D % 10 res2: Double = -6.0 scala> spark.sql("select -5083676433652386516D % 10 as a").show +---+ | a| +---+ |0.0| +---+ ``` ### After change ``` scala> spark.sql("select -5083676433652386516D % 10 as a").show +----+ | a| +----+ |-6.0| +----+ ``` ## How was this patch tested? Unit test. Author: Sean Zhong <[email protected]> Closes apache#15171 from clockfly/SPARK-17617. (cherry picked from commit 3977223) Signed-off-by: Wenchen Fan <[email protected]>
1 parent 8646b84 commit 8f88412

File tree

2 files changed

+16
-1
lines changed

2 files changed

+16
-1
lines changed

sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/arithmetic.scala

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,11 @@ case class Remainder(left: Expression, right: Expression) extends BinaryArithmet
273273
if (input1 == null) {
274274
null
275275
} else {
276-
integral.rem(input1, input2)
276+
input1 match {
277+
case d: Double => d % input2.asInstanceOf[java.lang.Double]
278+
case f: Float => f % input2.asInstanceOf[java.lang.Float]
279+
case _ => integral.rem(input1, input2)
280+
}
277281
}
278282
}
279283
}

sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/ArithmeticExpressionSuite.scala

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,17 @@ class ArithmeticExpressionSuite extends SparkFunSuite with ExpressionEvalHelper
172172
// }
173173
}
174174

175+
test("SPARK-17617: % (Remainder) double % double on super big double") {
176+
val leftDouble = Literal(-5083676433652386516D)
177+
val rightDouble = Literal(10D)
178+
checkEvaluation(Remainder(leftDouble, rightDouble), -6.0D)
179+
180+
// Float has smaller precision
181+
val leftFloat = Literal(-5083676433652386516F)
182+
val rightFloat = Literal(10F)
183+
checkEvaluation(Remainder(leftFloat, rightFloat), -2.0F)
184+
}
185+
175186
test("Abs") {
176187
testNumericDataTypes { convert =>
177188
val input = Literal(convert(1))

0 commit comments

Comments
 (0)