You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@spark.apache.org by do...@apache.org on 2019/07/15 03:42:12 UTC

[spark] branch master updated: [SPARK-28133][SQL] Add acosh/asinh/atanh functions to SQL

This is an automated email from the ASF dual-hosted git repository.

dongjoon pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/spark.git


The following commit(s) were added to refs/heads/master by this push:
     new a2f71a8  [SPARK-28133][SQL] Add acosh/asinh/atanh functions to SQL
a2f71a8 is described below

commit a2f71a8d852be166561c208fad0c9a74ae304dd3
Author: Tony Zhang <to...@uber.com>
AuthorDate: Sun Jul 14 20:41:45 2019 -0700

    [SPARK-28133][SQL] Add acosh/asinh/atanh functions to SQL
    
    ## What changes were proposed in this pull request?
    
    Adding support to hyperbolic functions like asinh\acosh\atanh in spark SQL.
    Feature parity: https://www.postgresql.org/docs/12/functions-math.html#FUNCTIONS-MATH-HYP-TABLE
    
    The followings are the diffence from PostgreSQL.
    ```
    spark-sql> SELECT acosh(0);     (PostgreSQL returns `ERROR:  input is out of range`)
    NaN
    
    spark-sql> SELECT atanh(2);     (PostgreSQL returns `ERROR:  input is out of range`)
    NaN
    ```
    
    Teradata has similar behavior as PostgreSQL with out of range input float values - It outputs **Invalid Input: numeric value within range only.**
    
    These newly added asinh/acosh/atanh handles special input(NaN, +-Infinity) in the same way as existing cos/sin/tan/acos/asin/atan in spark. For which input value range is not (-∞, ∞)):
    out of range float values: Spark returns NaN and PostgreSQL shows input is out of range
    NaN: Spark returns NaN, PostgreSQL also returns NaN
    Infinity: Spark return NaN, PostgreSQL shows input is out of range
    
    ## How was this patch tested?
    
    ```
    spark.sql("select asinh(xx)")
    spark.sql("select acosh(xx)")
    spark.sql("select atanh(xx)")
    
    ./build/sbt "testOnly org.apache.spark.sql.MathFunctionsSuite"
    ./build/sbt "testOnly org.apache.spark.sql.catalyst.expressions.MathExpressionsSuite"
    ```
    
    Closes #25041 from Tonix517/SPARK-28133.
    
    Authored-by: Tony Zhang <to...@uber.com>
    Signed-off-by: Dongjoon Hyun <dh...@apple.com>
---
 .../sql/catalyst/analysis/FunctionRegistry.scala   |  3 +
 .../sql/catalyst/expressions/mathExpressions.scala | 71 ++++++++++++++++++++++
 .../expressions/MathExpressionsSuite.scala         | 32 ++++++++++
 3 files changed, 106 insertions(+)

diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/FunctionRegistry.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/FunctionRegistry.scala
index 9fe9567..c72400a 100644
--- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/FunctionRegistry.scala
+++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/analysis/FunctionRegistry.scala
@@ -222,9 +222,12 @@ object FunctionRegistry {
 
     // math functions
     expression[Acos]("acos"),
+    expression[Acosh]("acosh"),
     expression[Asin]("asin"),
+    expression[Asinh]("asinh"),
     expression[Atan]("atan"),
     expression[Atan2]("atan2"),
+    expression[Atanh]("atanh"),
     expression[Bin]("bin"),
     expression[BRound]("bround"),
     expression[Cbrt]("cbrt"),
diff --git a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala
index bdeb9ed..e873f8e 100644
--- a/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala
+++ b/sql/catalyst/src/main/scala/org/apache/spark/sql/catalyst/expressions/mathExpressions.scala
@@ -287,6 +287,29 @@ case class Cos(child: Expression) extends UnaryMathExpression(math.cos, "COS")
   """)
 case class Cosh(child: Expression) extends UnaryMathExpression(math.cosh, "COSH")
 
+@ExpressionDescription(
+  usage = """
+    _FUNC_(expr) - Returns inverse hyperbolic cosine of `expr`.
+  """,
+  arguments = """
+    Arguments:
+      * expr - hyperbolic angle
+  """,
+  examples = """
+    Examples:
+      > SELECT _FUNC_(1);
+       0.0
+      > SELECT _FUNC_(0);
+       NaN
+  """,
+  since = "3.0.0")
+case class Acosh(child: Expression)
+  extends UnaryMathExpression((x: Double) => math.log(x + math.sqrt(x * x - 1.0)), "ACOSH") {
+  override def doGenCode(ctx: CodegenContext, ev: ExprCode): ExprCode = {
+    defineCodeGen(ctx, ev, c => s"java.lang.Math.log($c + java.lang.Math.sqrt($c * $c - 1.0))")
+  }
+}
+
 /**
  * Convert a num from one base to another
  *
@@ -558,6 +581,31 @@ case class Sin(child: Expression) extends UnaryMathExpression(math.sin, "SIN")
 case class Sinh(child: Expression) extends UnaryMathExpression(math.sinh, "SINH")
 
 @ExpressionDescription(
+  usage = """
+    _FUNC_(expr) - Returns inverse hyperbolic sine of `expr`.
+  """,
+  arguments = """
+    Arguments:
+      * expr - hyperbolic angle
+  """,
+  examples = """
+    Examples:
+      > SELECT _FUNC_(0);
+       0.0
+  """,
+  since = "3.0.0")
+case class Asinh(child: Expression)
+  extends UnaryMathExpression((x: Double) => x match {
+    case Double.NegativeInfinity => Double.NegativeInfinity
+    case _ => math.log(x + math.sqrt(x * x + 1.0)) }, "ASINH") {
+  override def doGenCode(ctx: CodegenContext, ev: ExprCode): ExprCode = {
+    defineCodeGen(ctx, ev, c =>
+      s"$c == Double.NEGATIVE_INFINITY ? Double.NEGATIVE_INFINITY : " +
+      s"java.lang.Math.log($c + java.lang.Math.sqrt($c * $c + 1.0))")
+  }
+}
+
+@ExpressionDescription(
   usage = "_FUNC_(expr) - Returns the square root of `expr`.",
   examples = """
     Examples:
@@ -618,6 +666,29 @@ case class Cot(child: Expression)
 case class Tanh(child: Expression) extends UnaryMathExpression(math.tanh, "TANH")
 
 @ExpressionDescription(
+  usage = """
+    _FUNC_(expr) - Returns inverse hyperbolic tangent of `expr`.
+  """,
+  arguments = """
+    Arguments:
+      * expr - hyperbolic angle
+  """,
+  examples = """
+    Examples:
+      > SELECT _FUNC_(0);
+       0.0
+      > SELECT _FUNC_(2);
+       NaN
+  """,
+  since = "3.0.0")
+case class Atanh(child: Expression)
+  extends UnaryMathExpression((x: Double) => 0.5 * math.log((1.0 + x) / (1.0 - x)), "ATANH") {
+  override def doGenCode(ctx: CodegenContext, ev: ExprCode): ExprCode = {
+    defineCodeGen(ctx, ev, c => s"0.5 * java.lang.Math.log((1.0 + $c)/(1.0 - $c))")
+  }
+}
+
+@ExpressionDescription(
   usage = "_FUNC_(expr) - Converts radians to degrees.",
   arguments = """
     Arguments:
diff --git a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/MathExpressionsSuite.scala b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/MathExpressionsSuite.scala
index 4810557..4c048f7 100644
--- a/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/MathExpressionsSuite.scala
+++ b/sql/catalyst/src/test/scala/org/apache/spark/sql/catalyst/expressions/MathExpressionsSuite.scala
@@ -199,6 +199,18 @@ class MathExpressionsSuite extends SparkFunSuite with ExpressionEvalHelper {
     checkConsistencyBetweenInterpretedAndCodegen(Sinh, DoubleType)
   }
 
+  test("asinh") {
+    testUnary(Asinh, (x: Double) => math.log(x + math.sqrt(x * x + 1.0)))
+    checkConsistencyBetweenInterpretedAndCodegen(Asinh, DoubleType)
+
+    checkEvaluation(Asinh(Double.NegativeInfinity), Double.NegativeInfinity)
+
+    val nullLit = Literal.create(null, NullType)
+    val doubleNullLit = Literal.create(null, DoubleType)
+    checkEvaluation(checkDataTypeAndCast(Asinh(nullLit)), null, EmptyRow)
+    checkEvaluation(checkDataTypeAndCast(Asinh(doubleNullLit)), null, EmptyRow)
+  }
+
   test("cos") {
     testUnary(Cos, math.cos)
     checkConsistencyBetweenInterpretedAndCodegen(Cos, DoubleType)
@@ -215,6 +227,16 @@ class MathExpressionsSuite extends SparkFunSuite with ExpressionEvalHelper {
     checkConsistencyBetweenInterpretedAndCodegen(Cosh, DoubleType)
   }
 
+  test("acosh") {
+    testUnary(Acosh, (x: Double) => math.log(x + math.sqrt(x * x - 1.0)))
+    checkConsistencyBetweenInterpretedAndCodegen(Cosh, DoubleType)
+
+    val nullLit = Literal.create(null, NullType)
+    val doubleNullLit = Literal.create(null, DoubleType)
+    checkEvaluation(checkDataTypeAndCast(Acosh(nullLit)), null, EmptyRow)
+    checkEvaluation(checkDataTypeAndCast(Acosh(doubleNullLit)), null, EmptyRow)
+  }
+
   test("tan") {
     testUnary(Tan, math.tan)
     checkConsistencyBetweenInterpretedAndCodegen(Tan, DoubleType)
@@ -244,6 +266,16 @@ class MathExpressionsSuite extends SparkFunSuite with ExpressionEvalHelper {
     checkConsistencyBetweenInterpretedAndCodegen(Tanh, DoubleType)
   }
 
+  test("atanh") {
+    testUnary(Atanh, (x: Double) => 0.5 * math.log((1.0 + x) / (1.0 - x)))
+    checkConsistencyBetweenInterpretedAndCodegen(Atanh, DoubleType)
+
+    val nullLit = Literal.create(null, NullType)
+    val doubleNullLit = Literal.create(null, DoubleType)
+    checkEvaluation(checkDataTypeAndCast(Atanh(nullLit)), null, EmptyRow)
+    checkEvaluation(checkDataTypeAndCast(Atanh(doubleNullLit)), null, EmptyRow)
+  }
+
   test("toDegrees") {
     testUnary(ToDegrees, math.toDegrees)
     checkConsistencyBetweenInterpretedAndCodegen(ToDegrees, DoubleType)


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@spark.apache.org
For additional commands, e-mail: commits-help@spark.apache.org