Skip to content

Fix POWER formula returning the base for a zero exponent#3614

Open
Osamaali313 wants to merge 1 commit into
teableio:developfrom
Osamaali313:fix/power-zero-exponent
Open

Fix POWER formula returning the base for a zero exponent#3614
Osamaali313 wants to merge 1 commit into
teableio:developfrom
Osamaali313:fix/power-zero-exponent

Conversation

@Osamaali313

Copy link
Copy Markdown

Problem

The POWER(base, exponent) formula function (packages/core/src/formula/functions/numeric.ts) reads its exponent with a truthy fallback:

eval(params: TypedValue<number | null>[]): number | null {
  const value = params[0].value;
  if (value == null) return null;
  const exponent = params[1]?.value || 1;
  return Math.pow(value, exponent);
}

POWER(x, 0) must return 1 (the identity x⁰ = 1), but 0 || 1 evaluates to 1, so the exponent silently becomes 1 and the function returns the base x instead of 1.

validateParams throws when fewer than 2 params are supplied, so params[1] always exists at eval time — the || 1 "default" is never needed for a missing argument, and its only reachable effect is corrupting an explicitly-passed 0.

Evidence (siblings prove intent)

Ceiling and Floor in the same file use params[1]?.value || 0 — harmless because their default (0) equals the falsy value. Power is the one case where the default (1) differs from the meaningful falsy input (0), so || 1 can only ever misfire.

Reproduction

formula expected before after
POWER(2, 0) 1 2 1 ✅
POWER(10, 0) 1 10 1 ✅
POWER(2, 3) 8 8 8

Fix

const exponent = params[1]?.value ?? 1;

?? preserves the null-safety intent while honoring an explicit 0. Existing tests (numeric.spec.ts) only cover exponents 2 and -2, so the zero case was unguarded.

The `POWER(base, exponent)` formula function reads its exponent with a
truthy fallback:

    const exponent = params[1]?.value || 1;
    return Math.pow(value, exponent);

`POWER(x, 0)` must return 1 (x^0 = 1), but `0 || 1` evaluates to 1, so the
exponent silently becomes 1 and the function returns the base `x` instead.

`validateParams` throws when fewer than 2 params are given, so `params[1]`
always exists at eval time — the `|| 1` default is never needed for a
missing argument and its only reachable effect is corrupting an explicitly
passed `0`. The sibling `Ceiling`/`Floor` functions use `params[1]?.value || 0`,
which is harmless there because their default equals the falsy value; `Power`
is the one case where the default (1) differs from the meaningful falsy input
(0). Use `??` so an explicit `0` exponent is honored.
Copilot AI review requested due to automatic review settings July 18, 2026 20:32

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@CLAassistant

CLAassistant commented Jul 18, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

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.

3 participants