github-actions[bot] commented on code in PR #68029:
URL: https://github.com/apache/doris/pull/68029#discussion_r4058837042


##########
fe/fe-core/src/main/java/org/apache/doris/nereids/trees/expressions/functions/executable/NumericArithmetic.java:
##########
@@ -755,6 +756,45 @@ public static Expression factorial(BigIntLiteral first) {
         return new BigIntLiteral(ArithmeticUtils.factorial((int) value));
     }
 
+    /**
+     * gamma
+     *
+     * <p>The BE computes this with std::tgamma and maps the poles to NULL, so 
this
+     * evaluation reproduces that outcome rather than the raw library 
behaviour:
+     * commons-math3 returns NaN for everything that is not finite, while 
std::tgamma
+     * returns an infinity at zero, at a large enough argument and at positive 
infinity.
+     *
+     * <p>-Infinity is the one input where the two classifications differ in a 
way that
+     * matters: the BE sees it as a negative integer, hence a pole, and yields 
NULL.
+     *
+     * <p>Positive and negative inputs need different routes through 
commons-math3.
+     * Gamma.gamma saturates to an infinity well before std::tgamma does - it 
already
+     * overflows at 165, while std::tgamma still returns a finite 3.29e293 
there - so
+     * positive inputs go through exp(logGamma(x)), which stays finite across 
the range and
+     * agrees with std::tgamma to the last place. logGamma is not defined for 
negative
+     * inputs, but that half has no overflow problem, so Gamma.gamma is used 
there.
+     */
+    @ExecFunction(name = "gamma")
+    public static Expression gamma(DoubleLiteral first) {
+        double x = first.getValue();
+        if (Double.isNaN(x)) {
+            return new DoubleLiteral(Double.NaN);
+        }
+        if (Double.isInfinite(x)) {
+            // +inf overflows to itself; -inf is treated as a negative 
integer, i.e. a pole.
+            return x > 0 ? new DoubleLiteral(Double.POSITIVE_INFINITY)

Review Comment:
   `gamma` is folded here with Commons Math, but execution uses `std::tgamma` 
in BE. These implementations do not agree for all finite doubles: Commons Math 
3.6.1 gives `gamma(-150.5) = -0.0` while BE returns about 
`-4.478447658150641e-264`, and `gamma(-1000.5) = NaN` while BE returns signed 
zero; near the positive subnormal overflow boundary (`0x0.3ffffffffffffp-1022`) 
FE produces a finite max-double value while BE returns `Infinity`. Even 
ordinary values differ (`gamma(10)` folds to `362879.9999999998` versus BE 
`362880.0`). A literal query can therefore change rows, comparisons, and 
overflow/NaN classification when constant folding is toggled. Please use a 
numerically equivalent implementation/shared boundary or disable folding for 
inputs that cannot be proven equivalent, and add parity coverage for these 
domains.



##########
be/test/exprs/function/function_math_test.cpp:
##########
@@ -184,6 +184,39 @@ TEST(MathFunctionTest, cbrt_test) {
     static_cast<void>(check_function<DataTypeFloat64, true>(func_name, 
input_types, data_set));
 }
 
+TEST(MathFunctionTest, gamma_test) {
+    std::string func_name = "gamma"; // gamma(x): x > 0, and a negative 
non-integer x
+
+    InputTypeSet input_types = {PrimitiveType::TYPE_DOUBLE};
+    // Gamma(n) is (n - 1)! for a positive integer n, but std::tgamma does not 
return every
+    // factorial exactly: 5 comes back as 24.000000000000004, so the 
expectation carries the ulp
+    // the implementation actually produces rather than the mathematical 
integer. Gamma(0.5) is
+    // sqrt(pi) and the half-integer rows are its multiples (sqrt(pi)/2 at 
1.5, 3*sqrt(pi)/4 at
+    // 2.5); the values at -0.5, -1.5 and -2.5 come from the reflection 
formula. 0 and the negative
+    // integers are poles and must come back NULL, as MySQL returns, and a 
NULL input stays NULL.
+    DataSet data_set = {{{1.0}, 1.0},
+                        {{2.0}, 1.0},
+                        {{3.0}, 2.0},
+                        {{4.0}, 6.0},
+                        {{5.0}, 24.000000000000004},
+                        {{10.0}, 362880.00000000047},
+                        {{0.5}, 1.7724538509055161},
+                        {{1.5}, 0.88622692545275805},
+                        {{2.5}, 1.329340388179137},
+                        {{-0.5}, -3.5449077018110318},
+                        {{-1.5}, 2.3632718012073544},
+                        {{-2.5}, -0.94530872048294179},

Review Comment:
   These exact expected values are from the FE `exp(logGamma)` route, not the 
registered BE call. On this runner `std::tgamma(5)` is `24.0`, `tgamma(10)` is 
`362880.0`, `tgamma(-1.5)` is `2.363271801207355`, `tgamma(-2.5)` is 
`-0.9453087204829419`, and `tgamma(171)` is `7.257415615307999e306`, while this 
test expects different doubles. `check_function` compares `ColumnFloat64` 
values exactly, so the unit test (and the generated regression fixture) is 
platform-dependent and can fail. Please regenerate expectations from the BE 
implementation or use a documented tolerance/portable oracle.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to