[ 
https://issues.apache.org/jira/browse/SPARK-58965?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
 ]

Vivek Gangavarapu updated SPARK-58965:
--------------------------------------
    Affects Version/s: 4.4.0
                           (was: 5.0.0)

> 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
>
> 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 | 
> ARITHMETIC_OVERFLOW | 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 raised as the existing ARITHMETIC_OVERFLOW error condition through
> {{MathUtils.withOverflow}}. No new error condition is introduced.
> 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]

Reply via email to