diff --git a/src/core/model/nstime.h b/src/core/model/nstime.h index 202bbc38e..ee33f2e87 100644 --- a/src/core/model/nstime.h +++ b/src/core/model/nstime.h @@ -86,13 +86,17 @@ public: */ enum Unit { - S = 0, //!< second - MS = 1, //!< millisecond - US = 2, //!< microsecond - NS = 3, //!< nanosecond - PS = 4, //!< picosecond - FS = 5, //!< femtosecond - LAST = 6 + Y = 0, //!< year, 365 days + D = 1, //!< day, 24 hours + H = 2, //!< hour, 60 minutes + MIN = 3, //!< minute, 60 seconds + S = 4, //!< second + MS = 5, //!< millisecond + US = 6, //!< microsecond + NS = 7, //!< nanosecond + PS = 8, //!< picosecond + FS = 9, //!< femtosecond + LAST = 10 }; inline Time &operator = (const Time &o) @@ -182,6 +186,10 @@ public: * - `ns` (nanoseconds) * - `ps` (picoseconds) * - `fs` (femtoseconds) + * - `min` (minutes) + * - `h` (hours) + * - `d` (days) + * - `y` (years) * * There can be no white space between the numerical portion * and the units. Any otherwise malformed string causes a fatal error to @@ -308,6 +316,40 @@ public: { return ToInteger (Time::FS); } + + /** + * \returns an approximation in minutes of the time stored in this + * instance. + */ + inline double GetMinutes (void) const + { + return ToDouble (Time::MIN); + } + /** + * \returns an approximation in hours of the time stored in this + * instance. + */ + inline double GetHours (void) const + { + return ToDouble (Time::H); + } + /** + * \returns an approximation in days of the time stored in this + * instance. + */ + inline double GetDays (void) const + { + return ToDouble (Time::D); + } + /** + * \returns an approximation in years of the time stored in this + * instance. + */ + inline double GetYears (void) const + { + return ToDouble (Time::Y); + } + /** * \returns the raw time value, in the current units */ @@ -762,7 +804,66 @@ inline Time FemtoSeconds (uint64_t fs) { return Time::FromInteger (fs, Time::FS); } - +/** + * \brief create ns3::Time instances in units of minutes (equal to 60 seconds). + * + * For example: + * \code + * Time t = Minutes (2.0); + * Simulator::Schedule (Minutes (5.0), ...); + * \endcode + * \param minutes mintues value + * \relates ns3::Time + */ +inline Time Minutes (double minutes) +{ + return Time::FromDouble (minutes, Time::MIN); +} +/** + * \brief create ns3::Time instances in units of hours (equal to 60 minutes). + * + * For example: + * \code + * Time t = Hours (2.0); + * Simulator::Schedule (Hours (5.0), ...); + * \endcode + * \param hours hours value + * \relates ns3::Time + */ +inline Time Hours (double hours) +{ + return Time::FromDouble (hours, Time::H); +} +/** + * \brief create ns3::Time instances in units of days (equal to 24 hours). + * + * For example: + * \code + * Time t = Days (2.0); + * Simulator::Schedule (Days (5.0), ...); + * \endcode + * \param days days value + * \relates ns3::Time + */ +inline Time Days (double days) +{ + return Time::FromDouble (days, Time::D); +} +/** + * \brief create ns3::Time instances in units of years (equal to 365 days). + * + * For example: + * \code + * Time t = Years (2.0); + * Simulator::Schedule (Years (5.0), ...); + * \endcode + * \param years years value + * \relates ns3::Time + */ +inline Time Years (double years) +{ + return Time::FromDouble (years, Time::Y); +} /** * \see Seconds(double) @@ -812,6 +913,38 @@ inline Time FemtoSeconds (int64x64_t fs) { return Time::From (fs, Time::FS); } +/** + * \see Minutes(uint64_t) + * \relates ns3::Time + */ +inline Time Minutes (int64x64_t minutes) +{ + return Time::From (minutes, Time::MIN); +} +/** + * \see Minutes(uint64_t) + * \relates ns3::Time + */ +inline Time Hours (int64x64_t hours) +{ + return Time::From (hours, Time::H); +} +/** + * \see Minutes(uint64_t) + * \relates ns3::Time + */ +inline Time Days (int64x64_t days) +{ + return Time::From (days, Time::D); +} +/** + * \see Minutes(uint64_t) + * \relates ns3::Time + */ +inline Time Years (int64x64_t years) +{ + return Time::From (years, Time::Y); +} // internal function not publicly documented inline Time TimeStep (uint64_t ts) diff --git a/src/core/model/time.cc b/src/core/model/time.cc index 03a54ffff..a2e02a9df 100644 --- a/src/core/model/time.cc +++ b/src/core/model/time.cc @@ -123,6 +123,22 @@ Time::Time (const std::string& s) { *this = Time::FromDouble (r, Time::FS); } + else if (trailer == std::string ("min")) + { + *this = Time::FromDouble (r, Time::MIN); + } + else if (trailer == std::string ("h")) + { + *this = Time::FromDouble (r, Time::H); + } + else if (trailer == std::string ("d")) + { + *this = Time::FromDouble (r, Time::D); + } + else if (trailer == std::string ("y")) + { + *this = Time::FromDouble (r, Time::Y); + } else { NS_ABORT_MSG ("Can't Parse Time " << s); @@ -176,21 +192,41 @@ Time::SetResolution (enum Unit unit, struct Resolution *resolution, ConvertTimes (unit); } - int8_t power [LAST] = { 15, 12, 9, 6, 3, 0}; + // Y, D, H, MIN, S, MS, US, NS, PS, FS + const int8_t power [LAST] = { 17, 17, 17, 16, 15, 12, 9, 6, 3, 0 }; + const int32_t coefficient [LAST] = { 315360, 864, 36, 6, 1, 1, 1, 1, 1, 1 }; for (int i = 0; i < Time::LAST; i++) { int shift = power[i] - power[(int)unit]; - int64_t factor = (int64_t) std::pow (10, std::fabs (shift)); + int quotient = 1; + if (coefficient[i] > coefficient[(int) unit]) + { + quotient = coefficient[i] / coefficient[(int) unit]; + NS_ASSERT (quotient * coefficient[(int) unit] == coefficient[i]); + } + else if (coefficient[i] < coefficient[(int) unit]) + { + quotient = coefficient[(int) unit] / coefficient[i]; + NS_ASSERT (quotient * coefficient[i] == coefficient[(int) unit]); + } + NS_LOG_DEBUG ("SetResolution for unit " << (int) unit << " loop iteration " << i + << " has shift " << shift << " has quotient " << quotient); + int64_t factor = static_cast (std::pow (10, std::fabs (shift)) * quotient); + double realFactor = std::pow (10, (double) shift) + * static_cast (coefficient[i]) / coefficient[(int) unit]; + NS_LOG_DEBUG ("SetResolution factor " << factor << " real factor " << realFactor); struct Information *info = &resolution->info[i]; info->factor = factor; - if (shift == 0) + // here we could equivalently check for realFactor == 1.0 but it's better + // to avoid checking equality of doubles + if (shift == 0 && quotient == 1) { info->timeFrom = int64x64_t (1); info->timeTo = int64x64_t (1); info->toMul = true; info->fromMul = true; } - else if (shift > 0) + else if (realFactor > 1) { info->timeFrom = int64x64_t (factor); info->timeTo = int64x64_t::Invert (factor); @@ -199,7 +235,7 @@ Time::SetResolution (enum Unit unit, struct Resolution *resolution, } else { - NS_ASSERT (shift < 0); + NS_ASSERT (realFactor < 1); info->timeFrom = int64x64_t::Invert (factor); info->timeTo = int64x64_t (factor); info->toMul = true; @@ -368,6 +404,18 @@ operator<< (std::ostream& os, const Time & time) case Time::FS: unit = "fs"; break; + case Time::MIN: + unit = "min"; + break; + case Time::H: + unit = "h"; + break; + case Time::D: + unit = "d"; + break; + case Time::Y: + unit = "y"; + break; case Time::LAST: NS_ABORT_MSG ("can't be reached"); unit = "unreachable"; diff --git a/src/core/test/time-test-suite.cc b/src/core/test/time-test-suite.cc index a875a1aa4..88b1b8348 100644 --- a/src/core/test/time-test-suite.cc +++ b/src/core/test/time-test-suite.cc @@ -47,6 +47,22 @@ TimeSimpleTestCase::DoSetup (void) void TimeSimpleTestCase::DoRun (void) { + NS_TEST_ASSERT_MSG_EQ_TOL (Years (1.0).GetYears (), 1.0, Years (1).GetYears (), + "is 1 really 1 ?"); + NS_TEST_ASSERT_MSG_EQ_TOL (Years (10.0).GetYears (), 10.0, Years (1).GetYears (), + "is 10 really 10 ?"); + NS_TEST_ASSERT_MSG_EQ_TOL (Days (1.0).GetDays (), 1.0, Days (1).GetDays (), + "is 1 really 1 ?"); + NS_TEST_ASSERT_MSG_EQ_TOL (Days (10.0).GetDays (), 10.0, Days (1).GetDays (), + "is 10 really 10 ?"); + NS_TEST_ASSERT_MSG_EQ_TOL (Hours (1.0).GetHours (), 1.0, Hours (1).GetHours (), + "is 1 really 1 ?"); + NS_TEST_ASSERT_MSG_EQ_TOL (Hours (10.0).GetHours (), 10.0, Hours (1).GetHours (), + "is 10 really 10 ?"); + NS_TEST_ASSERT_MSG_EQ_TOL (Minutes (1.0).GetMinutes (), 1.0, Minutes (1).GetMinutes (), + "is 1 really 1 ?"); + NS_TEST_ASSERT_MSG_EQ_TOL (Minutes (10.0).GetMinutes (), 10.0, Minutes (1).GetMinutes (), + "is 10 really 10 ?"); NS_TEST_ASSERT_MSG_EQ_TOL (Seconds (1.0).GetSeconds (), 1.0, TimeStep (1).GetSeconds (), "is 1 really 1 ?"); NS_TEST_ASSERT_MSG_EQ_TOL (Seconds (10.0).GetSeconds (), 10.0, TimeStep (1).GetSeconds (),