@@ -12,6 +12,8 @@ use ops::Sub;
12
12
use time:: Duration ;
13
13
use sync:: { Once , ONCE_INIT } ;
14
14
15
+ const NANOS_PER_SEC : i64 = 1_000_000_000 ;
16
+
15
17
pub struct SteadyTime {
16
18
t : libc:: LARGE_INTEGER ,
17
19
}
@@ -24,7 +26,7 @@ impl SteadyTime {
24
26
}
25
27
26
28
pub fn ns ( & self ) -> u64 {
27
- self . t as u64 * 1_000_000_000 / frequency ( ) as u64
29
+ mul_div_i64 ( self . t as i64 , NANOS_PER_SEC , frequency ( ) as i64 ) as u64
28
30
}
29
31
}
30
32
@@ -45,6 +47,27 @@ impl<'a> Sub for &'a SteadyTime {
45
47
46
48
fn sub ( self , other : & SteadyTime ) -> Duration {
47
49
let diff = self . t as i64 - other. t as i64 ;
48
- Duration :: microseconds ( diff * 1_000_000 / frequency ( ) as i64 )
50
+ Duration :: nanoseconds ( mul_div_i64 ( diff, NANOS_PER_SEC , frequency ( ) as i64 ) )
49
51
}
50
52
}
53
+
54
+ // Computes (value*numer)/denom without overflow, as long as both
55
+ // (numer*denom) and the overall result fit into i64 (which is the case
56
+ // for our time conversions).
57
+ fn mul_div_i64 ( value : i64 , numer : i64 , denom : i64 ) -> i64 {
58
+ let q = value / denom;
59
+ let r = value % denom;
60
+ // Decompose value as (value/denom*denom + value%denom),
61
+ // substitute into (value*numer)/denom and simplify.
62
+ // r < denom, so (denom*numer) is the upper bound of (r*numer)
63
+ q * numer + r * numer / denom
64
+ }
65
+
66
+ #[ test]
67
+ fn test_muldiv ( ) {
68
+ assert_eq ! ( mul_div_i64( 1_000_000_000_001 , 1_000_000_000 , 1_000_000 ) , 1_000_000_000_001_000 ) ;
69
+ assert_eq ! ( mul_div_i64( -1_000_000_000_001 , 1_000_000_000 , 1_000_000 ) , -1_000_000_000_001_000 ) ;
70
+ assert_eq ! ( mul_div_i64( -1_000_000_000_001 , -1_000_000_000 , 1_000_000 ) , 1_000_000_000_001_000 ) ;
71
+ assert_eq ! ( mul_div_i64( 1_000_000_000_001 , 1_000_000_000 , -1_000_000 ) , -1_000_000_000_001_000 ) ;
72
+ assert_eq ! ( mul_div_i64( 1_000_000_000_001 , -1_000_000_000 , -1_000_000 ) , 1_000_000_000_001_000 ) ;
73
+ }
0 commit comments