Skip to content

[doc](sql-functions) Add gamma function documentation - #4140

Open
RH211-sys wants to merge 2 commits into
apache:masterfrom
RH211-sys:add-gamma-function-doc
Open

RH211-sys wants to merge 2 commits into
apache:masterfrom
RH211-sys:add-gamma-function-doc

Conversation

@RH211-sys

Copy link
Copy Markdown

Versions

  • dev
  • 4.x
  • 3.x
  • 2.1 or older (not covered by version/language sync gate)

gamma is a new function on the master branch only, so there is no released version to document yet.

Languages

  • Chinese
  • English

Docs Checklist

  • Checked by AI
  • Test Cases Built
  • Updated required version and language counterparts, or explained why not
  • If only one language changed, confirmed whether source/translation counterparts need sync

Every example block on the page is the real output of the function, captured from a build of the dev
branch, and both language versions are added in this PR, so no counterpart sync is outstanding. The
function itself is covered by the regression test and the BE unit test in the Doris PR.

Summary

Document the gamma scalar function, which is being added to the Doris frontend and backend:

  • docs/sql-manual/sql-functions/scalar-functions/numeric-functions/gamma.md (English)
  • i18n/zh-CN/docusaurus-plugin-content-docs/current/sql-manual/sql-functions/scalar-functions/numeric-functions/gamma.md (Chinese)
  • the numeric-functions/gamma entry in sidebars.ts

The page covers the definition (gamma(n) is (n - 1)! for a positive integer n, gamma(0.5) is
sqrt(pi)), the special values the implementation produces (NULL at 0, at every negative integer
and at negative infinity; NaN for a NaN input; Infinity for positive infinity and above the double
overflow threshold), and nine examples in both languages. Every example block is the real output of
the function, taken from a build of the dev branch, so the values match what a reader gets,
including the double-precision representation 24.000000000000004 for gamma(5).

## Versions

- [x] dev
- [ ] 4.x
- [ ] 3.x
- [ ] 2.1

## Languages

- [x] Chinese
- [x] English

## Docs Checklist

- [ ] Checked by AI
- [ ] Test Cases Built

## Summary

Document the `gamma` scalar function, which is being added to the Doris
frontend and backend:

- `docs/sql-manual/sql-functions/scalar-functions/numeric-functions/gamma.md` (English)
- `i18n/zh-CN/docusaurus-plugin-content-docs/current/sql-manual/sql-functions/scalar-functions/numeric-functions/gamma.md` (Chinese)
- the `numeric-functions/gamma` entry in `sidebars.ts`

The page covers the definition (`gamma(n)` is `(n - 1)!` for a positive integer `n`, `gamma(0.5)`
is `sqrt(pi)`), the special values the implementation produces (NULL at `0`, at every negative
integer and at negative infinity; NaN for a NaN input; Infinity for positive infinity and above
the double overflow threshold), and nine examples in both languages. Every example block is the
real output of the function, taken from a build of the dev branch, so the values match what a
reader gets, including the double-precision representation `24.000000000000004` for `gamma(5)`.

Related Doris PR: added once the Doris pull request is opened; that pull request links back to
this documentation PR.
RH211-sys added a commit to RH211-sys/doris that referenced this pull request Sep 21, 2026
### What problem does this PR solve?

