Skip to content

fix: normalize extreme exponents in non-scientific decimal formatter#180

Closed
JuaniRios wants to merge 1 commit intomainfrom
fix/normalize-extreme-exponents-in-non-scientific-formatter
Closed

fix: normalize extreme exponents in non-scientific decimal formatter#180
JuaniRios wants to merge 1 commit intomainfrom
fix/normalize-extreme-exponents-in-non-scientific-formatter

Conversation

@JuaniRios
Copy link
Copy Markdown
Contributor

@JuaniRios JuaniRios commented Apr 20, 2026

Problem

The non-scientific path in LibFormatDecimalFloat.toDecimalString reverts with UnformatableExponent when the exponent is outside [-76, 76], because 10 ** uint256(abs(exponent)) overflows uint256 at that range.

However, the library's own arithmetic operations (add, sub) can produce Floats with exponents outside this range through normal operations. Specifically, catastrophic cancellation when subtracting nearly-equal maximized values:

  1. add/sub call maximizeFull on both inputs, pushing coefficients to ~76 digits with very negative exponents (e.g., -76)
  2. Subtraction of nearly-equal maximized values produces a small coefficient at the same large negative exponent
  3. packLossy stores this as-is (small coefficient fits in int224)
  4. The resulting Float is valid for all operations except non-scientific formatting

Discovery

This was found in production: a market-making bot (st0x.liquidity) accumulated 605 position events via Float add/sub. The net position ended up with exponent -77, which crashed the application during serialization with UnformatableExponent.

Fix

Instead of reverting when the exponent is outside [-76, 76], truncate trailing coefficient digits by dividing by 10^(abs(exponent) - 76) and clamping the exponent to the boundary. This loses insignificant trailing precision (at the 10^-77+ scale) but produces a valid decimal string for any Float the arithmetic can create.

Testing

  • Updated existing tests that expected UnformatableExponent reverts — they now verify successful formatting with truncation
  • Added test for the exact case from production: coefficient=9999999910959448, exponent=-77
  • Added test for exponent=-78 (two digits of truncation)
  • All 395 non-fork tests pass (8 pre-existing fork test failures from missing CI env vars)
  • Fuzz tests (testFormatDecimalRoundTripNonNegative, testFormatDecimalRoundTripNegative) pass with 5096 runs each

The non-scientific path in `toDecimalString` reverted with
`UnformatableExponent` when the exponent was outside [-76, 76],
because `10 ** uint256(abs(exponent))` overflows uint256 at that
range. However, the library's own arithmetic operations (add, sub)
can produce Floats with exponents outside this range through normal
operations — particularly catastrophic cancellation when subtracting
nearly-equal values.

Fix: instead of reverting, truncate trailing coefficient digits to
bring the exponent within the formattable range. This loses
insignificant precision at the 10^-77+ scale but produces a valid
decimal string for any Float the arithmetic can create.

This was discovered in production: a market-making bot accumulated
605 position events via Float add/sub, producing a net position with
exponent -77 that crashed on serialization.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 20, 2026

Important

Review skipped

Draft detected.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: b10468c9-65a4-4366-ab81-65e75de17bc4

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/normalize-extreme-exponents-in-non-scientific-formatter

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Contributor Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@JuaniRios JuaniRios closed this Apr 20, 2026
@JuaniRios JuaniRios deleted the fix/normalize-extreme-exponents-in-non-scientific-formatter branch April 20, 2026 02:00
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