@@ -1020,7 +1020,79 @@ impl Duration {
10201020 without modifying the original"]
10211021 #[ inline]
10221022 pub fn mul_f64 ( self , rhs : f64 ) -> Duration {
1023- Duration :: from_secs_f64 ( rhs * self . as_secs_f64 ( ) )
1023+ const DURATION_BITS : u32 = 64 + Duration :: SECOND . as_nanos ( ) . ilog2 ( ) + 1 ;
1024+
1025+ const NUM_BITS_MANT : u32 = f64:: MANTISSA_DIGITS - 1 ;
1026+ const NUM_BITS_EXP : u32 = 64 - f64:: MANTISSA_DIGITS ;
1027+
1028+ const SIGN_BIT : u64 = 1 << 63 ;
1029+ const MANT_IMPLIED_BIT : u64 = 1 << NUM_BITS_MANT ;
1030+ const MANT_MASK : u64 = MANT_IMPLIED_BIT - 1 ;
1031+ const EXP_MASK : u64 = ( 1 << NUM_BITS_EXP ) - 1 ;
1032+ const EXP_BIAS : i32 = 1 - ( 1 << NUM_BITS_EXP ) / 2 ;
1033+
1034+ let rhs_raw = rhs. to_bits ( ) ;
1035+ let mant_raw = rhs_raw & MANT_MASK ;
1036+ let exp_raw = ( rhs_raw >> NUM_BITS_MANT ) & EXP_MASK ;
1037+
1038+ if exp_raw == EXP_MASK {
1039+ panic ! ( "result is not finite" ) ;
1040+ }
1041+
1042+ if self . is_zero ( ) || rhs_raw & !SIGN_BIT == 0 {
1043+ // At least one factor is zero, so their product must be zero.
1044+ return Duration :: ZERO ;
1045+ }
1046+
1047+ let ( mant, biased_exp) = if exp_raw == 0 {
1048+ // `rhs` is subnormal. Renormalize by shifting so that the highest set bit is
1049+ // in the correct leading bit position.
1050+ let shift = mant_raw. leading_zeros ( ) - NUM_BITS_EXP ;
1051+ ( mant_raw << shift, 1 - shift as i32 )
1052+ } else {
1053+ // `rhs` is normal. Set the implied leading bit.
1054+ ( mant_raw | MANT_IMPLIED_BIT , exp_raw as i32 )
1055+ } ;
1056+
1057+ // From this point on, consider `mant` to be an integer of `f64::MANTISSA_DIGITS` bits,
1058+ // rather than a normalized fraction; therefore adjust the exponent by `NUM_BITS_MANT`.
1059+ let exp = biased_exp + EXP_BIAS - NUM_BITS_MANT as i32 ;
1060+ let mant = mant as u128 ;
1061+
1062+ let lhs_nanos = self . as_nanos ( ) ;
1063+
1064+ let nanos = if let Ok ( exp) = u32:: try_from ( exp) {
1065+ // `exp` is non-negative, therefore `rhs` has no fractional part. Mere integer
1066+ // multiplication is sufficient.
1067+ mant. checked_shl ( exp) . and_then ( |rhs_int| lhs_nanos. checked_mul ( rhs_int) )
1068+ } else {
1069+ let nexp = -exp as u32 ;
1070+ if nexp > DURATION_BITS + f64:: MANTISSA_DIGITS {
1071+ // `rhs` is such a small factor that it scales down any `Duration` to less than 0.5ns.
1072+ return Duration :: ZERO ;
1073+ }
1074+
1075+ let ( nexp_, start) = if nexp < 128 { ( nexp, 0 ) } else { ( nexp - 128 , 1 ) } ;
1076+
1077+ // Shift the mantissa across three values, in preparation for long multiplication.
1078+ let mut split = [ 0 ; 3 ] ;
1079+ split[ start..start + 2 ] . copy_from_slice ( & [ mant >> nexp_, mant << ( 128 - nexp_) ] ) ;
1080+
1081+ // Perform the long multiplication.
1082+ lhs_nanos. checked_mul ( split[ 0 ] ) . and_then ( |product| {
1083+ let ( _, carry) = lhs_nanos. carrying_mul ( split[ 2 ] , 0 ) ;
1084+ let ( frac, carry) = lhs_nanos. carrying_mul ( split[ 1 ] , carry) ;
1085+ let round_up = frac >> 127 ;
1086+ product. checked_add ( carry + round_up)
1087+ } )
1088+ }
1089+ . expect ( "result overflows `Duration`" ) ;
1090+
1091+ if nanos != 0 && rhs. is_sign_negative ( ) {
1092+ panic ! ( "result is negative" )
1093+ }
1094+
1095+ Duration :: from_nanos_u128 ( nanos)
10241096 }
10251097
10261098 /// Multiplies `Duration` by `f32`.
@@ -1033,15 +1105,15 @@ impl Duration {
10331105 /// use std::time::Duration;
10341106 ///
10351107 /// let dur = Duration::new(2, 700_000_000);
1036- /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_641 ));
1108+ /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_283 ));
10371109 /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847_800, 0));
10381110 /// ```
10391111 #[ stable( feature = "duration_float" , since = "1.38.0" ) ]
10401112 #[ must_use = "this returns the result of the operation, \
10411113 without modifying the original"]
10421114 #[ inline]
10431115 pub fn mul_f32 ( self , rhs : f32 ) -> Duration {
1044- Duration :: from_secs_f32 ( rhs * self . as_secs_f32 ( ) )
1116+ self . mul_f64 ( rhs. into ( ) )
10451117 }
10461118
10471119 /// Divides `Duration` by `f64`.
@@ -1062,7 +1134,98 @@ impl Duration {
10621134 without modifying the original"]
10631135 #[ inline]
10641136 pub fn div_f64 ( self , rhs : f64 ) -> Duration {
1065- Duration :: from_secs_f64 ( self . as_secs_f64 ( ) / rhs)
1137+ const DURATION_BITS : u32 = 64 + Duration :: SECOND . as_nanos ( ) . ilog2 ( ) + 1 ;
1138+
1139+ const NUM_BITS_MANT : u32 = f64:: MANTISSA_DIGITS - 1 ;
1140+ const NUM_BITS_EXP : u32 = 64 - f64:: MANTISSA_DIGITS ;
1141+
1142+ const SIGN_BIT : u64 = 1 << 63 ;
1143+ const MANT_IMPLIED_BIT : u64 = 1 << NUM_BITS_MANT ;
1144+ const MANT_MASK : u64 = MANT_IMPLIED_BIT - 1 ;
1145+ const EXP_MASK : u64 = ( 1 << NUM_BITS_EXP ) - 1 ;
1146+ const EXP_BIAS : i32 = 1 - ( 1 << NUM_BITS_EXP ) / 2 ;
1147+
1148+ let rhs_raw = rhs. to_bits ( ) ;
1149+
1150+ if rhs. is_nan ( ) || rhs_raw & !SIGN_BIT == 0 {
1151+ // `rhs` is either NaN or zero.
1152+ panic ! ( "result is not finite" ) ;
1153+ }
1154+
1155+ let mant_raw = rhs_raw & MANT_MASK ;
1156+ let exp_raw = ( rhs_raw >> NUM_BITS_MANT ) & EXP_MASK ;
1157+
1158+ if self . is_zero ( ) || exp_raw == EXP_MASK {
1159+ // Dividend is zero and/or divisor is infinite.
1160+ return Duration :: ZERO ;
1161+ }
1162+
1163+ let ( mant, biased_exp) = if exp_raw == 0 {
1164+ // `rhs` is subnormal. Renormalize by shifting so that the highest set bit is
1165+ // in the correct leading bit position.
1166+ let shift = mant_raw. leading_zeros ( ) - NUM_BITS_EXP ;
1167+ ( mant_raw << shift, 1 - shift as i32 )
1168+ } else {
1169+ // `rhs` is normal. Set the implied leading bit.
1170+ ( mant_raw | MANT_IMPLIED_BIT , exp_raw as i32 )
1171+ } ;
1172+
1173+ // From this point on, consider `mant` to be an integer of `f64::MANTISSA_DIGITS` bits,
1174+ // rather than a normalized fraction; therefore adjust the exponent by `NUM_BITS_MANT`.
1175+ let exp = biased_exp + EXP_BIAS - NUM_BITS_MANT as i32 ;
1176+ let mant = mant as u128 ;
1177+
1178+ let lhs_nanos = self . as_nanos ( ) ;
1179+
1180+ let nanos = if let Ok ( exp) = u32:: try_from ( exp) {
1181+ // `exp` is non-negative, therefore `rhs` has no fractional part. Mere integer
1182+ // division is sufficient.
1183+ ( lhs_nanos / mant) . unbounded_shr ( exp)
1184+ } else {
1185+ // `exp` is negative, therefore `rhs` has both integer and fractional parts.
1186+
1187+ // Calculate the first 127 bits of the reciprocal, and any remainder.
1188+ const MAX : u128 = 1 << 127 ;
1189+ let recip_q = MAX / mant;
1190+ let recip_r = MAX % mant;
1191+
1192+ // Calculate the next 127 bits of the reciprocal, and shift them into the most
1193+ // significant bits of a u128. Whilst the least significant bit may be incorrect, it is
1194+ // immaterial to the following calculation (it never funnels into `split`).
1195+ let recip_f = ( ( recip_q * recip_r) + ( recip_r * recip_r) / mant) << 1 ;
1196+
1197+ // Offset exponent by 1 because reciprocal is calculated as 2^127/mant,
1198+ // rather than 2^128/mant (which obviously requires greater width than u128).
1199+ let nexp = ( 1 - exp) as u32 ;
1200+ if nexp > DURATION_BITS + f64:: MANTISSA_DIGITS {
1201+ // `rhs` is such a small divisor that it scales up any `Duration` to overflow.
1202+ panic ! ( "result overflows `Duration`" ) ;
1203+ }
1204+
1205+ let ( nexp_, start) = if nexp < 128 { ( nexp, 1 ) } else { ( nexp - 128 , 0 ) } ;
1206+
1207+ // Shift the reciprocal across three values, in preparation for long multiplication.
1208+ let mut split = [ 0 ; 3 ] ;
1209+ split[ start..start + 2 ]
1210+ . copy_from_slice ( & [ recip_q >> ( 128 - nexp_) , recip_q. funnel_shl ( recip_f, nexp_) ] ) ;
1211+
1212+ // Perform the long multiplication.
1213+ lhs_nanos
1214+ . checked_mul ( split[ 1 ] )
1215+ . and_then ( |product| {
1216+ let ( _, carry) = lhs_nanos. carrying_mul ( split[ 0 ] , 0 ) ;
1217+ let ( frac, carry) = lhs_nanos. carrying_mul ( split[ 2 ] , carry) ;
1218+ let round_up = frac >> 127 ;
1219+ product. checked_add ( carry + round_up)
1220+ } )
1221+ . expect ( "result overflows `Duration`" )
1222+ } ;
1223+
1224+ if nanos != 0 && rhs. is_sign_negative ( ) {
1225+ panic ! ( "result is negative" )
1226+ }
1227+
1228+ Duration :: from_nanos_u128 ( nanos)
10661229 }
10671230
10681231 /// Divides `Duration` by `f32`.
@@ -1077,15 +1240,15 @@ impl Duration {
10771240 /// let dur = Duration::new(2, 700_000_000);
10781241 /// // note that due to rounding errors result is slightly
10791242 /// // different from 0.859_872_611
1080- /// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_580 ));
1243+ /// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_583 ));
10811244 /// assert_eq!(dur.div_f32(3.14e5), Duration::new(0, 8_599));
10821245 /// ```
10831246 #[ stable( feature = "duration_float" , since = "1.38.0" ) ]
10841247 #[ must_use = "this returns the result of the operation, \
10851248 without modifying the original"]
10861249 #[ inline]
10871250 pub fn div_f32 ( self , rhs : f32 ) -> Duration {
1088- Duration :: from_secs_f32 ( self . as_secs_f32 ( ) / rhs)
1251+ self . div_f64 ( rhs. into ( ) )
10891252 }
10901253
10911254 /// Divides `Duration` by `Duration` and returns `f64`.
0 commit comments