-
Notifications
You must be signed in to change notification settings - Fork 41
Closed
Labels
Description
Description
The function umul192_lower128
, used in writing floats, can overflow in rare circumstances in the following logic:
hi + (hi_lo >> 64) as u64
The wrapping is actually desired, as shown by the failing test case.
#[inline(always)]
pub const fn umul192_lower128(x: u64, yhi: u64, ylo: u64) -> (u64, u64) {
let hi = x.wrapping_mul(yhi);
let hi_lo = x as u128 * ylo as u128;
(hi + (hi_lo >> 64) as u64, hi_lo as u64)
}
umul192_lower128(15966911296221875, 0xcccccccccccccccc, 0xcccccccccccccccd);
In Python code, we have the same logic with the following:
>>> x = 15966911296221875
>>> yhi = 0xcccccccccccccccc
>>> ylo = 0xcccccccccccccccd
>>> y = (yhi << 64) + ylo
>>> z = x * y
>>> print(z & (2**128 - 1))
3193382259244375
This means hi + (hi_lo >> 64) as u64
is expected to wrap.
Prerequisites
Here are a few things you should provide to help me understand the issue:
- Rust version:
rustc 1.62.0-nightly (6dd68402c 2022-05-11)
- lexical version: lexical-write-float v0.8.4
- lexical compilation features used: default
Test case
Please provide a short, complete (with crate import, etc) test case for
the issue, showing clearly the expected and obtained results.
Example test case:
#[inline(always)]
pub const fn umul192_lower128(x: u64, yhi: u64, ylo: u64) -> (u64, u64) {
let hi = x.wrapping_mul(yhi);
let hi_lo = x as u128 * ylo as u128;
(hi + (hi_lo >> 64) as u64, hi_lo as u64)
}
fn main() {
umul192_lower128(15966911296221875, 14757395258967641292, 14757395258967641293);
}