@@ -730,9 +730,9 @@ impl Duration {
730730 /// // subnormal float
731731 /// let res = Duration::from_secs_f64(f64::from_bits(1));
732732 /// assert_eq!(res, Duration::new(0, 0));
733- /// // conversion uses truncation, not rounding
733+ /// // conversion uses rounding
734734 /// 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 ));
736736 /// ```
737737 #[ stable( feature = "duration_float" , since = "1.38.0" ) ]
738738 #[ must_use]
@@ -760,17 +760,17 @@ impl Duration {
760760 /// let res = Duration::from_secs_f32(1e-20);
761761 /// assert_eq!(res, Duration::new(0, 0));
762762 /// 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 ));
764764 /// 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 ));
766766 /// let res = Duration::from_secs_f32(3e10);
767767 /// assert_eq!(res, Duration::new(30_000_001_024, 0));
768768 /// // subnormal float
769769 /// let res = Duration::from_secs_f32(f32::from_bits(1));
770770 /// assert_eq!(res, Duration::new(0, 0));
771- /// // conversion uses truncation, not rounding
771+ /// // conversion uses rounding
772772 /// 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 ));
774774 /// ```
775775 #[ stable( feature = "duration_float" , since = "1.38.0" ) ]
776776 #[ must_use]
@@ -815,7 +815,7 @@ impl Duration {
815815 /// use std::time::Duration;
816816 ///
817817 /// 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 ));
819819 /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847800, 0));
820820 /// ```
821821 #[ stable( feature = "duration_float" , since = "1.38.0" ) ]
@@ -838,8 +838,7 @@ impl Duration {
838838 ///
839839 /// let dur = Duration::new(2, 700_000_000);
840840 /// 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));
843842 /// ```
844843 #[ stable( feature = "duration_float" , since = "1.38.0" ) ]
845844 #[ must_use = "this returns the result of the operation, \
@@ -862,9 +861,8 @@ impl Duration {
862861 /// let dur = Duration::new(2, 700_000_000);
863862 /// // note that due to rounding errors result is slightly
864863 /// // 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));
868866 /// ```
869867 #[ stable( feature = "duration_float" , since = "1.38.0" ) ]
870868 #[ must_use = "this returns the result of the operation, \
@@ -1272,19 +1270,53 @@ macro_rules! try_from_secs {
12721270 let mant = ( bits & MANT_MASK ) | ( MANT_MASK + 1 ) ;
12731271 let exp = ( ( bits >> $mant_bits) & EXP_MASK ) as i16 + MIN_EXP ;
12741272
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
12771275 ( 0u64 , 0u32 )
12781276 } else if exp < 0 {
12791277 // the input is less than 1 second
12801278 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 ) }
12831295 } else if exp < $mant_bits {
1284- let secs = mant >> ( $mant_bits - exp) ;
1296+ let secs = u64 :: from ( mant >> ( $mant_bits - exp) ) ;
12851297 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+ }
12881320 } else if exp < 64 {
12891321 // the input has no fractional part
12901322 let secs = u64 :: from( mant) << ( exp - $mant_bits) ;
@@ -1315,24 +1347,45 @@ impl Duration {
13151347 /// let res = Duration::try_from_secs_f32(1e-20);
13161348 /// assert_eq!(res, Ok(Duration::new(0, 0)));
13171349 /// 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 )));
13191351 /// 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 )));
13211353 /// let res = Duration::try_from_secs_f32(3e10);
13221354 /// assert_eq!(res, Ok(Duration::new(30_000_001_024, 0)));
13231355 /// // subnormal float:
13241356 /// let res = Duration::try_from_secs_f32(f32::from_bits(1));
13251357 /// 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)));
13291358 ///
13301359 /// let res = Duration::try_from_secs_f32(-5.0);
13311360 /// assert!(res.is_err());
13321361 /// let res = Duration::try_from_secs_f32(f32::NAN);
13331362 /// assert!(res.is_err());
13341363 /// let res = Duration::try_from_secs_f32(2e19);
13351364 /// 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)));
13361389 /// ```
13371390 #[ unstable( feature = "duration_checked_float" , issue = "83400" ) ]
13381391 #[ inline]
@@ -1372,16 +1425,45 @@ impl Duration {
13721425 /// // subnormal float
13731426 /// let res = Duration::try_from_secs_f64(f64::from_bits(1));
13741427 /// 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)));
13781428 ///
13791429 /// let res = Duration::try_from_secs_f64(-5.0);
13801430 /// assert!(res.is_err());
13811431 /// let res = Duration::try_from_secs_f64(f64::NAN);
13821432 /// assert!(res.is_err());
13831433 /// let res = Duration::try_from_secs_f64(2e19);
13841434 /// 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)));
13851467 /// ```
13861468 #[ unstable( feature = "duration_checked_float" , issue = "83400" ) ]
13871469 #[ inline]
0 commit comments