[
https://issues.apache.org/jira/browse/SPARK-58965?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
ASF GitHub Bot updated SPARK-58965:
-----------------------------------
Labels: pull-request-available (was: )
> Add gcd and lcm math functions
> ------------------------------
>
> Key: SPARK-58965
> URL: https://issues.apache.org/jira/browse/SPARK-58965
> Project: Spark
> Issue Type: Improvement
> Components: SQL
> Affects Versions: 4.4.0
> Reporter: Vivek Gangavarapu
> Priority: Major
> Labels: pull-request-available
>
> Spark SQL has no way to compute the greatest common divisor or the least
> common multiple of two integers. There is no expression, and no combination
> of existing built-ins that produces the result, so users must fall back to a
> UDF -- which for PySpark means a Python round trip per row and no whole-stage
> codegen.
> Both functions are standard in comparable engines:
> * PostgreSQL 13+: gcd(a, b), lcm(a, b) for integer, bigint and numeric
> * DuckDB: gcd(a, b), lcm(a, b) (aliases greatest_common_divisor,
> least_common_multiple)
> Common uses: reducing fractions and ratios to lowest terms, aligning batch or
> partition sizes, computing the repeat period of overlapping schedules, and
> normalizing denominators before aggregation.
> h3. Proposed signature
> {code:sql}
> gcd(a, b) -- returns BIGINT
> lcm(a, b) -- returns BIGINT
> {code}
> Both arguments are implicitly cast to BIGINT, matching the existing
> {{factorial}} expression, which also takes an integral argument and returns
> BIGINT.
> h3. Semantics
> || Case || gcd || lcm || Rationale ||
> | either argument is NULL | NULL | NULL | null-intolerant, as for all math
> functions |
> | gcd(0, 0) / lcm(0, 0) | 0 | 0 | PostgreSQL |
> | one argument is 0 | abs(other) | 0 | PostgreSQL |
> | negative arguments | result is non-negative | result is non-negative |
> PostgreSQL, DuckDB |
> | result not representable as BIGINT | ARITHMETIC_OVERFLOW under ANSI mode,
> NULL otherwise | ARITHMETIC_OVERFLOW under ANSI mode, NULL otherwise | see
> below |
> Overflow arises in exactly two places, and in both PostgreSQL raises an error
> as well:
> * {{gcd(-9223372036854775808, 0)}} -- the result is abs(Long.MinValue), which
> is not representable.
> * {{lcm(a, b)}} where {{abs(a) / gcd(a, b) * abs(b)}} exceeds Long.MaxValue.
> Both are reported with the existing ARITHMETIC_OVERFLOW error condition; no
> new error
> condition is introduced. Overflow is gated on ANSI mode, as it is everywhere
> else in Spark
> (compare {{conv}}, which takes the same approach): under ANSI mode the error
> is raised, and in
> non-ANSI mode the result is NULL. Raising unconditionally would make these
> the only functions in
> mathExpressions.scala that do so.
> h3. Examples
> {code:sql}
> SELECT gcd(24, 36); -- 12
> SELECT gcd(-24, 36); -- 12
> SELECT gcd(0, 0); -- 0
> SELECT lcm(4, 6); -- 12
> SELECT lcm(0, 5); -- 0
> SELECT gcd(NULL, 5); -- NULL
> -- reduce a ratio to lowest terms
> SELECT num / gcd(num, den) AS n,
> den / gcd(num, den) AS d
> FROM ratios;
> {code}
> h3. Scope
> * Two new expressions in mathExpressions.scala, with codegen.
> * Registration in FunctionRegistry.
> * Scala/Java API in functions.scala, plus PySpark and Spark Connect.
> * Unit tests, SQL golden-file tests, and documentation.
> No existing behavior changes; the change is purely additive.
> h3. Follow-ups deliberately left out of scope
> * DECIMAL support (PostgreSQL supports gcd/lcm on numeric). Can be added
> later without breaking the BIGINT signature.
> * A {{try_lcm}} variant returning NULL instead of raising on overflow, if the
> community wants one.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]