Add new i128 unit tests & patch-01 #92
Open
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.
7 tests fails that should pass
Proof that the current implementation has major issues
Impact / Severity
i128.fromBits32-Bit Shift forhi2clzwith High Bit Set (i128)fromStringPerformancePatch-01 (fromBits)
1. How Sign Extension Works (i32 → i64)
Let’s say you have a 32-bit signed integer (
i32) whose bits look like this:-2(i32).i32toi64, the language will sign-extend the value to 64 bits. That means it copies the leftmost bit (the sign bit,1in this case) to the newly added high bits.As a result, the 64-bit (
i64) pattern becomes:Thus, in decimal, this is still
-2as ani64, which might not be what you want if you needed the original bits as-is.2. How Zero Extension Works (i32 → u32 → i64)
If your goal is to preserve the exact 32 bits without interpreting them as signed, the usual trick is:
Cast
i32→u32: Sinceu32is an unsigned 32-bit integer, no sign extension occurs. The bit pattern is treated as a non-negative number in 32 bits.Then cast
u32→i64(oru64→i64), which zero-extends to 64 bits. It fills the newly created high bits with0instead of copying the sign bit.Following the same example (
-2ini32, which is11111111 11111111 11111111 11111110):i32 (
-2) → u32:The same bit pattern reinterpreted as unsigned yields
but this time it’s considered
u32, noti32. There’s no negative concept here—just bits.u32 → i64:
When you cast this
u32to ani64, the language zero-extends, producing:Now, numerically, this is
4294967294as ani64, which exactly preserves the original lower 32 bits without sign extension.In other words, you get a value that strictly matches the original 32 bits but in a 64-bit container.
3. Why This Matters
i32tou32first forces the language to treat those 32 bits as an unsigned quantity. Any further expansion to 64 bits will keep them exactly as they appear.i32 → i64can lead to undesired negative values if the sign bit ofi32was1.4. Masking Alternative:
& 0xFFFFFFFFAnother common technique is using a bitmask:
This manually zeros out any higher bits when interpreted as signed, effectively doing the same job as
i32 → u32 → i64. Under the hood:x & 0xFFFFFFFFchopsxdown to 32 bits in an unsigned sense.i64afterward prevents sign extension, because the upper 32 bits are now zero.But conceptually, doing
i32 → u32 → i64orx & 0xFFFFFFFF→i64is the same idea: no sign extension—just the raw 32 bits in a bigger integer.