diff --git a/include/rcutils/time.h b/include/rcutils/time.h index 0fb765e7..8ae8e6d3 100644 --- a/include/rcutils/time.h +++ b/include/rcutils/time.h @@ -28,19 +28,24 @@ extern "C" #include "rcutils/types.h" #include "rcutils/visibility_control.h" +/// Convenience defintitions to commonly used numbers. +#define RCUTILS_NANOSECONDS_PER_SEC 1000000000l +#define RCUTILS_NANOSECONDS_PER_MILLISEC 1000000l +#define RCUTILS_NANOSECONDS_PER_MICROSEC 1000l + /// Convenience macro to convert seconds to nanoseconds. -#define RCUTILS_S_TO_NS(seconds) ((seconds) * (1000LL * 1000LL * 1000LL)) +#define RCUTILS_S_TO_NS(seconds) ((seconds) * RCUTILS_NANOSECONDS_PER_SEC) /// Convenience macro to convert milliseconds to nanoseconds. -#define RCUTILS_MS_TO_NS(milliseconds) ((milliseconds) * (1000LL * 1000LL)) +#define RCUTILS_MS_TO_NS(milliseconds) ((milliseconds) * RCUTILS_NANOSECONDS_PER_MILLISEC) /// Convenience macro to convert microseconds to nanoseconds. -#define RCUTILS_US_TO_NS(microseconds) ((microseconds) * 1000LL) +#define RCUTILS_US_TO_NS(microseconds) ((microseconds) * RCUTILS_NANOSECONDS_PER_MICROSEC) /// Convenience macro to convert nanoseconds to seconds. -#define RCUTILS_NS_TO_S(nanoseconds) ((nanoseconds) / (1000LL * 1000LL * 1000LL)) +#define RCUTILS_NS_TO_S(nanoseconds) ((nanoseconds) / RCUTILS_NANOSECONDS_PER_SEC) /// Convenience macro to convert nanoseconds to milliseconds. -#define RCUTILS_NS_TO_MS(nanoseconds) ((nanoseconds) / (1000LL * 1000LL)) +#define RCUTILS_NS_TO_MS(nanoseconds) ((nanoseconds) / RCUTILS_NANOSECONDS_PER_MILLISEC) /// Convenience macro to convert nanoseconds to microseconds. -#define RCUTILS_NS_TO_US(nanoseconds) ((nanoseconds) / 1000LL) +#define RCUTILS_NS_TO_US(nanoseconds) ((nanoseconds) / RCUTILS_NANOSECONDS_PER_MICROSEC) /// Convenience macro for rcutils_steady_time_now(rcutils_time_point_value_t *). #define RCUTILS_STEADY_TIME rcutils_steady_time_now @@ -49,6 +54,69 @@ typedef int64_t rcutils_time_point_value_t; /// A duration of time, measured in nanoseconds. typedef int64_t rcutils_duration_value_t; +/** + * This function returns an accurate conversion from nanoseconds to seconds. + * + * The nanoseconds argument has to be an int64_t to ensure exact division + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | No + * Thread-Safe | Yes + * Uses Atomics | No + * Lock-Free | Yes + * + * \param[in] nanoseconds The int64_t needed for conversion + * \return double That nanoseconds number as seconds. + */ +RCUTILS_PUBLIC +RCUTILS_WARN_UNUSED +double +rcutils_nanoseconds_to_seconds(const int64_t nanoseconds); + +/** + * This function returns an accurate conversion from nanoseconds to milliseconds. + * + * The nanoseconds argument has to be an int64_t to ensure exact division + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | No + * Thread-Safe | Yes + * Uses Atomics | No + * Lock-Free | Yes + * + * \param[in] nanoseconds The int64_t needed for conversion + * \return double That nanoseconds number as milliseconds. + */ +RCUTILS_PUBLIC +RCUTILS_WARN_UNUSED +double +rcutils_nanoseconds_to_milliseconds(const int64_t nanoseconds); + +/** + * This function returns an accurate conversion from nanoseconds to microseconds. + * + * The nanoseconds argument has to be an int64_t to ensure exact division + * + *
+ * Attribute | Adherence + * ------------------ | ------------- + * Allocates Memory | No + * Thread-Safe | Yes + * Uses Atomics | No + * Lock-Free | Yes + * + * \param[in] nanoseconds The int64_t needed for conversion + * \return double That nanoseconds number as microseconds. + */ +RCUTILS_PUBLIC +RCUTILS_WARN_UNUSED +double +rcutils_nanoseconds_to_microseconds(const int64_t nanoseconds); + /** * This function returns the time from a system clock. * The closest equivalent would be to std::chrono::system_clock::now(); diff --git a/src/time.c b/src/time.c index 882c9d98..a2a88b3d 100644 --- a/src/time.c +++ b/src/time.c @@ -28,6 +28,48 @@ extern "C" #include "rcutils/error_handling.h" #include "rcutils/snprintf.h" +double +rcutils_nanoseconds_to_seconds(const int64_t nanoseconds) +{ + // scale the nanoseconds separately for improved accuracy + int64_t sec, nsec; + nsec = (nanoseconds % RCUTILS_NANOSECONDS_PER_SEC); + sec = ((nanoseconds - nsec) / RCUTILS_NANOSECONDS_PER_SEC); + + double sec_double, nsec_double; + nsec_double = 1e-9 * (double)(nsec); + sec_double = (double)(sec); + return sec_double + nsec_double; +} + +double +rcutils_nanoseconds_to_milliseconds(const int64_t nanoseconds) +{ + // scale the nanoseconds separately for improved accuracy + int64_t sec, nsec; + nsec = (nanoseconds % RCUTILS_NANOSECONDS_PER_MILLISEC); + sec = ((nanoseconds - nsec) / RCUTILS_NANOSECONDS_PER_MILLISEC); + + double sec_double, nsec_double; + nsec_double = 1e-6 * (double)(nsec); + sec_double = (double)(sec); + return sec_double + nsec_double; +} + +double +rcutils_nanoseconds_to_microseconds(const int64_t nanoseconds) +{ + // scale the nanoseconds separately for improved accuracy + int64_t sec, nsec; + nsec = (nanoseconds % RCUTILS_NANOSECONDS_PER_MICROSEC); + sec = ((nanoseconds - nsec) / RCUTILS_NANOSECONDS_PER_MICROSEC); + + double sec_double, nsec_double; + nsec_double = 1e-3 * (double)(nsec); + sec_double = (double)(sec); + return sec_double + nsec_double; +} + rcutils_ret_t rcutils_time_point_value_as_nanoseconds_string( const rcutils_time_point_value_t * time_point, diff --git a/test/test_time.cpp b/test/test_time.cpp index 5976cabf..a76be533 100644 --- a/test/test_time.cpp +++ b/test/test_time.cpp @@ -121,6 +121,36 @@ TEST_F(TestTimeFixture, test_rcutils_time_conversion_macros) { 9007199254740.992); // maximum precision double (53 bits) } +// Tests the rcutils time unit conversion functions. +TEST_F(TestTimeFixture, test_rcutils_time_conversion_functions) { + // nanoseconds to seconds + EXPECT_EQ(rcutils_nanoseconds_to_seconds(1000000000ll), 1.0); // int64_t + EXPECT_EQ(rcutils_nanoseconds_to_seconds(1000000042ll), 1.000000042); // int64_t + EXPECT_EQ(rcutils_nanoseconds_to_seconds(-2999999999ll), -2.999999999); // int64_t + EXPECT_EQ(rcutils_nanoseconds_to_seconds(1 + 1), 0.000000002); // sum of two int64_ts + EXPECT_EQ( + rcutils_nanoseconds_to_seconds(9007199254740992), + 9007199.254740992); // maximum precision double as an int64_t + + // nanoseconds to milliseconds + EXPECT_EQ(rcutils_nanoseconds_to_milliseconds(1000000ll), 1.0); // int64_t + EXPECT_EQ(rcutils_nanoseconds_to_milliseconds(1000042ll), 1.000042); // int64_t + EXPECT_EQ(rcutils_nanoseconds_to_milliseconds(-2999999ll), -2.999999); // int64_t + EXPECT_EQ(rcutils_nanoseconds_to_milliseconds(1 + 1), 0.000002); // sum of int64_ts + EXPECT_EQ( + rcutils_nanoseconds_to_milliseconds(9007199254740992), + 9007199254.740992); // maximum precision double as an int64_t + + // nanoseconds to microseconds + EXPECT_EQ(rcutils_nanoseconds_to_microseconds(1000ll), 1.0); // int64_t + EXPECT_EQ(rcutils_nanoseconds_to_microseconds(1042ll), 1.042); // int64_t + EXPECT_EQ(rcutils_nanoseconds_to_microseconds(-2999ll), -2.999); // int64_t + EXPECT_EQ(rcutils_nanoseconds_to_microseconds(1 + 1), 0.002); // sum of int64_ts + EXPECT_EQ( + rcutils_nanoseconds_to_microseconds(9007199254740992), + 9007199254740.992); // maximum precision double as an int64_t +} + // Tests the rcutils_system_time_now() function. TEST_F(TestTimeFixture, test_rcutils_system_time_now) { rcutils_ret_t ret;