From 0fb10c29d6b5ed0070c3d36338c2bafce7c7f06d Mon Sep 17 00:00:00 2001 From: David Venhoek Date: Fri, 8 Dec 2023 13:05:06 +0100 Subject: [PATCH] Polyfill around rust floating point handling. --- statime/src/filters/basic.rs | 6 +++-- statime/src/filters/kalman.rs | 2 ++ statime/src/float_polyfill.rs | 45 +++++++++++++++++++++++++++++++++++ statime/src/lib.rs | 1 + statime/src/ptp_instance.rs | 8 ++----- statime/src/time/duration.rs | 4 +++- statime/src/time/interval.rs | 9 +++---- 7 files changed, 60 insertions(+), 15 deletions(-) create mode 100644 statime/src/float_polyfill.rs diff --git a/statime/src/filters/basic.rs b/statime/src/filters/basic.rs index 6de33a4a3..2d975b7ca 100644 --- a/statime/src/filters/basic.rs +++ b/statime/src/filters/basic.rs @@ -3,6 +3,8 @@ use fixed::traits::LossyInto; use super::{Filter, FilterUpdate}; +#[allow(unused_imports)] +use crate::float_polyfill::FloatPolyfill; use crate::{ port::Measurement, time::{Duration, Time}, @@ -95,12 +97,12 @@ impl Filter for BasicFilter { // get relative frequency difference let mut freq_diff = interval_local / interval_master; - if libm::fabs(freq_diff - 1.0) > self.freq_confidence { + if (freq_diff - 1.0).abs() > self.freq_confidence { freq_diff = freq_diff.clamp(1.0 - self.freq_confidence, 1.0 + self.freq_confidence); self.freq_confidence *= 2.0; } else { self.freq_confidence -= - (self.freq_confidence - libm::fabs(freq_diff - 1.0)) * self.gain; + (self.freq_confidence - (freq_diff - 1.0).abs()) * self.gain; } // and decide the correction (and convert to ppm) diff --git a/statime/src/filters/kalman.rs b/statime/src/filters/kalman.rs index 7612a3ed3..fa4c80496 100644 --- a/statime/src/filters/kalman.rs +++ b/statime/src/filters/kalman.rs @@ -1,4 +1,6 @@ use super::matrix::{Matrix, Vector}; +#[allow(unused_imports)] +use crate::float_polyfill::FloatPolyfill; use crate::{ filters::Filter, port::Measurement, diff --git a/statime/src/float_polyfill.rs b/statime/src/float_polyfill.rs new file mode 100644 index 000000000..a7e504fab --- /dev/null +++ b/statime/src/float_polyfill.rs @@ -0,0 +1,45 @@ +pub(crate) trait FloatPolyfill { + #[cfg(not(feature = "std"))] + fn abs(self) -> Self; + #[cfg(not(feature = "std"))] + fn signum(self) -> Self; + #[cfg(not(feature = "std"))] + fn sqrt(self) -> Self; + #[cfg(not(feature = "std"))] + fn powi(self, n: i32) -> Self; + #[cfg(not(feature = "std"))] + fn exp(self) -> Self; +} + +impl FloatPolyfill for f64 { + #[cfg(not(feature = "std"))] + fn abs(self) -> Self { + libm::fabs(self) + } + + #[cfg(not(feature = "std"))] + fn signum(self) -> Self { + if self < 0.0 { + -1.0 + } else if self > 0.0 { + 1.0 + } else { + 0.0 + } + } + + #[cfg(not(feature = "std"))] + fn sqrt(self) -> Self { + libm::sqrt(self) + } + + #[cfg(not(feature = "std"))] + fn powi(self, n: i32) -> Self { + libm::pow(self, n as f64) + } + + #[cfg(not(feature = "std"))] + fn exp(self) -> Self { + libm::exp(self) + } +} diff --git a/statime/src/lib.rs b/statime/src/lib.rs index 689d7812e..30bd6401d 100644 --- a/statime/src/lib.rs +++ b/statime/src/lib.rs @@ -88,6 +88,7 @@ mod clock; pub mod config; pub(crate) mod datastructures; pub mod filters; +mod float_polyfill; pub mod port; mod ptp_instance; pub mod time; diff --git a/statime/src/ptp_instance.rs b/statime/src/ptp_instance.rs index 99ac87d89..2f4cd3f24 100644 --- a/statime/src/ptp_instance.rs +++ b/statime/src/ptp_instance.rs @@ -6,6 +6,8 @@ use core::{ use atomic_refcell::AtomicRefCell; use rand::Rng; +#[allow(unused_imports)] +use crate::float_polyfill::FloatPolyfill; use crate::{ bmc::{acceptable_master::AcceptableMasterList, bmca::Bmca}, clock::Clock, @@ -206,10 +208,7 @@ impl PtpInstance { self.state.borrow_mut().bmca( ports, Duration::from_seconds( - #[cfg(feature = "std")] 2f64.powi(self.log_bmca_interval.load(Ordering::Relaxed) as i32), - #[cfg(not(feature = "std"))] - libm::pow(2f64, self.log_bmca_interval.load(Ordering::Relaxed) as f64), ), ) } @@ -217,10 +216,7 @@ impl PtpInstance { /// Time to wait between calls to [`PtpInstance::bmca`] pub fn bmca_interval(&self) -> core::time::Duration { core::time::Duration::from_secs_f64( - #[cfg(feature = "std")] 2f64.powi(self.log_bmca_interval.load(Ordering::Relaxed) as i32), - #[cfg(not(feature = "std"))] - libm::pow(2f64, self.log_bmca_interval.load(Ordering::Relaxed) as f64), ) } } diff --git a/statime/src/time/duration.rs b/statime/src/time/duration.rs index eb39e9b32..308eb9787 100644 --- a/statime/src/time/duration.rs +++ b/statime/src/time/duration.rs @@ -13,6 +13,8 @@ use fixed::{ use super::Interval; use crate::datastructures::common::TimeInterval; +#[allow(unused_imports)] +use crate::float_polyfill::FloatPolyfill; /// A duration is a span of time that can also be negative. /// @@ -93,7 +95,7 @@ impl Duration { /// Converts a log interval (as defined by the PTP spec) to a duration pub fn from_log_interval(log_interval: i8) -> Self { - let seconds = libm::pow(2.0f64, log_interval as f64); + let seconds = 2.0f64.powi(log_interval as i32); let nanos = seconds * 1_000_000_000.0; Self::from_fixed_nanos(nanos) } diff --git a/statime/src/time/interval.rs b/statime/src/time/interval.rs index 482990984..e28110b6c 100644 --- a/statime/src/time/interval.rs +++ b/statime/src/time/interval.rs @@ -1,3 +1,6 @@ +#[allow(unused_imports)] +use crate::float_polyfill::FloatPolyfill; + /// A log2 representation of seconds used to describe the pacing of events in /// PTP #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] @@ -69,12 +72,6 @@ impl Interval { core::time::Duration::from_secs_f64(self.seconds()) } - #[cfg(not(feature = "std"))] - fn as_f64(self) -> f64 { - libm::pow(2.0f64, self.0 as f64) - } - - #[cfg(feature = "std")] fn as_f64(self) -> f64 { 2.0f64.powi(self.0 as i32) }