@@ -730,9 +730,9 @@ impl Duration {
730
730
/// // subnormal float
731
731
/// let res = Duration::from_secs_f64(f64::from_bits(1));
732
732
/// assert_eq!(res, Duration::new(0, 0));
733
- /// // conversion uses truncation, not rounding
733
+ /// // conversion uses rounding
734
734
/// let res = Duration::from_secs_f64(0.999e-9);
735
- /// assert_eq!(res, Duration::new(0, 0 ));
735
+ /// assert_eq!(res, Duration::new(0, 1 ));
736
736
/// ```
737
737
#[ stable( feature = "duration_float" , since = "1.38.0" ) ]
738
738
#[ must_use]
@@ -760,17 +760,17 @@ impl Duration {
760
760
/// let res = Duration::from_secs_f32(1e-20);
761
761
/// assert_eq!(res, Duration::new(0, 0));
762
762
/// let res = Duration::from_secs_f32(4.2e-7);
763
- /// assert_eq!(res, Duration::new(0, 419 ));
763
+ /// assert_eq!(res, Duration::new(0, 420 ));
764
764
/// let res = Duration::from_secs_f32(2.7);
765
- /// assert_eq!(res, Duration::new(2, 700_000_047 ));
765
+ /// assert_eq!(res, Duration::new(2, 700_000_048 ));
766
766
/// let res = Duration::from_secs_f32(3e10);
767
767
/// assert_eq!(res, Duration::new(30_000_001_024, 0));
768
768
/// // subnormal float
769
769
/// let res = Duration::from_secs_f32(f32::from_bits(1));
770
770
/// assert_eq!(res, Duration::new(0, 0));
771
- /// // conversion uses truncation, not rounding
771
+ /// // conversion uses rounding
772
772
/// let res = Duration::from_secs_f32(0.999e-9);
773
- /// assert_eq!(res, Duration::new(0, 0 ));
773
+ /// assert_eq!(res, Duration::new(0, 1 ));
774
774
/// ```
775
775
#[ stable( feature = "duration_float" , since = "1.38.0" ) ]
776
776
#[ must_use]
@@ -815,7 +815,7 @@ impl Duration {
815
815
/// use std::time::Duration;
816
816
///
817
817
/// let dur = Duration::new(2, 700_000_000);
818
- /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_640 ));
818
+ /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_641 ));
819
819
/// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847800, 0));
820
820
/// ```
821
821
#[ stable( feature = "duration_float" , since = "1.38.0" ) ]
@@ -838,8 +838,7 @@ impl Duration {
838
838
///
839
839
/// let dur = Duration::new(2, 700_000_000);
840
840
/// assert_eq!(dur.div_f64(3.14), Duration::new(0, 859_872_611));
841
- /// // note that truncation is used, not rounding
842
- /// assert_eq!(dur.div_f64(3.14e5), Duration::new(0, 8_598));
841
+ /// assert_eq!(dur.div_f64(3.14e5), Duration::new(0, 8_599));
843
842
/// ```
844
843
#[ stable( feature = "duration_float" , since = "1.38.0" ) ]
845
844
#[ must_use = "this returns the result of the operation, \
@@ -862,9 +861,8 @@ impl Duration {
862
861
/// let dur = Duration::new(2, 700_000_000);
863
862
/// // note that due to rounding errors result is slightly
864
863
/// // different from 0.859_872_611
865
- /// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_579));
866
- /// // note that truncation is used, not rounding
867
- /// assert_eq!(dur.div_f32(3.14e5), Duration::new(0, 8_598));
864
+ /// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_580));
865
+ /// assert_eq!(dur.div_f32(3.14e5), Duration::new(0, 8_599));
868
866
/// ```
869
867
#[ stable( feature = "duration_float" , since = "1.38.0" ) ]
870
868
#[ must_use = "this returns the result of the operation, \
@@ -1272,19 +1270,53 @@ macro_rules! try_from_secs {
1272
1270
let mant = ( bits & MANT_MASK ) | ( MANT_MASK + 1 ) ;
1273
1271
let exp = ( ( bits >> $mant_bits) & EXP_MASK ) as i16 + MIN_EXP ;
1274
1272
1275
- let ( secs, nanos) = if exp < -30 {
1276
- // the input represents less than 1ns.
1273
+ let ( secs, nanos) = if exp < -31 {
1274
+ // the input represents less than 1ns and can not be rounded to it
1277
1275
( 0u64 , 0u32 )
1278
1276
} else if exp < 0 {
1279
1277
// the input is less than 1 second
1280
1278
let t = <$double_ty>:: from( mant) << ( $offset + exp) ;
1281
- let nanos = ( u128 :: from( NANOS_PER_SEC ) * u128 :: from( t) ) >> ( $mant_bits + $offset) ;
1282
- ( 0 , nanos as u32 )
1279
+ let nanos_offset = $mant_bits + $offset;
1280
+ let nanos_tmp = u128 :: from( NANOS_PER_SEC ) * u128 :: from( t) ;
1281
+ let nanos = ( nanos_tmp >> nanos_offset) as u32 ;
1282
+
1283
+ let rem_mask = ( 1 << nanos_offset) - 1 ;
1284
+ let rem_msb_mask = 1 << ( nanos_offset - 1 ) ;
1285
+ let rem = nanos_tmp & rem_mask;
1286
+ let is_tie = rem == rem_msb_mask;
1287
+ let is_even = ( nanos & 1 ) == 0 ;
1288
+ let rem_msb = nanos_tmp & rem_msb_mask == 0 ;
1289
+ let add_ns = !( rem_msb || ( is_even && is_tie) ) ;
1290
+
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.
1293
+ let nanos = nanos + add_ns as u32 ;
1294
+ if ( $mant_bits == 23 ) || ( nanos != NANOS_PER_SEC ) { ( 0 , nanos) } else { ( 1 , 0 ) }
1283
1295
} else if exp < $mant_bits {
1284
- let secs = mant >> ( $mant_bits - exp) ;
1296
+ let secs = u64 :: from ( mant >> ( $mant_bits - exp) ) ;
1285
1297
let t = <$double_ty>:: from( ( mant << exp) & MANT_MASK ) ;
1286
- let nanos = ( <$double_ty>:: from( NANOS_PER_SEC ) * t) >> $mant_bits;
1287
- ( u64 :: from( secs) , nanos as u32 )
1298
+ let nanos_offset = $mant_bits;
1299
+ let nanos_tmp = <$double_ty>:: from( NANOS_PER_SEC ) * t;
1300
+ let nanos = ( nanos_tmp >> nanos_offset) as u32 ;
1301
+
1302
+ let rem_mask = ( 1 << nanos_offset) - 1 ;
1303
+ let rem_msb_mask = 1 << ( nanos_offset - 1 ) ;
1304
+ let rem = nanos_tmp & rem_mask;
1305
+ let is_tie = rem == rem_msb_mask;
1306
+ let is_even = ( nanos & 1 ) == 0 ;
1307
+ let rem_msb = nanos_tmp & rem_msb_mask == 0 ;
1308
+ let add_ns = !( rem_msb || ( is_even && is_tie) ) ;
1309
+
1310
+ // f32 does not have enough presicion to trigger the second branch.
1311
+ // For example, it can not represent numbers between 1.999_999_880...
1312
+ // and 2.0. Bigger values result in even smaller presicion of the
1313
+ // fractional part.
1314
+ let nanos = nanos + add_ns as u32 ;
1315
+ if ( $mant_bits == 23 ) || ( nanos != NANOS_PER_SEC ) {
1316
+ ( secs, nanos)
1317
+ } else {
1318
+ ( secs + 1 , 0 )
1319
+ }
1288
1320
} else if exp < 64 {
1289
1321
// the input has no fractional part
1290
1322
let secs = u64 :: from( mant) << ( exp - $mant_bits) ;
@@ -1315,24 +1347,45 @@ impl Duration {
1315
1347
/// let res = Duration::try_from_secs_f32(1e-20);
1316
1348
/// assert_eq!(res, Ok(Duration::new(0, 0)));
1317
1349
/// let res = Duration::try_from_secs_f32(4.2e-7);
1318
- /// assert_eq!(res, Ok(Duration::new(0, 419 )));
1350
+ /// assert_eq!(res, Ok(Duration::new(0, 420 )));
1319
1351
/// let res = Duration::try_from_secs_f32(2.7);
1320
- /// assert_eq!(res, Ok(Duration::new(2, 700_000_047 )));
1352
+ /// assert_eq!(res, Ok(Duration::new(2, 700_000_048 )));
1321
1353
/// let res = Duration::try_from_secs_f32(3e10);
1322
1354
/// assert_eq!(res, Ok(Duration::new(30_000_001_024, 0)));
1323
1355
/// // subnormal float:
1324
1356
/// let res = Duration::try_from_secs_f32(f32::from_bits(1));
1325
1357
/// assert_eq!(res, Ok(Duration::new(0, 0)));
1326
- /// // conversion uses truncation, not rounding
1327
- /// let res = Duration::try_from_secs_f32(0.999e-9);
1328
- /// assert_eq!(res, Ok(Duration::new(0, 0)));
1329
1358
///
1330
1359
/// let res = Duration::try_from_secs_f32(-5.0);
1331
1360
/// assert!(res.is_err());
1332
1361
/// let res = Duration::try_from_secs_f32(f32::NAN);
1333
1362
/// assert!(res.is_err());
1334
1363
/// let res = Duration::try_from_secs_f32(2e19);
1335
1364
/// assert!(res.is_err());
1365
+ ///
1366
+ /// // the conversion uses rounding with tie resolution to even
1367
+ /// let res = Duration::try_from_secs_f32(0.999e-9);
1368
+ /// assert_eq!(res, Ok(Duration::new(0, 1)));
1369
+ ///
1370
+ /// // this float represents exactly 976562.5e-9
1371
+ /// let val = f32::from_bits(0x3A80_0000);
1372
+ /// let res = Duration::try_from_secs_f32(val);
1373
+ /// assert_eq!(res, Ok(Duration::new(0, 976_562)));
1374
+ ///
1375
+ /// // this float represents exactly 2929687.5e-9
1376
+ /// let val = f32::from_bits(0x3B40_0000);
1377
+ /// let res = Duration::try_from_secs_f32(val);
1378
+ /// assert_eq!(res, Ok(Duration::new(0, 2_929_688)));
1379
+ ///
1380
+ /// // this float represents exactly 1.000_976_562_5
1381
+ /// let val = f32::from_bits(0x3F802000);
1382
+ /// let res = Duration::try_from_secs_f32(val);
1383
+ /// assert_eq!(res, Ok(Duration::new(1, 976_562)));
1384
+ ///
1385
+ /// // this float represents exactly 1.002_929_687_5
1386
+ /// let val = f32::from_bits(0x3F806000);
1387
+ /// let res = Duration::try_from_secs_f32(val);
1388
+ /// assert_eq!(res, Ok(Duration::new(1, 2_929_688)));
1336
1389
/// ```
1337
1390
#[ unstable( feature = "duration_checked_float" , issue = "83400" ) ]
1338
1391
#[ inline]
@@ -1372,16 +1425,45 @@ impl Duration {
1372
1425
/// // subnormal float
1373
1426
/// let res = Duration::try_from_secs_f64(f64::from_bits(1));
1374
1427
/// assert_eq!(res, Ok(Duration::new(0, 0)));
1375
- /// // conversion uses truncation, not rounding
1376
- /// let res = Duration::try_from_secs_f32(0.999e-9);
1377
- /// assert_eq!(res, Ok(Duration::new(0, 0)));
1378
1428
///
1379
1429
/// let res = Duration::try_from_secs_f64(-5.0);
1380
1430
/// assert!(res.is_err());
1381
1431
/// let res = Duration::try_from_secs_f64(f64::NAN);
1382
1432
/// assert!(res.is_err());
1383
1433
/// let res = Duration::try_from_secs_f64(2e19);
1384
1434
/// assert!(res.is_err());
1435
+ ///
1436
+ /// // the conversion uses rounding with tie resolution to even
1437
+ /// let res = Duration::try_from_secs_f64(0.999e-9);
1438
+ /// assert_eq!(res, Ok(Duration::new(0, 1)));
1439
+ /// let res = Duration::try_from_secs_f64(0.999_999_999_499);
1440
+ /// assert_eq!(res, Ok(Duration::new(0, 999_999_999)));
1441
+ /// let res = Duration::try_from_secs_f64(0.999_999_999_501);
1442
+ /// assert_eq!(res, Ok(Duration::new(1, 0)));
1443
+ /// let res = Duration::try_from_secs_f64(42.999_999_999_499);
1444
+ /// assert_eq!(res, Ok(Duration::new(42, 999_999_999)));
1445
+ /// let res = Duration::try_from_secs_f64(42.999_999_999_501);
1446
+ /// assert_eq!(res, Ok(Duration::new(43, 0)));
1447
+ ///
1448
+ /// // this float represents exactly 976562.5e-9
1449
+ /// let val = f64::from_bits(0x3F50_0000_0000_0000);
1450
+ /// let res = Duration::try_from_secs_f64(val);
1451
+ /// assert_eq!(res, Ok(Duration::new(0, 976_562)));
1452
+ ///
1453
+ /// // this float represents exactly 2929687.5e-9
1454
+ /// let val = f64::from_bits(0x3F68_0000_0000_0000);
1455
+ /// let res = Duration::try_from_secs_f64(val);
1456
+ /// assert_eq!(res, Ok(Duration::new(0, 2_929_688)));
1457
+ ///
1458
+ /// // this float represents exactly 1.000_976_562_5
1459
+ /// let val = f64::from_bits(0x3FF0_0400_0000_0000);
1460
+ /// let res = Duration::try_from_secs_f64(val);
1461
+ /// assert_eq!(res, Ok(Duration::new(1, 976_562)));
1462
+ ///
1463
+ /// // this float represents exactly 1.002_929_687_5
1464
+ /// let val = f64::from_bits(0x3_FF00_C000_0000_000);
1465
+ /// let res = Duration::try_from_secs_f64(val);
1466
+ /// assert_eq!(res, Ok(Duration::new(1, 2_929_688)));
1385
1467
/// ```
1386
1468
#[ unstable( feature = "duration_checked_float" , issue = "83400" ) ]
1387
1469
#[ inline]
0 commit comments