Skip to content

fix: updatedMaxValue inflates maxValue when lowestDiscernibleValue > 1 - #59

Open
alexvictoor wants to merge 1 commit into
masterfrom
fix/updated-max-value
Open

alexvictoor wants to merge 1 commit into
masterfrom
fix/updated-max-value

Conversation

@alexvictoor

Copy link
Copy Markdown
Member

Problem

The Java original tracks the maximum as value | unitMagnitudeMask, setting the low unitMagnitude bits so the stored maximum is the top of the finest resolvable range. Both ports in this repo did value + unitMagnitudeMask instead:

  • src/JsHistogram.ts (updatedMaxValue)
  • assembly/Histogram.ts (updatedMaxValue)

With lowestDiscernibleValue: 1 the mask is 0 and the two agree, so the default path was unaffected. With a larger lowest (e.g. 1000, the event-loop-delay convention, mask = 511), a value whose low bits are already partly set gets inflated by up to one mask width: recording 9,999,000,063 reported maxValue 9,999,000,574 instead of 9,999,000,063.

Only the maxValue getter and the percentile-distribution footer are affected; percentiles, mean, stddev and the iterators read the counts array and were always correct.

Fix

  • TypeScript: arithmetic equivalent of the OR (floor(value / 2^unitMagnitude) * 2^unitMagnitude + mask), since bitwise | truncates to 32 bits in JavaScript and values can exceed that.
  • AssemblyScript: plain u64 OR.
  • Regression tests on both sides with lowest: 1000, covering a value with partially-set low bits and one with the low bits already all set.

Tests

  • npm test: 181 passed
  • npm run astest:ci: 113/113

🤖 Generated with Claude Code

The Java original tracks the maximum as value | unitMagnitudeMask, setting
the low unitMagnitude bits so the stored maximum is the top of the finest
resolvable range. Both the TypeScript and AssemblyScript ports did
value + unitMagnitudeMask instead, which over-reports maxValue by up to one
mask width whenever the low bits are already partly set (e.g. +511 with the
event-loop-delay default lowest of 1000).

The TypeScript fix is arithmetic (floor-divide, multiply, add mask) because
bitwise OR truncates to 32 bits in JavaScript; the AssemblyScript port uses
a plain u64 OR.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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