GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — feat: switch grisu2 float-to-string algorithm to hybrid of xjb & zmij algorithms by JairusSW · Pull Request #3025 · AssemblyScript/assemblyscript

Conversation

@JairusSW

@JairusSW JairusSW commented Jun 9, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

Fixes #3012.

Changes proposed in this pull request:

  • Switch to xjb-as which is an improvement over zmij-as
  • Comply to the ECMA262 Specification with the exception of a trailing .0

Note: I wrote xjb-as with claude assisting me for an initial port. I then optimized by hand. Everything is carefully checked and passes over a trillion fuzz cases compared directly against Number::parse() in V8. It also reaches 100% code coverage and tests every edge case both I and claude could think of.

It's good quality stuff though, and I'm quite confident in that.

Current implementation measurements from independent review of 0c115329 against b6bda05, including the exact-integer string path. These are diagnostic results for the stated engine, machine, runtime, and workloads.

Generated Wasm size for tiny modules exporting f64.toString(), f32.toString(), or both, compiled with -O --noAssert --runtime stub:

Types used Base PR Increase
f64 only 4,122 B 7,319 B +3,197 B
f32 only 4,120 B 5,690 B +1,570 B
Both 4,342 B 10,690 B +6,348 B

With the default incremental runtime, the both-width module grows from 6,834 B to 13,248 B (+6,414 B). These small formatter-focused modules do not estimate whole-application growth. The generated string wrappers call shared buffered formatters; the exact-integer direct-allocation path adds specialized code.

Throughput on Node 24.22.1, x86-64 AMD EPYC 9V74, default incremental runtime, scalar builds: 4,096 inputs per bucket, 150,000 warmup operations, and medians of seven alternating base/PR samples of 400,000 operations. The timed loops run inside Wasm.

Input bucket API Base, ns/value PR, ns/value Speedup
Small signed integers f64 buffered 43.6 10.1 4.31×
Small signed integers f32 buffered 46.1 9.8 4.71×
Small signed integers f64 string 89.6 50.6 1.77×
Small signed integers f32 string 85.1 48.4 1.76×
Ordinary decimals f64 buffered 52.5 38.6 1.36×
Ordinary decimals f32 buffered 55.0 27.5 2.00×
Ordinary decimals f64 string 96.0 96.4 Effectively unchanged
Ordinary decimals f32 string 100.9 85.5 1.18×
Random finite bit patterns f64 buffered 82.9 48.0 1.73×
Random finite bit patterns f32 buffered 68.6 27.7 2.47×
Random finite bit patterns f64 string 132.1 93.1 1.42×
Random finite bit patterns f32 string 132.6 87.4 1.52×

Ordinary decimals are nonintegral values roughly between −1,000 and +1,000, formed by dividing integers by 1,000. Gains are strongest for buffered formatting and integers; complete-string performance varies with workload. The 96.0 → 96.4 ns ordinary-decimal f64 result is effectively flat, not a meaningful measured regression.

A separate SIMD diagnostic run improved random-finite buffered formatting by 2.31× (f64) and 2.75× (f32) against its own interleaved baseline. Ordinary-decimal f64 string output improved by about 6% in that run.

Correctness validation at this revision includes exact BigInt binary32 rounding intervals with ties-to-even, the four formerly double-rounded f32 regressions, all four checked-in debug/release × scalar/SIMD configurations (556,880 exact output comparisons), 28-code-unit canaries, the float-array join allocation budget, and independent verification of all 618 cached powers. Independent review also checked 28,076 cases against C++ std::to_chars(float, scientific) and 12,384 additional boundary comparisons across the buffered, ordinary string, and low-level string paths. These are substantial checks, not an exhaustive proof over all floating-point bit patterns.

  • I've read the contributing guidelines
  • I've added my name and email to the NOTICE file

