1919//! assert_eq!(total, Duration::new(10, 7));
2020//! ```
2121
22- use crate :: fmt;
2322use crate :: iter:: Sum ;
2423use crate :: num:: niche_types:: Nanoseconds ;
2524use crate :: ops:: { Add , AddAssign , Div , DivAssign , Mul , MulAssign , Sub , SubAssign } ;
25+ use crate :: { fmt, hint} ;
2626
2727const NANOS_PER_SEC : u32 = 1_000_000_000 ;
2828const NANOS_PER_MILLI : u32 = 1_000_000 ;
@@ -1018,7 +1018,79 @@ impl Duration {
10181018 without modifying the original"]
10191019 #[ inline]
10201020 pub fn mul_f64 ( self , rhs : f64 ) -> Duration {
1021- Duration :: from_secs_f64 ( rhs * self . as_secs_f64 ( ) )
1021+ if rhs < 0.0 {
1022+ // Ideally we'd always panic here, however we wish to preserve the stabilized behavior.
1023+ if self . as_secs_f64 ( ) * rhs != 0.0 {
1024+ panic ! ( "{}" , TryFromFloatSecsError { kind: TryFromFloatSecsErrorKind :: Negative } ) ;
1025+ } else {
1026+ return Duration :: ZERO ;
1027+ }
1028+ }
1029+ if !rhs. is_finite ( ) {
1030+ panic ! ( "{}" , TryFromFloatSecsError { kind: TryFromFloatSecsErrorKind :: OverflowOrNan } ) ;
1031+ }
1032+
1033+ let lhs_nanos = self . as_nanos ( ) ;
1034+ if lhs_nanos == 0 || rhs == 0.0 {
1035+ return Duration :: ZERO ;
1036+ }
1037+
1038+ let lhs_log2 = lhs_nanos. ilog2 ( ) as i32 ;
1039+ let ( rhs_significand, rhs_log2) = f64_normalize ( rhs) ;
1040+
1041+ let prod_log2_floor = lhs_log2 + rhs_log2;
1042+ if prod_log2_floor > Duration :: MAX . as_nanos ( ) . ilog2 ( ) as i32 {
1043+ // Product is definitely more than Duration::MAX
1044+ panic ! ( "{}" , TryFromFloatSecsError { kind: TryFromFloatSecsErrorKind :: OverflowOrNan } ) ;
1045+ }
1046+
1047+ let prod_log2_ceil = prod_log2_floor + 1 ;
1048+ if prod_log2_ceil < -1 {
1049+ // Product is definitely less than 0.5ns
1050+ return Duration :: ZERO ;
1051+ }
1052+
1053+ // Denormalize to a purely integer significand.
1054+ let exp = rhs_log2 + 1 - f64:: MANTISSA_DIGITS as i32 ;
1055+ let rhs_significand = rhs_significand as u128 ;
1056+
1057+ let nanos = if exp >= 0 {
1058+ // `rhs` has no fractional precision, so mere integer multiplication is sufficient.
1059+ ( lhs_nanos * rhs_significand) << exp
1060+ } else {
1061+ // Perform long-multiplication to calculate the 2 most significant 128-bit chunks of the
1062+ // product: hi (most significant) and lo (least significant).
1063+ let ( lo, hi) = lhs_nanos. carrying_mul ( rhs_significand, 0 ) ;
1064+
1065+ let nexp = -exp as u32 ;
1066+
1067+ if nexp < 128 {
1068+ // The result spans the two chunks, hi and lo; shift their concatenation down.
1069+ // The rounding bit is the most significant from lo that was shifted out of the
1070+ // result.
1071+ debug_assert ! ( nexp > 128 - hi. leading_zeros( ) ) ;
1072+ let round_up = ( lo >> ( nexp - 1 ) ) & 1 ;
1073+ hi. funnel_shr ( lo, nexp) + round_up
1074+ } else {
1075+ // The result is entirely within the most significant chunk, hi; implicitly shift
1076+ // down by discarding the least significant chunk, lo.
1077+ let shift = nexp - 128 ;
1078+ let round_up = if let Some ( one_shift_less) = shift. checked_sub ( 1 ) {
1079+ // Bits were shifted from hi; the most significant of them is the rounding bit.
1080+ ( hi >> one_shift_less) & 1
1081+ } else {
1082+ // No shift; the most significant bit from discarded lo is the rounding bit.
1083+ lo >> 127
1084+ } ;
1085+ ( hi >> shift) + round_up
1086+ }
1087+ } ;
1088+
1089+ if nanos > Duration :: MAX . as_nanos ( ) {
1090+ panic ! ( "{}" , TryFromFloatSecsError { kind: TryFromFloatSecsErrorKind :: OverflowOrNan } ) ;
1091+ }
1092+
1093+ Duration :: from_nanos_u128 ( nanos)
10221094 }
10231095
10241096 /// Multiplies `Duration` by `f32`.
@@ -1031,15 +1103,15 @@ impl Duration {
10311103 /// use std::time::Duration;
10321104 ///
10331105 /// let dur = Duration::new(2, 700_000_000);
1034- /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_641 ));
1106+ /// assert_eq!(dur.mul_f32(3.14), Duration::new(8, 478_000_283 ));
10351107 /// assert_eq!(dur.mul_f32(3.14e5), Duration::new(847_800, 0));
10361108 /// ```
10371109 #[ stable( feature = "duration_float" , since = "1.38.0" ) ]
10381110 #[ must_use = "this returns the result of the operation, \
10391111 without modifying the original"]
10401112 #[ inline]
10411113 pub fn mul_f32 ( self , rhs : f32 ) -> Duration {
1042- Duration :: from_secs_f32 ( rhs * self . as_secs_f32 ( ) )
1114+ self . mul_f64 ( rhs. into ( ) )
10431115 }
10441116
10451117 /// Divides `Duration` by `f64`.
@@ -1060,7 +1132,103 @@ impl Duration {
10601132 without modifying the original"]
10611133 #[ inline]
10621134 pub fn div_f64 ( self , rhs : f64 ) -> Duration {
1063- Duration :: from_secs_f64 ( self . as_secs_f64 ( ) / rhs)
1135+ if rhs. is_finite ( ) && rhs. is_sign_negative ( ) {
1136+ panic ! ( "{}" , TryFromFloatSecsError { kind: TryFromFloatSecsErrorKind :: Negative } ) ;
1137+ }
1138+ if rhs. is_nan ( ) || rhs == 0.0 {
1139+ panic ! ( "{}" , TryFromFloatSecsError { kind: TryFromFloatSecsErrorKind :: OverflowOrNan } ) ;
1140+ }
1141+
1142+ let lhs_nanos = self . as_nanos ( ) ;
1143+ if lhs_nanos == 0 || rhs. is_infinite ( ) {
1144+ return Duration :: ZERO ;
1145+ }
1146+
1147+ let lhs_log2 = lhs_nanos. ilog2 ( ) as i32 ;
1148+ let ( rhs_significand, rhs_log2) = f64_normalize ( rhs) ;
1149+
1150+ // Avoid needless div-by-zero checks.
1151+ // SAFETY: if `rhs` is normal, the implied bit will have been set in `rhs_significand`;
1152+ // if it is subnormal, then the mantissa cannot be zero (we already panicked above
1153+ // in the event that `rhs` is NaN or zero, and early-returned in the event that it
1154+ // is infinite).
1155+ unsafe {
1156+ hint:: assert_unchecked ( rhs_significand != 0 ) ;
1157+ }
1158+
1159+ let quot_log2_ceil = lhs_log2 - rhs_log2;
1160+ if quot_log2_ceil < -1 {
1161+ // Quotient is definitely less than 0.5ns
1162+ return Duration :: ZERO ;
1163+ }
1164+
1165+ // To assist the compiler in eliminating the bounds check on funnel_shl, The following `if`
1166+ // condition has been manually expanded & rewritten from:
1167+ // let quot_log2_floor = quot_log2_ceil - 1;
1168+ // if quot_log2_floor > Duration::MAX.as_nanos().ilog2() { ... }
1169+ if rhs_log2 < lhs_log2 - Duration :: MAX . as_nanos ( ) . ilog2 ( ) as i32 - 1 {
1170+ // Quotient is definitely more than Duration::MAX
1171+ panic ! ( "{}" , TryFromFloatSecsError { kind: TryFromFloatSecsErrorKind :: OverflowOrNan } ) ;
1172+ }
1173+
1174+ // Denormalize to a purely integer significand.
1175+ let exp = rhs_log2 + 1 - f64:: MANTISSA_DIGITS as i32 ;
1176+ let rhs_significand = rhs_significand as u128 ;
1177+
1178+ let nanos = if let Ok ( shift) = u32:: try_from ( exp) {
1179+ // `rhs` has no fractional precision, so mere integer division is sufficient.
1180+ let unshifted_q = lhs_nanos / rhs_significand;
1181+ let round_up = if let Some ( one_shift_less) = shift. checked_sub ( 1 ) {
1182+ // Bits are to be shifted; the most significant of them is the rounding bit.
1183+ ( unshifted_q >> one_shift_less) & 1
1184+ } else {
1185+ // Nothing is to be shifted out, there is nothing to round.
1186+ 0
1187+ } ;
1188+ ( unshifted_q >> shift) + round_up
1189+ } else {
1190+ // Calculate the first 127 bits of the significand's reciprocal, and any remainder.
1191+ const RECIP_N : u128 = u128:: rotate_right ( 1 , 1 ) ;
1192+ let recip_q = RECIP_N / rhs_significand;
1193+ let recip_r = RECIP_N % rhs_significand;
1194+
1195+ // Calculate the next 127 bits of the reciprocal, and shift them into the most
1196+ // significant bits of a u128. Whilst the least significant bit may be incorrect,
1197+ // it is immaterial to the result.
1198+ let recip_f = ( ( recip_q * recip_r) + ( recip_r * recip_r) / rhs_significand) << 1 ;
1199+
1200+ // Long-multiply lhs with the reciprocal to calculate the 3 most significant 128-bit
1201+ // chunks of the quotient: q2 (most significant) to q0 (least significant).
1202+ let ( q0, carry) = lhs_nanos. carrying_mul ( recip_f, 0 ) ;
1203+ let ( q1, q2) = lhs_nanos. carrying_mul ( recip_q, carry) ;
1204+
1205+ // Offset exponent by 1 because reciprocal is calculated as 2^127/significand,
1206+ // rather than 2^128/significand (which obviously requires greater width than u128).
1207+ let nexp = ( 1 - exp) as u32 ;
1208+
1209+ let ( hi, lo, shift) = if nexp < 128 {
1210+ // The result spans the most significant two chunks, q2 and q1; their concatenation
1211+ // simply needs to be shifted by `nexp` bits.
1212+ ( q2, q1, nexp)
1213+ } else {
1214+ // The result spans the least significant two chunks, q1 and q0: implicitly shift up
1215+ // by discarding the most signiciant chunk q2; the resulting concatenation then
1216+ // simply needs to be shifted by `nexp - 128` bits.
1217+ debug_assert_eq ! ( q2, 0 ) ;
1218+ ( q1, q0, nexp - 128 )
1219+ } ;
1220+
1221+ debug_assert ! ( shift <= hi. leading_zeros( ) ) ;
1222+
1223+ let round_up = ( lo >> ( 127 - shift) ) & 1 ;
1224+ hi. funnel_shl ( lo, shift) + round_up
1225+ } ;
1226+
1227+ if nanos > Duration :: MAX . as_nanos ( ) {
1228+ panic ! ( "{}" , TryFromFloatSecsError { kind: TryFromFloatSecsErrorKind :: OverflowOrNan } ) ;
1229+ }
1230+
1231+ Duration :: from_nanos_u128 ( nanos)
10641232 }
10651233
10661234 /// Divides `Duration` by `f32`.
@@ -1075,15 +1243,15 @@ impl Duration {
10751243 /// let dur = Duration::new(2, 700_000_000);
10761244 /// // note that due to rounding errors result is slightly
10771245 /// // different from 0.859_872_611
1078- /// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_580 ));
1246+ /// assert_eq!(dur.div_f32(3.14), Duration::new(0, 859_872_583 ));
10791247 /// assert_eq!(dur.div_f32(3.14e5), Duration::new(0, 8_599));
10801248 /// ```
10811249 #[ stable( feature = "duration_float" , since = "1.38.0" ) ]
10821250 #[ must_use = "this returns the result of the operation, \
10831251 without modifying the original"]
10841252 #[ inline]
10851253 pub fn div_f32 ( self , rhs : f32 ) -> Duration {
1086- Duration :: from_secs_f32 ( self . as_secs_f32 ( ) / rhs)
1254+ self . div_f64 ( rhs. into ( ) )
10871255 }
10881256
10891257 /// Divides `Duration` by `Duration` and returns `f64`.
@@ -1780,3 +1948,35 @@ impl Duration {
17801948 )
17811949 }
17821950}
1951+
1952+ /// For the input `f`, returns its `(normalized_significand, exponent)` pair where the
1953+ /// `normalized_significand` is a `f64::MANTISSA_DIGITS`-bit fixed point number in [0b1, 0b10) -
1954+ /// and therefore its `f64::MANTISSA_DIGITS`th bit is always set and is always its most significant
1955+ /// set bit; and where the `exponent` is the base-2 exponent of that `normalized_significand` such
1956+ /// that, together, they evaluate to `f`.
1957+ ///
1958+ /// The return values are unspecified if `f` is neither normal nor subnormal (ie is zero, NaN or
1959+ /// infinite).
1960+ fn f64_normalize ( f : f64 ) -> ( u64 , i32 ) {
1961+ const NUM_BITS_MANT : u32 = f64:: MANTISSA_DIGITS - 1 ;
1962+ const NUM_BITS_EXP : u32 = 64 - f64:: MANTISSA_DIGITS ;
1963+
1964+ const MANT_IMPLIED_BIT : u64 = 1 << NUM_BITS_MANT ;
1965+ const MANT_MASK : u64 = MANT_IMPLIED_BIT - 1 ;
1966+ const EXP_MASK : u64 = ( ( 1 << NUM_BITS_EXP ) - 1 ) << NUM_BITS_MANT ;
1967+ const EXP_BIAS : i32 = 1 - f64:: MAX_EXP ;
1968+
1969+ let raw = f. to_bits ( ) ;
1970+ let mantissa = raw & MANT_MASK ;
1971+ let ( significand, biased_exp) = if f. is_normal ( ) {
1972+ let biased_exp = ( ( raw & EXP_MASK ) >> NUM_BITS_MANT ) as i32 ;
1973+ ( mantissa | MANT_IMPLIED_BIT , biased_exp)
1974+ } else {
1975+ // f is subnormal: renormalize by shifting so that the highest set bit is in the correct
1976+ // leading bit position.
1977+ let shift = mantissa. leading_zeros ( ) - NUM_BITS_EXP ;
1978+ ( mantissa << shift, 1 - shift as i32 )
1979+ } ;
1980+
1981+ ( significand, biased_exp + EXP_BIAS )
1982+ }
0 commit comments