Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Creating More Accuracy in NS_TO_S #460

Open
wants to merge 6 commits into
base: rolling
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 74 additions & 6 deletions include/rcutils/time.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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
*
* <hr>
* 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
*
* <hr>
* 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
*
* <hr>
* 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();
Expand Down
42 changes: 42 additions & 0 deletions src/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
30 changes: 30 additions & 0 deletions test/test_time.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down