P.S. Sorry about the diff. Most of it is generated WAT fixtures.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
JairusSW added 3 commits June 8, 2026 21:45
@JairusSW
chore: add xjb-as to util
5705f06
Signed-off-by: Jairus Tanaka <[email protected]>
@JairusSW
chore: add liceses to NOTICE
c778be9
Signed-off-by: Jairus Tanaka <[email protected]>
@JairusSW
chore: update changed tests
1fdc61d
Signed-off-by: Jairus Tanaka <[email protected]>
@JairusSW
JairusSW marked this pull request as draft June 9, 2026 06:04
JairusSW added 5 commits June 16, 2026 16:00
@JairusSW
chore: simplify and use smaller tables
09c3ef8
@JairusSW
chore: use table from number instead
7cd14a4
@JairusSW
chore: update notice
e0646ff
@JairusSW
chore: clean up
650a7c3
@JairusSW
chore: clean up
759c01f
@JairusSW
JairusSW marked this pull request as ready for review June 17, 2026 18:13
@PaperPrototype

PaperPrototype commented Jun 17, 2026

Copy link
Copy Markdown

Just curious here, why the exception of a trailing .0?

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@JairusSW

JairusSW commented Jun 17, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member Author

Just curious here, why the exception of a trailing .0?

Max and Dan made that decision so that floats are easily identifiable when converting them to a string. For example, you know that the string "1.0" is a result of f64.toString() while the string "1" is likely a result of i32.toString(). Slight deviation from ECMA262-spec, but it's not awful

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@MaxGraey

MaxGraey commented Jun 17, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Member

Can you rename xjb.ts to dtoa.ts and in comments mentioned about implementation based on xjb and zmij? xjb filename is very exotic and doesn't explains exactly what this file does

JairusSW reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

MaxGraey
MaxGraey reviewed Jun 17, 2026
View reviewed changes
Comment thread std/assembly/util/dtoa.ts Resolved

Uh oh!

There was an error while loading. Please reload this page.

@JairusSW
chore: rename to dtoa.ts and remove XJB_SIMD toggle
fa93c15
MaxGraey
MaxGraey reviewed Jun 17, 2026
View reviewed changes
Comment thread std/assembly/util/xjb.ts Resolved

Uh oh!

There was an error while loading. Please reload this page.

MaxGraey
MaxGraey reviewed Jun 17, 2026
View reviewed changes
Comment thread std/assembly/util/dtoa.ts Resolved

Uh oh!

There was an error while loading. Please reload this page.

MaxGraey
MaxGraey reviewed Jun 17, 2026
View reviewed changes
Comment thread std/assembly/util/dtoa.ts Resolved

Uh oh!

There was an error while loading. Please reload this page.

MaxGraey
MaxGraey reviewed Jun 17, 2026
View reviewed changes
Comment thread std/assembly/util/dtoa.ts Resolved

Uh oh!

There was an error while loading. Please reload this page.

JairusSW and others added 2 commits June 17, 2026 16:23
@JairusSW @MaxGraey
Update std/assembly/util/dtoa.ts
d41ce13
Co-authored-by: Max Graey <[email protected]>
@JairusSW @MaxGraey
Update std/assembly/util/dtoa.ts
4aa4210
Co-authored-by: Max Graey <[email protected]>
MaxGraey
MaxGraey reviewed Jun 17, 2026
View reviewed changes
Comment thread std/assembly/util/dtoa.ts Resolved

Uh oh!

There was an error while loading. Please reload this page.

MaxGraey
MaxGraey reviewed Jun 17, 2026
View reviewed changes
Comment thread std/assembly/util/dtoa.ts Resolved

Uh oh!

There was an error while loading. Please reload this page.

MaxGraey
MaxGraey reviewed Jun 17, 2026
View reviewed changes
Comment thread std/assembly/util/dtoa.ts Resolved

Uh oh!

There was an error while loading. Please reload this page.

MaxGraey
MaxGraey reviewed Jun 17, 2026
View reviewed changes
Comment thread std/assembly/util/dtoa.ts Resolved

Uh oh!

There was an error while loading. Please reload this page.

MaxGraey
MaxGraey reviewed Jun 17, 2026
View reviewed changes
Comment thread std/assembly/util/dtoa.ts Resolved

Uh oh!

There was an error while loading. Please reload this page.

@JairusSW @MaxGraey
Update std/assembly/util/dtoa.ts
48f3ee5
Co-authored-by: Max Graey <[email protected]>
dcodeIO
dcodeIO reviewed Jun 17, 2026
View reviewed changes
Comment thread tests/compiler/bindings/raw.release.wat Resolved

