Skip to content

fix: preserve negative zero sign in std.mantissa - #1092

Merged
stephenamar-db merged 1 commit into
databricks:masterfrom
He-Pin:fix/mantissa-negative-zero
Jul 28, 2026
Merged

fix: preserve negative zero sign in std.mantissa#1092
stephenamar-db merged 1 commit into
databricks:masterfrom
He-Pin:fix/mantissa-negative-zero

Conversation

@He-Pin

@He-Pin He-Pin commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Motivation

std.mantissa(0 * -1) returned positive 0.0 instead of -0.0. The zero guard used literal 0.0, discarding the IEEE 754 sign bit.

Mathematical basis: std.mantissa implements the mantissa component of frexp (C99 §7.12.6.4). While C says "if value is zero, both parts are zero", IEEE 754 requires sign preservation. All reference implementations (go-jsonnet via Go's math.Frexp, jrsonnet via Rust's bit-preserving (s, 0) return, Python via math.frexp) return (-0.0, 0) for negative zero input.

Modification

Change if (x == 0) 0.0 to if (x == 0) x. Since -0.0 == 0.0 is true in IEEE 754, the guard still catches both zeros but now returns the input unchanged, preserving the sign bit.

std.exponent does not need the same fix — it returns an integer (0L), so there is no sign bit to preserve.

Result

std.mantissa(0 * -1) now returns -0.0, matching all reference implementations. Positive zero behavior is unchanged.

Behavior comparison

Input go-jsonnet jrsonnet Python (math.frexp) sjsonnet (before) sjsonnet (after)
std.mantissa(0 * -1) -0 -0 (-0.0, 0) 0 -0
std.mantissa(0) 0 0 (0.0, 0) 0 0 (unchanged)
std.mantissa(1.5) 0.75 0.75 (0.75, 1) 0.75 0.75 (unchanged)
std.mantissa(-1.5) -0.75 -0.75 (-0.75, 1) -0.75 -0.75 (unchanged)

Test plan

  • Added mantissa_negative_zero.jsonnet regression test with golden file
  • Test uses std.toString to observe sign (assertEqual cannot distinguish -0.0 from 0.0 due to IEEE equality)
  • std.toString(std.mantissa(0 * -1))"-0" (was "0")
  • std.toString(std.mantissa(0))"0" (unchanged)
  • Full test suite passes (48/48)

Motivation:
`std.mantissa(0 * -1)` returned positive 0.0 instead of -0.0. The zero
guard used literal `0.0`, discarding the IEEE 754 sign bit. std.mantissa
implements the mantissa component of frexp (C99 §7.12.6.4); IEEE 754
requires sign preservation. go-jsonnet (math.Frexp), jrsonnet (returns s
directly), and Python (math.frexp) all return -0.0 for negative zero.

Modification:
Change `if (x == 0) 0.0` to `if (x == 0) x`. Since -0.0 == 0.0 is true
in IEEE 754, the guard still catches both zeros but returns the input
unchanged, preserving the sign bit. std.exponent needs no change (returns
integer 0L, no sign bit to preserve).

Result:
`std.mantissa(0 * -1)` returns -0.0, matching all reference
implementations. Positive zero and non-zero behavior unchanged.
@He-Pin
He-Pin force-pushed the fix/mantissa-negative-zero branch from ac97744 to e0c5ec3 Compare July 27, 2026 19:04
@stephenamar-db
stephenamar-db merged commit 705a675 into databricks:master Jul 28, 2026
5 checks passed
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.

2 participants