Skip to content

Commit 38609cd

Browse files
committed
fix nanos overflow for f64
1 parent 06af3a6 commit 38609cd

File tree

1 file changed

+24
-9
lines changed

1 file changed

+24
-9
lines changed

library/core/src/time.rs

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1288,12 +1288,14 @@ macro_rules! try_from_secs {
12881288
let rem_msb = nanos_tmp & rem_msb_mask == 0;
12891289
let add_ns = !(rem_msb || (is_even && is_tie));
12901290

1291-
// note that neither `f32`, nor `f64` can represent
1292-
// 0.999_999_999_5 exactly, so the nanos part
1293-
// never will be equal to NANOS_PER_SEC
1291+
// f32 does not have enough presicion to trigger the second branch
1292+
// since it can not represent numbers between 0.999_999_940_395 and 1.0.
12941293
let nanos = nanos + add_ns as u32;
1295-
debug_assert!(nanos < NANOS_PER_SEC);
1296-
(0, nanos)
1294+
if ($mant_bits == 23) || (nanos != NANOS_PER_SEC) {
1295+
(0, nanos)
1296+
} else {
1297+
(1, 0)
1298+
}
12971299
} else if exp < $mant_bits {
12981300
let secs = u64::from(mant >> ($mant_bits - exp));
12991301
let t = <$double_ty>::from((mant << exp) & MANT_MASK);
@@ -1309,11 +1311,16 @@ macro_rules! try_from_secs {
13091311
let rem_msb = nanos_tmp & rem_msb_mask == 0;
13101312
let add_ns = !(rem_msb || (is_even && is_tie));
13111313

1312-
// neither `f32`, nor `f64` can represent x.999_999_999_5 exactly,
1313-
// so the nanos part never will be equal to NANOS_PER_SEC
1314+
// f32 does not have enough presicion to trigger the second branch.
1315+
// For example, it can not represent numbers between 1.999_999_880...
1316+
// and 2.0. Bigger values result in even smaller presicion of the
1317+
// fractional part.
13141318
let nanos = nanos + add_ns as u32;
1315-
debug_assert!(nanos < NANOS_PER_SEC);
1316-
(secs, nanos)
1319+
if ($mant_bits == 23) || (nanos != NANOS_PER_SEC) {
1320+
(secs, nanos)
1321+
} else {
1322+
(secs + 1, 0)
1323+
}
13171324
} else if exp < 64 {
13181325
// the input has no fractional part
13191326
let secs = u64::from(mant) << (exp - $mant_bits);
@@ -1433,6 +1440,14 @@ impl Duration {
14331440
/// // the conversion uses rounding with tie resolution to even
14341441
/// let res = Duration::try_from_secs_f64(0.999e-9);
14351442
/// assert_eq!(res, Ok(Duration::new(0, 1)));
1443+
/// let res = Duration::try_from_secs_f64(0.999_999_999_499);
1444+
/// assert_eq!(res, Ok(Duration::new(0, 999_999_999)));
1445+
/// let res = Duration::try_from_secs_f64(0.999_999_999_501);
1446+
/// assert_eq!(res, Ok(Duration::new(1, 0)));
1447+
/// let res = Duration::try_from_secs_f64(42.999_999_999_499);
1448+
/// assert_eq!(res, Ok(Duration::new(42, 999_999_999)));
1449+
/// let res = Duration::try_from_secs_f64(42.999_999_999_501);
1450+
/// assert_eq!(res, Ok(Duration::new(43, 0)));
14361451
///
14371452
/// // this float represents exactly 976562.5e-9
14381453
/// let val = f64::from_bits(0x3F50_0000_0000_0000);

0 commit comments

Comments
 (0)