Related issue: [apache#48203](apache#48203)

Problem Summary:

The FE folded `gamma(<literal>)` through commons-math3 while the BE computes it with
`std::tgamma`. The two are independent implementations that cannot be kept aligned, so a
folded constant could differ from the value the BE produces. Measured on the Doris build
environment:

- `gamma(-1000.5)` is NaN from the FE and -0.0 from the BE, a different classification;
- `gamma(-150.5)` is 0.0 from the FE and -4.4784476581511713e-264 from the BE;
- `gamma(10)` is 362879.9999999998 from the FE and 362880.00000000047 from the BE, about 11 ulp.

`gamma` feeds neither partition nor bucket pruning, so the folding buys nothing. Remove it
(`NumericArithmetic.gamma` and the commons-math3 import it needed) and let the BE stay the
only implementation. There is then a single evaluation path: the default session, a session
with `debug_skip_fold_constant=true`, a session with `enable_fold_constant_by_be=true` and a
query that reads `gamma` of a table column all return identical values for the boundary inputs
below (0, -0.0, negative integers, +/-infinity, NaN, 165/170/171/171.5/171.8/172/1e308, the
smallest subnormal and the smallest normal, 1e-300, and large negative non-integers).

Also in this commit:

- The negative-zero row of the regression suite was written as the integer `-0`, which is
  stored as +0.0 and silently duplicated the row holding 0.0. It now uses
  `cast('-0.0' as double)` and is guarded by a `signbit` assertion, so a wrong test value fails
  instead of being recorded in the generated .out file. The suite also gains the boundary
  classes it was missing: inputs whose reciprocal overflows (1e-300, 5e-324,
  2.2250738585072014e-308), the overflow onset (171.5 is finite, 171.8 is Infinity) and large
  negative non-integers that underflow to -0.0 (-1000.5) or to a subnormal (-171.5).
- `math.cpp` cited a MySQL `gamma` anchor, but MySQL has no `gamma` function. The comment now
  states the convention actually followed: a domain error such as a pole returns NULL, as
  `sqrt(-1)` and `ln(0)` do, and only overflow returns Infinity.
- The BE unit test also pins -0.0 as a pole.
- The new FE statements are covered by `GammaTest`, which exercises the signature, the
  nullability, the implicit cast of the argument and the visitor dispatch through
  `withChildren`. This is what `check_coverage_fe` reports as uncovered.

### Release note

None

### Check List (For Author)

- Test
    - [x] Regression test
    - [x] Unit Test
    - [x] Manual test (the boundary matrix described above)
    - [ ] No need to test or manual test. Explain why:
- Behavior changed:
    - [x] Yes: `gamma(<literal>)` is no longer constant folded in the FE, it is computed by the
      BE like every other invocation. The values returned to the client are unchanged.
- Does this need documentation?
    - [x] Yes: apache/doris-website#4140
RH211-sys added a commit to RH211-sys/doris that referenced this pull request Sep 21, 2026
### What problem does this PR solve?

Related issue: [apache#48203](apache#48203)

Problem Summary:

The FE folded `gamma(<literal>)` through commons-math3 while the BE computes it with
`std::tgamma`. The two are independent implementations that cannot be kept aligned, so a
folded constant could differ from the value the BE produces. Measured on the Doris build
environment:

- `gamma(-1000.5)` is NaN from the FE and -0.0 from the BE, a different classification;
- `gamma(-150.5)` is 0.0 from the FE and -4.4784476581511713e-264 from the BE;
- `gamma(10)` is 362879.9999999998 from the FE and 362880.00000000047 from the BE, about 11 ulp.

`gamma` feeds neither partition nor bucket pruning, so the folding buys nothing. Remove it
(`NumericArithmetic.gamma` and the commons-math3 import it needed) and let the BE stay the
only implementation. There is then a single evaluation path: the default session, a session
with `debug_skip_fold_constant=true`, a session with `enable_fold_constant_by_be=true` and a
query that reads `gamma` of a table column all return identical values for the boundary inputs
below (0, -0.0, negative integers, +/-infinity, NaN, 165/170/171/171.5/171.8/172/1e308, the
smallest subnormal and the smallest normal, 1e-300, and large negative non-integers).

Also in this commit:

- The negative-zero row of the regression suite was written as the integer `-0`, which is
  stored as +0.0 and silently duplicated the row holding 0.0. It now uses
  `cast('-0.0' as double)` and is guarded by a `signbit` assertion, so a wrong test value fails
  instead of being recorded in the generated .out file. The suite also gains the boundary
  classes it was missing: inputs whose reciprocal overflows (1e-300, 5e-324,
  2.2250738585072014e-308), the overflow onset (171.5 is finite, 171.8 is Infinity) and large
  negative non-integers that underflow to -0.0 (-1000.5) or to a subnormal (-171.5).
- The near-zero rows hold what libm's tgamma returns, about 1e-14 relative away from the
  correctly rounded value, which is inside the 1e-8 relative tolerance the framework applies to
  DOUBLE cells. The two properties that tolerance cannot see are asserted directly: the sign of
  a result that underflows to zero, and a subnormal result that must not collapse to zero.
- `testFoldConst` passes by construction now that nothing is folded, so it is kept as a guard
  for a folding that might come back, and its last two columns are BOOLEAN
  (`signbit(gamma(-1000.5))`, `gamma(-171.5) > 0`). checkCell compares BOOLEAN cells exactly,
  while its double path would not notice a folding that flipped the sign of an underflowed zero
  (0.0 against -0.0 divides by a zero magnitude) or let a subnormal collapse to zero (the
  decimal-place fallback accepts it).
- `math.cpp` cited a MySQL `gamma` anchor, but MySQL has no `gamma` function. The comment now
  states the convention actually followed: a domain error such as a pole returns NULL, as
  `sqrt(-1)` and `ln(0)` do, and only overflow returns Infinity.
- The BE unit test also pins -0.0 as a pole.
- The new FE statements are covered by `GammaTest`, which exercises the signature, the
  nullability, the implicit cast of the argument and the visitor dispatch through
  `withChildren`. This is what `check_coverage_fe` reports as uncovered.

### Release note

None

### Check List (For Author)

- Test
    - [x] Regression test
    - [x] Unit Test
    - [x] Manual test (the boundary matrix described above)
    - [ ] No need to test or manual test. Explain why:
- Behavior changed:
    - [x] Yes: `gamma(<literal>)` is no longer constant folded in the FE, it is computed by the
      BE like every other invocation. The values returned to the client are unchanged.
- Does this need documentation?
    - [x] Yes: apache/doris-website#4140
- gamma(-2.5) returns -0.9453087204829418, not -0.9453087204829419.
- The pole case covers -0.0 as well.
- Document the two remaining boundary classes: a very small positive argument, where
  gamma(a) is about 1 / a, overflows to Infinity, and a large negative non-integer can
  underflow to a signed zero.

Checked against the engine on the pull request build: gamma(-2.5) is
-0.9453087204829418, signbit(gamma(-1000.5)) is true, and gamma(5e-324) and gamma(1e-320)
are Infinity.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant