From 3828a98c76103d67d7bac99d18a428152af4629a Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 21 Dec 2022 01:01:05 +0100 Subject: [PATCH 1/3] important bugfix --- src/time/cuc.rs | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/src/time/cuc.rs b/src/time/cuc.rs index 7347921..bf87064 100644 --- a/src/time/cuc.rs +++ b/src/time/cuc.rs @@ -64,10 +64,16 @@ pub fn fractional_part_from_subsec_ns( if ns > sec_as_ns { panic!("passed nanosecond value larger than 1 second"); } + let resolution = fractional_res_to_div(res) as u64; + // Use integer division because this can reduce code size of really small systems. // First determine the nanoseconds for the smallest segment given the resolution. - // Then divide by that to find out the fractional part. An integer division floors - // which is what we want here. - let fractional_part = ns / (sec_as_ns / fractional_res_to_div(res) as u64); + // Then divide by that to find out the fractional part. For the calculation of the smallest + // fraction, we perform a ceiling division. This is because if we would use the default + // flooring division, we would divide by a smaller value, thereby allowing the calculation to + // invalid fractional parts which are too large. For the division of the nanoseconds by the + // smallest fraction, a flooring division is correct. + // The multiplication with 100000 is necessary to avoid precision loss during integer division. + let fractional_part = ns * 100000 / ((sec_as_ns * 100000 + resolution) / resolution); Some(FractionalPart(res, fractional_part as u32)) } @@ -914,4 +920,12 @@ mod tests { let res = stamp.update_from_now(); assert!(res.is_ok()); } + + #[test] + fn assert_largest_fractions() { + let fractions = fractional_part_from_subsec_ns(FractionalResolution::SixtyNs, 10u64.pow(9) - 1).unwrap(); + // The value can not be larger than representable by 3 bytes + // Assert that the maximum resolution can be reached + assert_eq!(fractions.1, 2_u32.pow(3 * 8) - 2); + } } From 14fa1bad9263f14d4c823dd9f93ccb599a99756f Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 21 Dec 2022 01:03:26 +0100 Subject: [PATCH 2/3] add TODO --- src/time/cuc.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/time/cuc.rs b/src/time/cuc.rs index bf87064..a7660e2 100644 --- a/src/time/cuc.rs +++ b/src/time/cuc.rs @@ -73,6 +73,8 @@ pub fn fractional_part_from_subsec_ns( // invalid fractional parts which are too large. For the division of the nanoseconds by the // smallest fraction, a flooring division is correct. // The multiplication with 100000 is necessary to avoid precision loss during integer division. + // TODO: Floating point division might actually be faster option, but requires additional + // code on small embedded systems.. let fractional_part = ns * 100000 / ((sec_as_ns * 100000 + resolution) / resolution); Some(FractionalPart(res, fractional_part as u32)) } From 472bfa9964f3c0cd218e829f9c93d8564fcb7ecc Mon Sep 17 00:00:00 2001 From: Robin Mueller Date: Wed, 21 Dec 2022 01:17:36 +0100 Subject: [PATCH 3/3] add floating point division code --- src/time/cuc.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/time/cuc.rs b/src/time/cuc.rs index a7660e2..bae59dc 100644 --- a/src/time/cuc.rs +++ b/src/time/cuc.rs @@ -76,6 +76,8 @@ pub fn fractional_part_from_subsec_ns( // TODO: Floating point division might actually be faster option, but requires additional // code on small embedded systems.. let fractional_part = ns * 100000 / ((sec_as_ns * 100000 + resolution) / resolution); + // Floating point division. + //let fractional_part = (ns as f64 / ((sec_as_ns as f64) / resolution as f64)).floor() as u32; Some(FractionalPart(res, fractional_part as u32)) } @@ -930,4 +932,17 @@ mod tests { // Assert that the maximum resolution can be reached assert_eq!(fractions.1, 2_u32.pow(3 * 8) - 2); } + + // extern crate test; + // use test::Bencher; + // + // #[bench] + // fn speed_test(b: &mut Bencher) { + // let ns = 10_u32.pow(9) - 1; + // let sec_as_ns = ns + 1; + // let resolution = 2_u32.pow(3 * 8) - 1; + // b.iter(|| { + // ns * 100000 / ((sec_as_ns * 100000 + resolution) / resolution) + // }); + // } }