This is an automated email from the ASF dual-hosted git repository.
gengliangwang 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 67947f6cf830 [SPARK-57178][SQL] Simplify Asinh codegen by extracting a
static Java helper
67947f6cf830 is described below
commit 67947f6cf8304482e04b4925d86435d7deac331e
Author: Gengliang Wang <[email protected]>
AuthorDate: Wed Jun 3 11:45:35 2026 -0700
[SPARK-57178][SQL] Simplify Asinh codegen by extracting a static Java helper
### What changes were proposed in this pull request?
Add `ExpressionImplUtils.asinh(double x)` (the fdlibm `s_asinh.c`
algorithm) and route `Asinh`'s eval and codegen paths through it.
`Asinh.doGenCode` previously emitted a ~14-line inline five-branch if/else; it
now emits a single `ExpressionImplUtils.asinh(...)` call via `defineCodeGen`,
and the eval path calls the same helper instead of an inline lambda copy of the
algorithm.
`asinh` returns a primitive `double`, so the helper is a clean drop-in for
both paths with no boxing and no null handling. Sibling of SPARK-57177 (Acosh).
### Why are the changes needed?
Part of SPARK-56908 (umbrella). Collapsing the duplicated ~14-line
algorithm to a single call shrinks the generated Java for every stage that uses
`asinh`, and removes the eval/codegen duplication of the same fdlibm algorithm,
helping with the JVM 64KB method / constant-pool limits, Janino compile time,
and JIT work.
### Does this PR introduce _any_ user-facing change?
No. The compiled behavior is identical; only the emitted Java source text
changes.
### How was this patch tested?
```
build/sbt "catalyst/testOnly *MathExpressionsSuite"
```
Pass, including `asinh` and `SPARK-56089: asinh/acosh fdlibm algorithm
coverage` (exercised both with and without whole-stage codegen).
### Was this patch authored or co-authored using generative AI tooling?
Generated-by: Claude Code (Opus 4.8)
Closes #56229 from gengliangwang/spark-asinh-codegen.
Authored-by: Gengliang Wang <[email protected]>
Signed-off-by: Gengliang Wang <[email protected]>
---
.../catalyst/expressions/ExpressionImplUtils.java | 24 ++++++++++++
.../sql/catalyst/expressions/mathExpressions.scala | 44 ++--------------------
2 files changed, 28 insertions(+), 40 deletions(-)
diff --git
a/sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/ExpressionImplUtils.java
b/sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/ExpressionImplUtils.java
index 4343f6631c0c..1a49cf6bb52b 100644
---
a/sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/ExpressionImplUtils.java
+++
b/sql/catalyst/src/main/java/org/apache/spark/sql/catalyst/expressions/ExpressionImplUtils.java
@@ -346,6 +346,30 @@ public class ExpressionImplUtils {
return UTF8String.fromString(qtChar + sp + qtChar);
}
+ /**
+ * Inverse hyperbolic sine for the {@code asinh} expression, using the fdlibm
+ * {@code s_asinh.c} algorithm (odd function, so the sign of {@code x} is
+ * preserved). Shared by the eval and codegen paths so the generated Java is
a
+ * single call rather than an inline five-branch if/else.
+ */
+ public static double asinh(double x) {
+ double ax = Math.abs(x);
+ double w;
+ if (Double.isInfinite(ax) || Double.isNaN(ax)) {
+ w = ax;
+ } else if (ax < 1.0 / (1 << 28)) {
+ w = ax;
+ } else if (ax > (1 << 28)) {
+ w = StrictMath.log(ax) + StrictMath.log(2.0);
+ } else if (ax > 2.0) {
+ w = StrictMath.log(2.0 * ax + 1.0 / (Math.sqrt(x * x + 1.0) + ax));
+ } else {
+ double t = x * x;
+ w = StrictMath.log1p(ax + t / (1.0 + Math.sqrt(1.0 + t)));
+ }
+ return Math.copySign(w, x);
+ }
+
/**
* Inverse hyperbolic cosine for the {@code acosh} expression, using the
* fdlibm {@code e_acosh.c} algorithm (returns {@code NaN} for {@code x <
1}).
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 2f62e1427d16..7bd166250db0 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
@@ -848,47 +848,11 @@ case class Sinh(child: Expression) extends
UnaryMathExpression(math.sinh, "SINH"
since = "3.0.0",
group = "math_funcs")
case class Asinh(child: Expression)
- extends UnaryMathExpression((x: Double) => {
- // fdlibm s_asinh.c algorithm
- val ax = Math.abs(x)
- val w = if (ax.isInfinite || ax.isNaN) {
- ax
- } else if (ax < 1.0 / (1 << 28)) {
- ax
- } else if (ax > (1 << 28)) {
- StrictMath.log(ax) + StrictMath.log(2.0)
- } else if (ax > 2.0) {
- StrictMath.log(2.0 * ax + 1.0 / (math.sqrt(x * x + 1.0) + ax))
- } else {
- val t = x * x
- StrictMath.log1p(ax + t / (1.0 + math.sqrt(1.0 + t)))
- }
- Math.copySign(w, x)
- }, "ASINH") {
+ // fdlibm s_asinh.c algorithm, shared with codegen via
ExpressionImplUtils.asinh.
+ extends UnaryMathExpression((x: Double) => ExpressionImplUtils.asinh(x),
"ASINH") {
override def doGenCode(ctx: CodegenContext, ev: ExprCode): ExprCode = {
- nullSafeCodeGen(ctx, ev, c => {
- val sm = "java.lang.StrictMath"
- val ax = ctx.freshName("ax")
- val w = ctx.freshName("w")
- val t = ctx.freshName("t")
- s"""
- |double $ax = java.lang.Math.abs($c);
- |double $w;
- |if (java.lang.Double.isInfinite($ax) || java.lang.Double.isNaN($ax))
{
- | $w = $ax;
- |} else if ($ax < ${1.0 / (1 << 28)}) {
- | $w = $ax;
- |} else if ($ax > ${1 << 28}.0) {
- | $w = $sm.log($ax) + $sm.log(2.0);
- |} else if ($ax > 2.0) {
- | $w = $sm.log(2.0 * $ax + 1.0 / (java.lang.Math.sqrt($c * $c + 1.0)
+ $ax));
- |} else {
- | double $t = $c * $c;
- | $w = $sm.log1p($ax + $t / (1.0 + java.lang.Math.sqrt(1.0 + $t)));
- |}
- |${ev.value} = java.lang.Math.copySign($w, $c);
- |""".stripMargin
- })
+ val utils = classOf[ExpressionImplUtils].getName
+ defineCodeGen(ctx, ev, c => s"$utils.asinh($c)")
}
override protected def withNewChildInternal(newChild: Expression): Asinh =
copy(child = newChild)
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]