Uh oh!

There was an error while loading. Please reload this page.

MaxGraey
MaxGraey reviewed Jun 17, 2026
View reviewed changes
Comment thread std/assembly/util/dtoa.ts Resolved

Uh oh!

There was an error while loading. Please reload this page.

@JairusSW @MaxGraey
Update std/assembly/util/dtoa.ts
5dd492b
Co-authored-by: Max Graey <[email protected]>
MaxGraey
MaxGraey reviewed Jun 18, 2026
View reviewed changes
Comment thread std/assembly/util/dtoa.ts Resolved

Uh oh!

There was an error while loading. Please reload this page.

MaxGraey
MaxGraey reviewed Jun 18, 2026
View reviewed changes
Comment thread std/assembly/util/dtoa.ts Resolved

Uh oh!

There was an error while loading. Please reload this page.

MaxGraey
MaxGraey reviewed Jun 18, 2026
View reviewed changes
Comment thread std/assembly/util/dtoa.ts Resolved

Uh oh!

There was an error while loading. Please reload this page.

@MaxGraey

MaxGraey commented Jun 18, 2026

Copy link
Copy Markdown
Member

Also plz add extra tests which cover new implementation-specific edge cases (I anready found a bug) and uncomment existing test cases which failed with grisu2

JairusSW reacted with thumbs up emoji
All reactions
  • 👍 1 reaction

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

JairusSW and others added 20 commits June 23, 2026 20:29
@JairusSW
chore: use more descriptive names
43dbf58
@JairusSW
Merge branch 'jairus/switch-to-xjb' of github.com:JairusSW/assemblysc…
c5c6e07
…ript into jairus/switch-to-xjb
@JairusSW
fix: correct dtoa digit counts and shortest formatting
d93842f
@JairusSW
Merge origin/main into jairus/switch-to-xjb
644040a
@JairusSW
fix: finalize float formatting and review cleanup
a28f957
@JairusSW
Avoid emitting unused dtoa globals in debug output
c13739d
@JairusSW
Optimize float formatting fast paths and validate scalar/SIMD output
42ff464
@JairusSW
Cover f32 exact-integer fast-path boundary
859401d
@JairusSW
Optimize SIMD digit packing and normalized f64 formatting
cf6bad1
@JairusSW
Use SIMD digit packing for long integer formatting
f516ed4
@JairusSW
Use full dtoa power cache in speed builds
c9f8b9c
@JairusSW
Speed up subnormal f32 digit scaling
fdbc7ed
@JairusSW
Use compact power cache in all builds
1079de4
@JairusSW
Reuse float power cache for common doubles
ed4390a
@JairusSW
Share minor powers with float cache
055a82d
@JairusSW
Use one shared power table in every build
f39d7b7
@JairusSW
Trim shared power table to common f64 range
dcab81e
@JairusSW
Use compact power cache outside common exponents
881a8ec
@JairusSW
Test exact dtoa output and compact powers
84f5f2f
@JairusSW
Speed up exact-integer string formatting
660bd25
@JairusSW JairusSW self-assigned this Oct 21, 2026
@JairusSW JairusSW added performance standard library labels Oct 21, 2026
@JairusSW
JairusSW force-pushed the jairus/switch-to-xjb branch from 220f9c4 to 660bd25 Compare October 30, 2026 18:27
JairusSW added 2 commits October 30, 2026 14:34
@JairusSW
fix: correct f32 oracle rounding and float join capacity
0c11532
@JairusSW
fix: size float scratch buffer from its documented bound
f97f67d

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@dcodeIO dcodeIO dcodeIO left review comments
@MaxGraey MaxGraey MaxGraey left review comments

Uh oh!

There was an error while loading. Please reload this page.

Assignees

@JairusSW JairusSW

Labels

performance standard library

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

[Task] Replace Grisu2 with Xjb for float-to-string conversion

Uh oh!

There was an error while loading. Please reload this page.

4 participants

@JairusSW @PaperPrototype @MaxGraey @dcodeIO
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.
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.