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 5 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
63 changes: 63 additions & 0 deletions include/rcutils/time.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,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 % 1000000000l);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

just a minor suggestion. can we have like RCUTILS_NANOSECS_PER_SEC for 1000000000 and use it else where? e.g RCUTILS_S_TO_NS, RCUTILS_NS_TO_S. the same thing can go to miliseconds and microseconds.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah seems like a great metric for users to have, especially if they design their own time-based algorithms and want standardization. I would figure it'll get used enough to be worth having 3 definitions.

sec = ((nanoseconds - nsec) / 1000000000l);

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 % 1000000l);
sec = ((nanoseconds - nsec) / 1000000l);

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 % 1000l);
sec = ((nanoseconds - nsec) / 1000l);

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