Skip to content

math: pow special cases pow(1, NaN) and pow(±1, ±inf) return NaN, diverging from IEEE 754/C99 pow #4059

Description

@bobzhang

Behavior

On every backend (wasm-gc, wasm, js, native), the following all return NaN:

@math.pow(1.0, @double.not_a_number)   // NaN, IEEE 754 / C99 Annex F say 1.0
@math.pow(1.0, @double.infinity)       // NaN, IEEE 754 / C99 Annex F say 1.0
@math.pow(1.0, @double.neg_infinity)   // NaN, IEEE 754 / C99 Annex F say 1.0
@math.pow(-1.0, @double.infinity)      // NaN, IEEE 754 / C99 Annex F say 1.0
@math.pow(-1.0, @double.neg_infinity)  // NaN, IEEE 754 / C99 Annex F say 1.0

Discussion

  • IEEE 754-2019 (§9.2.1) and C99 Annex F (F.9.4.4) specify pow(1, y) = 1 for any y, including NaN, and pow(±1, ±∞) = 1 — the rationale being "1 to any power is 1".
  • The current behavior follows the classic fdlibm ordering (NaN check first) and matches ECMAScript's Math.pow / **, so it is at least internally consistent and consistent across backends.
  • However, the function's doc comment claims IEEE 754 semantics, so today either the docs or the behavior is wrong.

Possible resolutions

  1. Align behavior with IEEE 754/C99: special-case x == 1.0 (and |x| == 1.0 with infinite y) before the NaN check. This is what glibc/musl/Rust/Go do.
  2. Keep JS-Math.pow behavior and fix the doc comment to say so explicitly.

Either way the divergence should stop being implicit. Found while adding QuickCheck special-value coverage in #4055 (the property suite currently pins the actual behavior, and can be flipped to the IEEE behavior if option 1 is chosen).

🤖 Generated with Claude Code

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions