@@ -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, \
@@ -1278,13 +1276,30 @@ macro_rules! try_from_secs {
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+ if nanos_tmp & ( 1 << ( nanos_offset - 1 ) ) == 0 {
1283+ ( 0 , nanos)
1284+ } else if nanos + 1 != NANOS_PER_SEC {
1285+ ( 0 , nanos + 1 )
1286+ } else {
1287+ ( 1 , 0 )
1288+ }
12831289 } else if exp < $mant_bits {
1284- let secs = mant >> ( $mant_bits - exp) ;
1290+ let secs = u64 :: from ( mant >> ( $mant_bits - exp) ) ;
12851291 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 )
1292+ let nanos_tmp = <$double_ty>:: from( NANOS_PER_SEC ) * t;
1293+ let nanos = ( nanos_tmp >> $mant_bits) as u32 ;
1294+ if nanos_tmp & ( 1 << ( $mant_bits - 1 ) ) == 0 {
1295+ ( secs, nanos)
1296+ } else if nanos + 1 != NANOS_PER_SEC {
1297+ ( secs, nanos + 1 )
1298+ } else {
1299+ // `secs + 1` can not overflow since `exp` is less than `$mant_bits`
1300+ // and the latter is less than 64 bits for both `f32` and `f64`
1301+ ( secs + 1 , 0 )
1302+ }
12881303 } else if exp < 64 {
12891304 // the input has no fractional part
12901305 let secs = u64 :: from( mant) << ( exp - $mant_bits) ;
@@ -1315,17 +1330,17 @@ impl Duration {
13151330 /// let res = Duration::try_from_secs_f32(1e-20);
13161331 /// assert_eq!(res, Ok(Duration::new(0, 0)));
13171332 /// let res = Duration::try_from_secs_f32(4.2e-7);
1318- /// assert_eq!(res, Ok(Duration::new(0, 419 )));
1333+ /// assert_eq!(res, Ok(Duration::new(0, 420 )));
13191334 /// let res = Duration::try_from_secs_f32(2.7);
1320- /// assert_eq!(res, Ok(Duration::new(2, 700_000_047 )));
1335+ /// assert_eq!(res, Ok(Duration::new(2, 700_000_048 )));
13211336 /// let res = Duration::try_from_secs_f32(3e10);
13221337 /// assert_eq!(res, Ok(Duration::new(30_000_001_024, 0)));
13231338 /// // subnormal float:
13241339 /// let res = Duration::try_from_secs_f32(f32::from_bits(1));
13251340 /// assert_eq!(res, Ok(Duration::new(0, 0)));
1326- /// // conversion uses truncation, not rounding
1341+ /// // conversion uses rounding
13271342 /// let res = Duration::try_from_secs_f32(0.999e-9);
1328- /// assert_eq!(res, Ok(Duration::new(0, 0 )));
1343+ /// assert_eq!(res, Ok(Duration::new(0, 1 )));
13291344 ///
13301345 /// let res = Duration::try_from_secs_f32(-5.0);
13311346 /// assert!(res.is_err());
@@ -1372,9 +1387,9 @@ impl Duration {
13721387 /// // subnormal float
13731388 /// let res = Duration::try_from_secs_f64(f64::from_bits(1));
13741389 /// assert_eq!(res, Ok(Duration::new(0, 0)));
1375- /// // conversion uses truncation, not rounding
1390+ /// // conversion uses rounding
13761391 /// let res = Duration::try_from_secs_f32(0.999e-9);
1377- /// assert_eq!(res, Ok(Duration::new(0, 0 )));
1392+ /// assert_eq!(res, Ok(Duration::new(0, 1 )));
13781393 ///
13791394 /// let res = Duration::try_from_secs_f64(-5.0);
13801395 /// assert!(res.is_err());
0 commit comments