fix: preserve negative zero in Float32Array and Float64Array#356
Open
greymoth-jp wants to merge 1 commit into
Open
fix: preserve negative zero in Float32Array and Float64Array#356greymoth-jp wants to merge 1 commit into
greymoth-jp wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
stringify/parsedrops the sign of negative zero when it is stored in aFloat32ArrayorFloat64Array:The typed-array transformer already encodes the special float values that a JSON round-trip cannot represent:
NaN,Infinityand-Infinityare written out as strings (#292, #349).-0is the one that was left out.JSON.stringify(-0)returns"0", so the sign is gone as soon as the serialized payload passes through JSON.superjson preserves
-0everywhere else (the dedicated number rule from regression #83), and the object-onlyserialize/deserializepath kept it too because it passes the raw value through untouched. Only the string path lost it, and only for the two float-backed typed arrays, since integer and clamped arrays cannot hold-0.This stores
-0as"-0"and reads it back, the same wayNaN/Infinityare handled in that function. I added a regression test next to the existing #292 case.Greptile Summary
This PR fixes a bug where
-0stored inFloat32ArrayorFloat64Arraywas silently dropped during JSON serialization, coming back as+0after astringify/parseround-trip. It extends the existing special-float-value encoding intypedArrayRuleto treat-0the same wayNaN,Infinity, and-Infinityare already handled.src/transformer.ts: Adds a-0detection check (n === 0 && 1 / n === -Infinity) in the serializer and a corresponding'-0'→-0conversion in the deserializer, following the exact pattern already used for the other IEEE 754 special values.src/index.test.ts: Adds a regression test that verifies round-trip fidelity for-0entries in bothFloat64ArrayandFloat32Array, and also confirms positive0is not incorrectly converted.Confidence Score: 5/5
Safe to merge — the change is minimal, isolated to the typed-array transformer, and follows the existing pattern exactly.
Both the serializer and deserializer changes are a single-line addition each, directly mirroring the already-proven NaN/Infinity handling. The negative-zero detection idiom (n === 0 && 1 / n === -Infinity) is correct and widely used in JS. The new test covers mixed arrays with both -0 and +0 to prevent false positives, and integer typed arrays are unaffected since they can never hold -0 in the first place.
No files require special attention.
Important Files Changed
Sequence Diagram
%%{init: {'theme': 'neutral'}}%% sequenceDiagram participant App participant SuperJSON participant typedArrayRule participant JSON App->>SuperJSON: stringify(new Float64Array([-0, 0, 1])) SuperJSON->>typedArrayRule: serialize(Float64Array) typedArrayRule->>typedArrayRule: map each element Note over typedArrayRule: -0 → '-0' (new)<br/>0 → 0<br/>1 → 1 typedArrayRule-->>SuperJSON: ['-0', 0, 1] + annotation SuperJSON->>JSON: JSON.stringify(['-0', 0, 1]) JSON-->>App: "'{"json":{"a":["-0",0,1]},...}'" App->>SuperJSON: "parse('{"json":{"a":["-0",0,1]},...}')" SuperJSON->>JSON: JSON.parse(...) JSON-->>SuperJSON: "{a: ['-0', 0, 1]}" SuperJSON->>typedArrayRule: deserialize(['-0', 0, 1], 'Float64Array') typedArrayRule->>typedArrayRule: map each element Note over typedArrayRule: '-0' → -0 (new)<br/>0 → 0<br/>1 → 1 typedArrayRule-->>SuperJSON: new Float64Array([-0, 0, 1]) SuperJSON-->>App: Float64Array [-0, 0, 1]%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% sequenceDiagram participant App participant SuperJSON participant typedArrayRule participant JSON App->>SuperJSON: stringify(new Float64Array([-0, 0, 1])) SuperJSON->>typedArrayRule: serialize(Float64Array) typedArrayRule->>typedArrayRule: map each element Note over typedArrayRule: -0 → '-0' (new)<br/>0 → 0<br/>1 → 1 typedArrayRule-->>SuperJSON: ['-0', 0, 1] + annotation SuperJSON->>JSON: JSON.stringify(['-0', 0, 1]) JSON-->>App: "'{"json":{"a":["-0",0,1]},...}'" App->>SuperJSON: "parse('{"json":{"a":["-0",0,1]},...}')" SuperJSON->>JSON: JSON.parse(...) JSON-->>SuperJSON: "{a: ['-0', 0, 1]}" SuperJSON->>typedArrayRule: deserialize(['-0', 0, 1], 'Float64Array') typedArrayRule->>typedArrayRule: map each element Note over typedArrayRule: '-0' → -0 (new)<br/>0 → 0<br/>1 → 1 typedArrayRule-->>SuperJSON: new Float64Array([-0, 0, 1]) SuperJSON-->>App: Float64Array [-0, 0, 1]Reviews (1): Last reviewed commit: "fix: preserve negative zero in Float32Ar..." | Re-trigger Greptile