merge with bug826 fixes
This commit is contained in:
@@ -125,8 +125,8 @@ ATTRIBUTE_HELPER_HEADER (DataRate);
|
||||
* \param rhs
|
||||
* \return Bits transmitted in rhs seconds at lhs b/s
|
||||
*/
|
||||
double operator*(const DataRate& lhs, const TimeUnit<1>& rhs);
|
||||
double operator*(const TimeUnit<1>& lhs, const DataRate& rhs);
|
||||
double operator*(const DataRate& lhs, const Time& rhs);
|
||||
double operator*(const Time& lhs, const DataRate& rhs);
|
||||
|
||||
} //namespace ns3
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ Backoff::GetBackoffTime (void)
|
||||
|
||||
uint32_t backoffSlots = (uint32_t)m_rng.GetValue(minSlot, maxSlot);
|
||||
|
||||
backoff = Scalar(backoffSlots) * m_slotTime;
|
||||
backoff = Scalar (backoffSlots) * m_slotTime;
|
||||
return (backoff);
|
||||
}
|
||||
|
||||
|
||||
@@ -157,7 +157,7 @@ NdiscCache::Entry::Entry (NdiscCache* nd)
|
||||
m_retransTimer(Timer::CANCEL_ON_DESTROY),
|
||||
m_probeTimer(Timer::CANCEL_ON_DESTROY),
|
||||
m_delayTimer(Timer::CANCEL_ON_DESTROY),
|
||||
m_lastReachabilityConfirmation(Timer::CANCEL_ON_DESTROY),
|
||||
m_lastReachabilityConfirmation(Seconds (0.0)),
|
||||
m_nsRetransmit (0)
|
||||
{
|
||||
NS_LOG_FUNCTION_NOARGS ();
|
||||
|
||||
@@ -28,8 +28,8 @@ Waypoint::Waypoint (const Time &waypointTime, const Vector &waypointPosition)
|
||||
position (waypointPosition)
|
||||
{}
|
||||
Waypoint::Waypoint ()
|
||||
: time (0.0),
|
||||
position (0,0,0)
|
||||
: time (Seconds (0.0)),
|
||||
position (0,0,0)
|
||||
{}
|
||||
|
||||
std::ostream &operator << (std::ostream &os, const Waypoint &waypoint)
|
||||
|
||||
@@ -40,7 +40,7 @@ TypeId
|
||||
DefaultSimulatorImpl::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::DefaultSimulatorImpl")
|
||||
.SetParent<Object> ()
|
||||
.SetParent<SimulatorImpl> ()
|
||||
.AddConstructor<DefaultSimulatorImpl> ()
|
||||
;
|
||||
return tid;
|
||||
|
||||
@@ -1,30 +1,59 @@
|
||||
#include "high-precision-128.h"
|
||||
#include "ns3/fatal-error.h"
|
||||
#include "ns3/abort.h"
|
||||
#include "ns3/assert.h"
|
||||
#include <math.h>
|
||||
#ifdef COUNT_OPS
|
||||
#include <iostream>
|
||||
#endif
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
#ifdef COUNT_OPS
|
||||
uint128_t HighPrecision::g_nAdd = 0;
|
||||
uint128_t HighPrecision::g_nMuli = 0;
|
||||
uint128_t HighPrecision::g_nMul = 0;
|
||||
uint128_t HighPrecision::g_nDiv = 0;
|
||||
uint128_t HighPrecision::g_nCmp = 0;
|
||||
HighPrecision::Printer HighPrecision::g_printer;
|
||||
HighPrecision::Printer::~Printer ()
|
||||
{
|
||||
std::cout << "add=" << (double)g_nAdd << " mul=" << (double)g_nMul << " div=" << (double)g_nDiv
|
||||
<< " muli=" << (double)g_nMuli << " cmp=" << (double)g_nCmp;
|
||||
}
|
||||
#endif
|
||||
|
||||
#define OUTPUT_SIGN(sa,sb,ua,ub) \
|
||||
({bool negA, negB; \
|
||||
negA = sa < 0; \
|
||||
negB = sb < 0; \
|
||||
ua = negA?-sa:sa; \
|
||||
ub = negB?-sb:sb; \
|
||||
(negA && !negB) || (!negA && negB);})
|
||||
|
||||
|
||||
#define MASK_LO ((((uint128_t)1)<<64)-1)
|
||||
#define MASK_HI (~MASK_LO)
|
||||
void
|
||||
HighPrecision::Mul (HighPrecision const &o)
|
||||
{
|
||||
bool negResult, negA, negB;
|
||||
// take the sign of the operands
|
||||
negA = m_value < 0;
|
||||
negB = o.m_value < 0;
|
||||
// the result is negative only if one of the operand is negative
|
||||
negResult = (negA && !negB) || (!negA && negB);
|
||||
// now take the absolute part to make sure that the resulting operands are positive
|
||||
bool negResult;
|
||||
uint128_t a, b;
|
||||
a = negA?-m_value:m_value;
|
||||
b = negB?-o.m_value:o.m_value;
|
||||
negResult = OUTPUT_SIGN (m_value, o.m_value, a, b);
|
||||
int128_t result = Umul (a, b);
|
||||
// add the sign to the result
|
||||
result = negResult ? -result : result;
|
||||
m_value = result;
|
||||
}
|
||||
|
||||
uint128_t
|
||||
HighPrecision::Umul (uint128_t a, uint128_t b)
|
||||
{
|
||||
INC_MUL;
|
||||
uint128_t aL = a & MASK_LO;
|
||||
uint128_t bL = b & MASK_LO;
|
||||
uint128_t aH = (a >> 64) & MASK_LO;
|
||||
uint128_t bH = (b >> 64) & MASK_LO;
|
||||
|
||||
|
||||
uint128_t result;
|
||||
uint128_t hiPart,loPart,midPart;
|
||||
|
||||
@@ -42,28 +71,25 @@ HighPrecision::Mul (HighPrecision const &o)
|
||||
// truncate the high part and only use the low part
|
||||
result |= ((hiPart & MASK_LO) << 64) + (midPart & MASK_HI);
|
||||
// if the high part is not zero, put a warning
|
||||
if ((hiPart & MASK_HI) != 0)
|
||||
{
|
||||
NS_FATAL_ERROR ("High precision 128 bits multiplication error: multiplication overflow.");
|
||||
}
|
||||
// add the sign to the result
|
||||
result = negResult ? -result:result;
|
||||
m_value = result;
|
||||
NS_ABORT_MSG_IF ((hiPart & MASK_HI) != 0,
|
||||
"High precision 128 bits multiplication error: multiplication overflow.");
|
||||
return result;
|
||||
}
|
||||
void
|
||||
HighPrecision::Div (HighPrecision const &o)
|
||||
{
|
||||
bool negResult, negA, negB;
|
||||
// take the sign of the operands
|
||||
negA = m_value < 0;
|
||||
negB = o.m_value < 0;
|
||||
// the result is negative only if one of the operand is negative
|
||||
negResult = (negA && !negB) || (!negA && negB);
|
||||
// now take the absolute part to make sure that the resulting operands are positive
|
||||
bool negResult;
|
||||
uint128_t a, b;
|
||||
a = negA?-m_value:m_value;
|
||||
b = negB?-o.m_value:o.m_value;
|
||||
negResult = OUTPUT_SIGN (m_value, o.m_value, a, b);
|
||||
int128_t result = Divu (a, b);
|
||||
result = negResult ? -result:result;
|
||||
m_value = result;
|
||||
}
|
||||
|
||||
uint128_t
|
||||
HighPrecision::Divu (uint128_t a, uint128_t b)
|
||||
{
|
||||
INC_DIV;
|
||||
uint128_t quo = a / b;
|
||||
uint128_t rem = (a % b);
|
||||
uint128_t result = quo << 64;
|
||||
@@ -82,8 +108,50 @@ HighPrecision::Div (HighPrecision const &o)
|
||||
}
|
||||
quo = rem / div;
|
||||
result = result + quo;
|
||||
result = negResult ? -result:result;
|
||||
m_value = result;
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
HighPrecision::MulByInvert (const HighPrecision &o)
|
||||
{
|
||||
bool negResult = m_value < 0;
|
||||
uint128_t a = negResult?-m_value:m_value;
|
||||
uint128_t result = UmulByInvert (a, o.m_value);
|
||||
|
||||
m_value = negResult?-result:result;
|
||||
}
|
||||
uint128_t
|
||||
HighPrecision::UmulByInvert (uint128_t a, uint128_t b)
|
||||
{
|
||||
INC_MULI;
|
||||
uint128_t result, ah, bh, al, bl;
|
||||
uint128_t hi, mid;
|
||||
ah = a >> 64;
|
||||
bh = b >> 64;
|
||||
al = a & MASK_LO;
|
||||
bl = b & MASK_LO;
|
||||
hi = ah * bh;
|
||||
mid = ah * bl + al * bh;
|
||||
mid >>= 64;
|
||||
result = ah * bh + mid;
|
||||
return result;
|
||||
}
|
||||
HighPrecision
|
||||
HighPrecision::Invert (uint64_t v)
|
||||
{
|
||||
NS_ASSERT (v > 1);
|
||||
uint128_t a;
|
||||
a = 1;
|
||||
a <<= 64;
|
||||
HighPrecision result;
|
||||
result.m_value = Divu (a, v);
|
||||
HighPrecision tmp = HighPrecision (v, false);
|
||||
tmp.MulByInvert (result);
|
||||
if (tmp.GetInteger () != 1)
|
||||
{
|
||||
result.m_value += 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
@@ -24,19 +24,37 @@
|
||||
#include <math.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define noCOUNT_OPS 1
|
||||
|
||||
#if defined(HAVE___UINT128_T) and !defined(HAVE_UINT128_T)
|
||||
typedef __uint128_t uint128_t;
|
||||
typedef __int128_t int128_t;
|
||||
#endif
|
||||
|
||||
#ifdef COUNT_OPS
|
||||
#define INC_ADD HighPrecision::g_nAdd++
|
||||
#define INC_SUB HighPrecision::g_nAdd++
|
||||
#define INC_MUL HighPrecision::g_nMul++
|
||||
#define INC_DIV HighPrecision::g_nDiv++
|
||||
#define INC_MULI HighPrecision::g_nMuli++
|
||||
#define INC_CMP HighPrecision::g_nCmp++
|
||||
#else
|
||||
#define INC_ADD
|
||||
#define INC_SUB
|
||||
#define INC_MUL
|
||||
#define INC_DIV
|
||||
#define INC_MULI
|
||||
#define INC_CMP
|
||||
#endif
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
class HighPrecision
|
||||
{
|
||||
public:
|
||||
inline HighPrecision ();
|
||||
inline HighPrecision (int64_t value, bool dummy);
|
||||
inline HighPrecision (double value);
|
||||
explicit inline HighPrecision (int64_t value, bool dummy);
|
||||
explicit inline HighPrecision (double value);
|
||||
|
||||
inline int64_t GetInteger (void) const;
|
||||
inline double GetDouble (void) const;
|
||||
@@ -44,11 +62,28 @@ public:
|
||||
inline void Sub (HighPrecision const &o);
|
||||
void Mul (HighPrecision const &o);
|
||||
void Div (HighPrecision const &o);
|
||||
void MulByInvert (const HighPrecision &o);
|
||||
static HighPrecision Invert (uint64_t v);
|
||||
|
||||
inline int Compare (HighPrecision const &o) const;
|
||||
inline static HighPrecision Zero (void);
|
||||
private:
|
||||
static uint128_t UmulByInvert (uint128_t a, uint128_t b);
|
||||
static uint128_t Umul (uint128_t a, uint128_t b);
|
||||
static uint128_t Divu (uint128_t a, uint128_t b);
|
||||
|
||||
int128_t m_value;
|
||||
|
||||
#ifdef COUNT_OPS
|
||||
static uint128_t g_nAdd;
|
||||
static uint128_t g_nMuli;
|
||||
static uint128_t g_nMul;
|
||||
static uint128_t g_nDiv;
|
||||
static uint128_t g_nCmp;
|
||||
static struct Printer {
|
||||
~Printer ();
|
||||
} g_printer;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
@@ -75,17 +110,20 @@ int64_t HighPrecision::GetInteger (void) const
|
||||
void
|
||||
HighPrecision::Add (HighPrecision const &o)
|
||||
{
|
||||
INC_ADD;
|
||||
m_value += o.m_value;
|
||||
}
|
||||
void
|
||||
HighPrecision::Sub (HighPrecision const &o)
|
||||
{
|
||||
INC_SUB;
|
||||
m_value -= o.m_value;
|
||||
}
|
||||
|
||||
int
|
||||
HighPrecision::Compare (HighPrecision const &o) const
|
||||
{
|
||||
INC_CMP;
|
||||
return (m_value < o.m_value)?-1:(m_value == o.m_value)?0:1;
|
||||
}
|
||||
|
||||
|
||||
@@ -19,17 +19,31 @@
|
||||
*/
|
||||
#include "high-precision-cairo.h"
|
||||
#include "ns3/test.h"
|
||||
#include "ns3/fatal-error.h"
|
||||
#include "ns3/abort.h"
|
||||
#include "ns3/assert.h"
|
||||
#include <math.h>
|
||||
#include <iostream>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
|
||||
#define OUTPUT_SIGN(sa,sb,ua,ub) \
|
||||
({bool negA, negB; \
|
||||
negA = _cairo_int128_negative (sa); \
|
||||
negB = _cairo_int128_negative (sb); \
|
||||
ua = _cairo_int128_to_uint128 (sa); \
|
||||
ub = _cairo_int128_to_uint128 (sb); \
|
||||
ua = negA ? _cairo_uint128_negate (ua) : ua; \
|
||||
ub = negB ? _cairo_uint128_negate (ub) : ub; \
|
||||
(negA && !negB) || (!negA && negB);})
|
||||
|
||||
void
|
||||
HighPrecision::Mul (HighPrecision const &o)
|
||||
{
|
||||
// use the 128 bits multiplication
|
||||
m_value = Mul128 (m_value,o.m_value);
|
||||
cairo_uint128_t a, b, result;
|
||||
bool sign = OUTPUT_SIGN (m_value, o.m_value, a, b);
|
||||
result = Umul (a, b);
|
||||
m_value = sign ? _cairo_uint128_negate (result) : result;
|
||||
}
|
||||
|
||||
|
||||
@@ -39,22 +53,9 @@ HighPrecision::Mul (HighPrecision const &o)
|
||||
* as the fractional part. It takes into account the sign
|
||||
* of the operands to produce a signed 128 bits result.
|
||||
*/
|
||||
cairo_int128_t
|
||||
HighPrecision::Mul128 (cairo_int128_t sa, cairo_int128_t sb ) const
|
||||
cairo_uint128_t
|
||||
HighPrecision::Umul (cairo_uint128_t a, cairo_uint128_t b)
|
||||
{
|
||||
bool negResult, negA, negB;
|
||||
|
||||
negA = _cairo_int128_negative (sa);
|
||||
negB = _cairo_int128_negative (sb);
|
||||
// the result is negative only if one of the operand is negative
|
||||
negResult = (negA && !negB) || (!negA && negB);
|
||||
// now take the absolute part to make sure that the resulting operands are positive
|
||||
cairo_uint128_t a, b;
|
||||
a = _cairo_int128_to_uint128 (sa);
|
||||
b = _cairo_int128_to_uint128 (sb);
|
||||
a = negA ? _cairo_uint128_negate (a) : a;
|
||||
b = negB ? _cairo_uint128_negate (b) : b;
|
||||
|
||||
cairo_uint128_t result;
|
||||
cairo_uint128_t hiPart,loPart,midPart;
|
||||
|
||||
@@ -73,38 +74,23 @@ HighPrecision::Mul128 (cairo_int128_t sa, cairo_int128_t sb ) const
|
||||
// truncate the high part and only use the low part
|
||||
result.hi = _cairo_uint64_add (hiPart.lo,midPart.hi);
|
||||
// if the high part is not zero, put a warning
|
||||
if (hiPart.hi != 0)
|
||||
{
|
||||
NS_FATAL_ERROR ("High precision 128 bits multiplication error: multiplication overflow.");
|
||||
}
|
||||
// add the sign to the result
|
||||
result = negResult ? _cairo_uint128_negate (result) : result;
|
||||
return _cairo_uint128_to_int128 (result);
|
||||
NS_ABORT_MSG_IF (hiPart.hi != 0,
|
||||
"High precision 128 bits multiplication error: multiplication overflow.");
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
HighPrecision::Div (HighPrecision const &o)
|
||||
{
|
||||
cairo_int128_t result = Div128 (m_value, o.m_value);
|
||||
m_value = result;
|
||||
cairo_uint128_t a, b, result;
|
||||
bool sign = OUTPUT_SIGN (m_value, o.m_value, a, b);
|
||||
result = Udiv (a, b);
|
||||
m_value = sign ? _cairo_uint128_negate (result) : result;
|
||||
}
|
||||
|
||||
cairo_int128_t
|
||||
HighPrecision::Div128 (cairo_int128_t sa, cairo_int128_t sb) const
|
||||
cairo_uint128_t
|
||||
HighPrecision::Udiv (cairo_uint128_t a, cairo_uint128_t b)
|
||||
{
|
||||
bool negResult, negA, negB;
|
||||
// take the sign of the operands
|
||||
negA = _cairo_int128_negative (sa);
|
||||
negB = _cairo_int128_negative (sb);
|
||||
// the result is negative only if one of the operand is negative
|
||||
negResult = (negA && !negB) || (!negA && negB);
|
||||
// now take the absolute part to make sure that the resulting operands are positive
|
||||
cairo_uint128_t a, b;
|
||||
a = _cairo_int128_to_uint128 (sa);
|
||||
b = _cairo_int128_to_uint128 (sb);
|
||||
a = negA ? _cairo_uint128_negate (a) : a;
|
||||
b = negB ? _cairo_uint128_negate (b) : b;
|
||||
|
||||
cairo_uquorem128_t qr = _cairo_uint128_divrem (a, b);
|
||||
cairo_uint128_t result = _cairo_uint128_lsl (qr.quo, 64);
|
||||
// Now, manage the remainder
|
||||
@@ -123,9 +109,56 @@ HighPrecision::Div128 (cairo_int128_t sa, cairo_int128_t sb) const
|
||||
}
|
||||
qr = _cairo_uint128_divrem (rem, div);
|
||||
result = _cairo_uint128_add (result, qr.quo);
|
||||
result = negResult ? _cairo_uint128_negate (result) : result;
|
||||
return _cairo_uint128_to_int128 (result);
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
HighPrecision::MulByInvert (const HighPrecision &o)
|
||||
{
|
||||
bool negResult = _cairo_int128_negative (m_value);
|
||||
cairo_uint128_t a = negResult?_cairo_int128_negate(m_value):m_value;
|
||||
cairo_uint128_t result = UmulByInvert (a, o.m_value);
|
||||
|
||||
m_value = negResult?_cairo_int128_negate(result):result;
|
||||
}
|
||||
cairo_uint128_t
|
||||
HighPrecision::UmulByInvert (cairo_uint128_t a, cairo_uint128_t b)
|
||||
{
|
||||
cairo_uint128_t result;
|
||||
cairo_uint128_t hi, mid;
|
||||
hi = _cairo_uint64x64_128_mul (a.hi, b.hi);
|
||||
mid = _cairo_uint128_add (_cairo_uint64x64_128_mul (a.hi, b.lo),
|
||||
_cairo_uint64x64_128_mul (a.lo, b.hi));
|
||||
mid.lo = mid.hi;
|
||||
mid.hi = 0;
|
||||
result = _cairo_uint128_add (hi,mid);
|
||||
return result;
|
||||
}
|
||||
HighPrecision
|
||||
HighPrecision::Invert (uint64_t v)
|
||||
{
|
||||
NS_ASSERT (v > 1);
|
||||
cairo_uint128_t a, factor;
|
||||
a.hi = 1;
|
||||
a.lo = 0;
|
||||
factor.hi = 0;
|
||||
factor.lo = v;
|
||||
HighPrecision result;
|
||||
result.m_value = Udiv (a, factor);
|
||||
HighPrecision tmp = HighPrecision (v, false);
|
||||
tmp.MulByInvert (result);
|
||||
if (tmp.GetInteger () != 1)
|
||||
{
|
||||
cairo_uint128_t one = {1, 0};
|
||||
result.m_value = _cairo_uint128_add (result.m_value, one);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
// include directly to allow optimizations within the compilation unit.
|
||||
extern "C" {
|
||||
#include "cairo-wideint.c"
|
||||
}
|
||||
|
||||
@@ -37,37 +37,6 @@
|
||||
* Division operations (there are really really super costly)
|
||||
* and Comparison operations (because there are typically a lot of
|
||||
* these in any complex timekeeping code).
|
||||
*
|
||||
* So, the code tries really hard to perform any of these 128 bit
|
||||
* operations by doing all arithmetic on 64 bit integers when possible
|
||||
* (i.e., when there is no fractional part. This is a very common case).
|
||||
* Hence, the following code has a m_fastValue (64 bits) and a
|
||||
* m_slowValue (128 bits). m_fastValue is used by default and the code
|
||||
* converts it to a m_slowValue when needed.
|
||||
*
|
||||
* If you want to monitor the efficiency of this strategy, you can
|
||||
* enable the macro HP128INC below and call the HighPrecision::PrintStats
|
||||
* method at the end of the simulation.
|
||||
*
|
||||
* Explanation of Slow and Fast values:
|
||||
*
|
||||
* HighPrecision class create a fastValue and a slowValue depending on the
|
||||
* input number. If the input is an integer with 0 fractional part, it will
|
||||
* use the fastValue which will contain the integer in a 64 bits format. If
|
||||
* it has a fractional part, the slowValue will be used. It is represented
|
||||
* simply as a high part slowValue.hi which will contain the integer part
|
||||
* and the fractional part slowValue.lo which will contain the factional
|
||||
* part as an integer (obtained by multiplying the fractional part by 2^64).
|
||||
*
|
||||
* Explanation of Slow and Fast operations:
|
||||
*
|
||||
* If both operands are fastValues, we will perform fast operations, i-e
|
||||
* simply using integer operations. If we have though one of the value is
|
||||
* slowValue we need to convert the fastValue into a slow one. It is simply
|
||||
* obtained by putting the slowValue.lo = 0 and slowValue.hi = fastValue.
|
||||
* After that we apply the slow operation which will be a 128 bits operation
|
||||
* with two 128 bits operands.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace ns3 {
|
||||
@@ -76,8 +45,8 @@ class HighPrecision
|
||||
{
|
||||
public:
|
||||
inline HighPrecision ();
|
||||
inline HighPrecision (int64_t value, bool dummy);
|
||||
inline HighPrecision (double value);
|
||||
explicit inline HighPrecision (int64_t value, bool dummy);
|
||||
explicit inline HighPrecision (double value);
|
||||
|
||||
inline int64_t GetInteger (void) const;
|
||||
inline double GetDouble (void) const;
|
||||
@@ -85,12 +54,15 @@ public:
|
||||
inline void Sub (HighPrecision const &o);
|
||||
void Mul (HighPrecision const &o);
|
||||
void Div (HighPrecision const &o);
|
||||
void MulByInvert (const HighPrecision &o);
|
||||
static HighPrecision Invert (uint64_t v);
|
||||
|
||||
inline int Compare (HighPrecision const &o) const;
|
||||
inline static HighPrecision Zero (void);
|
||||
private:
|
||||
cairo_uint128_t Mul128 (cairo_uint128_t, cairo_uint128_t ) const;
|
||||
cairo_int128_t Div128 (cairo_int128_t sa, cairo_int128_t sb) const;
|
||||
static cairo_uint128_t Umul (cairo_uint128_t a, cairo_uint128_t b);
|
||||
static cairo_uint128_t Udiv (cairo_uint128_t a, cairo_uint128_t b);
|
||||
static cairo_uint128_t UmulByInvert (cairo_uint128_t a, cairo_uint128_t b);
|
||||
inline bool IsNegative (void) const;
|
||||
|
||||
cairo_int128_t m_value;
|
||||
|
||||
@@ -35,8 +35,8 @@ class HighPrecision
|
||||
{
|
||||
public:
|
||||
inline HighPrecision ();
|
||||
inline HighPrecision (int64_t value, bool dummy);
|
||||
inline HighPrecision (double value);
|
||||
explicit inline HighPrecision (int64_t value, bool dummy);
|
||||
explicit inline HighPrecision (double value);
|
||||
|
||||
inline int64_t GetInteger (void) const;
|
||||
inline double GetDouble (void) const;
|
||||
@@ -44,6 +44,8 @@ public:
|
||||
inline void Sub (HighPrecision const &o);
|
||||
inline void Mul (HighPrecision const &o);
|
||||
inline void Div (HighPrecision const &o);
|
||||
inline void MulByInvert (const HighPrecision &o);
|
||||
inline static HighPrecision Invert (uint64_t v);
|
||||
|
||||
inline int Compare (HighPrecision const &o) const;
|
||||
inline static HighPrecision Zero (void);
|
||||
@@ -101,10 +103,21 @@ HighPrecision::Div (HighPrecision const &o)
|
||||
{
|
||||
m_value /= o.m_value;
|
||||
}
|
||||
void
|
||||
HighPrecision::MulByInvert (const HighPrecision &o)
|
||||
{
|
||||
m_value *= o.m_value;
|
||||
}
|
||||
HighPrecision
|
||||
HighPrecision::Invert (uint64_t v)
|
||||
{
|
||||
return HighPrecision (1.0 / v);
|
||||
}
|
||||
|
||||
int
|
||||
HighPrecision::Compare (HighPrecision const &o) const
|
||||
{
|
||||
return m_value < o.m_value;
|
||||
return (m_value < o.m_value)?-1:(m_value == o.m_value)?0:1;
|
||||
}
|
||||
HighPrecision
|
||||
HighPrecision::Zero (void)
|
||||
|
||||
@@ -282,6 +282,70 @@ Hp128CompareTestCase::DoRun (void)
|
||||
return false;
|
||||
}
|
||||
|
||||
class Hp128InvertTestCase : public TestCase
|
||||
{
|
||||
public:
|
||||
Hp128InvertTestCase ();
|
||||
virtual bool DoRun (void);
|
||||
};
|
||||
|
||||
Hp128InvertTestCase::Hp128InvertTestCase ()
|
||||
: TestCase ("Test case for invertion")
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
Hp128InvertTestCase::DoRun (void)
|
||||
{
|
||||
#define TEST(factor) \
|
||||
do { \
|
||||
HighPrecision a; \
|
||||
a = HighPrecision::Invert (factor); \
|
||||
HighPrecision b = V (factor); \
|
||||
b.MulByInvert (a); \
|
||||
NS_TEST_ASSERT_MSG_EQ (b.GetInteger (), 1, \
|
||||
"x * 1/x should be 1 for x=" << factor); \
|
||||
HighPrecision c = V (1); \
|
||||
c.MulByInvert (a); \
|
||||
NS_TEST_ASSERT_MSG_EQ (c.GetInteger (), 0, \
|
||||
"1 * 1/x should be 0 for x=" << factor); \
|
||||
HighPrecision d = V (1); \
|
||||
d.Div (V(factor)); \
|
||||
NS_TEST_ASSERT_MSG_EQ (d.GetDouble (), c.GetDouble (), \
|
||||
"1 * 1/x should be equal to 1/x for x=" << factor); \
|
||||
HighPrecision e = V (-factor); \
|
||||
e.MulByInvert (a); \
|
||||
NS_TEST_ASSERT_MSG_EQ (e.GetInteger (), -1, \
|
||||
"-x * 1/x should be -1 for x=" << factor); \
|
||||
} while(false)
|
||||
|
||||
TEST(2);
|
||||
TEST(3);
|
||||
TEST(4);
|
||||
TEST(5);
|
||||
TEST(6);
|
||||
TEST(10);
|
||||
TEST(99);
|
||||
TEST(100);
|
||||
TEST(1000);
|
||||
TEST(10000);
|
||||
TEST(100000);
|
||||
TEST(100000);
|
||||
TEST(1000000);
|
||||
TEST(10000000);
|
||||
TEST(100000000);
|
||||
TEST(1000000000);
|
||||
TEST(10000000000LL);
|
||||
TEST(100000000000LL);
|
||||
TEST(1000000000000LL);
|
||||
TEST(10000000000000LL);
|
||||
TEST(100000000000000LL);
|
||||
TEST(1000000000000000LL);
|
||||
#undef TEST
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
static class HighPrecision128TestSuite : public TestSuite
|
||||
{
|
||||
public:
|
||||
@@ -292,6 +356,7 @@ public:
|
||||
AddTestCase (new Hp128Bug455TestCase ());
|
||||
AddTestCase (new Hp128Bug863TestCase ());
|
||||
AddTestCase (new Hp128CompareTestCase ());
|
||||
AddTestCase (new Hp128InvertTestCase ());
|
||||
}
|
||||
} g_highPrecision128TestSuite;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -45,7 +45,7 @@ TypeId
|
||||
RealtimeSimulatorImpl::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::RealtimeSimulatorImpl")
|
||||
.SetParent<Object> ()
|
||||
.SetParent<SimulatorImpl> ()
|
||||
.AddConstructor<RealtimeSimulatorImpl> ()
|
||||
.AddAttribute ("SynchronizationMode",
|
||||
"What to do if the simulation cannot keep up with real time.",
|
||||
|
||||
14
src/simulator/simulator-impl.cc
Normal file
14
src/simulator/simulator-impl.cc
Normal file
@@ -0,0 +1,14 @@
|
||||
#include "simulator-impl.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
TypeId
|
||||
SimulatorImpl::GetTypeId (void)
|
||||
{
|
||||
static TypeId tid = TypeId ("ns3::SimulatorImpl")
|
||||
.SetParent<Object> ()
|
||||
;
|
||||
return tid;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
@@ -35,6 +35,8 @@ class Scheduler;
|
||||
class SimulatorImpl : public Object
|
||||
{
|
||||
public:
|
||||
static TypeId GetTypeId (void);
|
||||
|
||||
/**
|
||||
* Every event scheduled by the Simulator::insertAtDestroy method is
|
||||
* invoked. Then, we ensure that any memory allocated by the
|
||||
|
||||
@@ -112,49 +112,15 @@ Synchronizer::EventEnd (void)
|
||||
uint64_t
|
||||
Synchronizer::TimeStepToNanosecond (uint64_t ts)
|
||||
{
|
||||
switch (TimeStepPrecision::Get ()) {
|
||||
case TimeStepPrecision::S:
|
||||
return ts * 1000000000;
|
||||
case TimeStepPrecision::MS:
|
||||
return ts * 1000000;
|
||||
case TimeStepPrecision::US:
|
||||
return ts * 1000;
|
||||
case TimeStepPrecision::NS:
|
||||
return ts;
|
||||
case TimeStepPrecision::PS:
|
||||
return ts / 1000;
|
||||
case TimeStepPrecision::FS:
|
||||
return ts / 1000000;
|
||||
default:
|
||||
NS_ASSERT_MSG (false, "Synchronizer::TimeStepToNanosecond: "
|
||||
"Unexpected precision not implemented");
|
||||
return 0;
|
||||
}
|
||||
return TimeStep (ts).GetNanoSeconds ();
|
||||
}
|
||||
|
||||
uint64_t
|
||||
Synchronizer::NanosecondToTimeStep (uint64_t ns)
|
||||
{
|
||||
switch (TimeStepPrecision::Get ()) {
|
||||
case TimeStepPrecision::S:
|
||||
return ns / 1000000000;
|
||||
case TimeStepPrecision::MS:
|
||||
return ns / 1000000;
|
||||
case TimeStepPrecision::US:
|
||||
return ns / 1000;
|
||||
case TimeStepPrecision::NS:
|
||||
return ns;
|
||||
case TimeStepPrecision::PS:
|
||||
return ns * 1000;
|
||||
case TimeStepPrecision::FS:
|
||||
return ns * 1000000;
|
||||
default:
|
||||
NS_ASSERT_MSG (false, "Synchronizer::NanosecondToTimeStep: "
|
||||
"Unexpected precision not implemented");
|
||||
return 0;
|
||||
}
|
||||
return NanoSeconds (ns).GetTimeStep ();
|
||||
}
|
||||
|
||||
}; // namespace ns3
|
||||
} // namespace ns3
|
||||
|
||||
|
||||
|
||||
59
src/simulator/time-base.cc
Normal file
59
src/simulator/time-base.cc
Normal file
@@ -0,0 +1,59 @@
|
||||
#include "time-base.h"
|
||||
#include "ns3/assert.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
struct TimeBase::Resolution
|
||||
TimeBase::GetNsResolution (void)
|
||||
{
|
||||
struct Resolution resolution;
|
||||
SetResolution (TimeBase::NS, &resolution);
|
||||
return resolution;
|
||||
}
|
||||
void
|
||||
TimeBase::SetResolution (enum Unit resolution)
|
||||
{
|
||||
SetResolution (resolution, PeekResolution ());
|
||||
}
|
||||
void
|
||||
TimeBase::SetResolution (enum Unit unit, struct Resolution *resolution)
|
||||
{
|
||||
int8_t power [LAST] = {15, 12, 9, 6, 3, 0};
|
||||
for (int i = 0; i < TimeBase::LAST; i++)
|
||||
{
|
||||
int shift = power[i] - power[(int)unit];
|
||||
uint64_t factor = (uint64_t) pow (10, fabs (shift));
|
||||
struct Information *info = &resolution->info[i];
|
||||
info->factor = factor;
|
||||
if (shift == 0)
|
||||
{
|
||||
info->timeFrom = HighPrecision (1, false);
|
||||
info->timeTo = HighPrecision (1, false);
|
||||
info->toMul = true;
|
||||
info->fromMul = true;
|
||||
}
|
||||
else if (shift > 0)
|
||||
{
|
||||
info->timeFrom = HighPrecision (factor, false);
|
||||
info->timeTo = HighPrecision::Invert (factor);
|
||||
info->toMul = false;
|
||||
info->fromMul = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_ASSERT (shift < 0);
|
||||
info->timeFrom = HighPrecision::Invert (factor);
|
||||
info->timeTo = HighPrecision (factor, false);
|
||||
info->toMul = true;
|
||||
info->fromMul = false;
|
||||
}
|
||||
}
|
||||
resolution->unit = unit;
|
||||
}
|
||||
enum TimeBase::Unit
|
||||
TimeBase::GetResolution (void)
|
||||
{
|
||||
return PeekResolution ()->unit;
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
336
src/simulator/time-base.h
Normal file
336
src/simulator/time-base.h
Normal file
@@ -0,0 +1,336 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/*
|
||||
* Copyright (c) 2005,2006 INRIA
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation;
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
||||
*/
|
||||
#ifndef TIME_BASE_H
|
||||
#define TIME_BASE_H
|
||||
|
||||
#include "high-precision.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
/**
|
||||
* \ingroup time
|
||||
* \brief keep track of global simulation resolution
|
||||
*
|
||||
* This class is the base class for all time-related classes. It controls
|
||||
* the resolution of the underlying time value . The default resolution
|
||||
* is nanoseconds. That is, TimeStep (1).GetNanoSeconds () will return
|
||||
* 1. It is possible to either increase or decrease the resolution and the
|
||||
* code tries really hard to make this easy.
|
||||
*
|
||||
* If your resolution is X (say, nanoseconds) and if you create Time objects
|
||||
* with a lower resolution (say, picoseconds), don't expect that this
|
||||
* code will return 1: PicoSeconds (1).GetPicoSeconds (). It will most
|
||||
* likely return 0 because the Time object has only 64 bits of fractional
|
||||
* precision which means that PicoSeconds (1) is stored as a 64-bit aproximation
|
||||
* of 1/1000 in the Time object. If you later multiply it again by the exact
|
||||
* value 1000, the result is unlikely to be 1 exactly. It will be close to
|
||||
* 1 but not exactly 1.
|
||||
*
|
||||
* In general, it is thus a really bad idea to try to use time objects of a
|
||||
* resolution higher than the global resolution controlled through
|
||||
* TimeBase::SetResolution. If you do need to use picoseconds, it's thus best
|
||||
* to switch the global resolution to picoseconds to avoid nasty surprises.
|
||||
*
|
||||
* Another important issue to keep in mind is that if you increase the
|
||||
* global resolution, you also implicitely decrease the range of your simulation.
|
||||
* i.e., the global simulation time is stored in a 64 bit integer whose interpretation
|
||||
* will depend on the global resolution so, 2^64 picoseconds which is the maximum
|
||||
* duration of your simulation if the global resolution is picoseconds
|
||||
* is smaller than 2^64 nanoseconds which is the maximum duration of your simulation
|
||||
* if the global resolution is nanoseconds.
|
||||
*
|
||||
* Finally, don't even think about ever changing the global resolution after
|
||||
* creating Time objects: all Time objects created before the call to SetResolution
|
||||
* will contain values which are not updated to the new resolution. In practice,
|
||||
* the default value for the attributes of many models is indeed calculated
|
||||
* before the main function of the main program enters. Because of this, if you
|
||||
* use one of these models (and it's likely), it's going to be hard to change
|
||||
* the global simulation resolution in a way which gives reasonable results. This
|
||||
* issue has been filed as bug 954 in the ns-3 bugzilla installation.
|
||||
*/
|
||||
class TimeBase
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* The unit to use to interpret a number representing time
|
||||
*/
|
||||
enum Unit
|
||||
{
|
||||
S = 0,
|
||||
MS = 1,
|
||||
US = 2,
|
||||
NS = 3,
|
||||
PS = 4,
|
||||
FS = 5,
|
||||
LAST = 6
|
||||
};
|
||||
/**
|
||||
* \param resolution the new resolution to use
|
||||
*
|
||||
* Change the global resolution used to convert all
|
||||
* user-provided time values in Time objects and Time objects
|
||||
* in user-expected time units.
|
||||
*/
|
||||
static void SetResolution (enum Unit resolution);
|
||||
/**
|
||||
* \returns the current global resolution.
|
||||
*/
|
||||
static enum Unit GetResolution (void);
|
||||
/**
|
||||
* \param value to convert into a Time object
|
||||
* \param timeUnit the unit of the value to convert
|
||||
* \return a new Time object
|
||||
*
|
||||
* This method interprets the input value according to the input
|
||||
* unit and constructs a matching Time object.
|
||||
*
|
||||
* \sa FromDouble, ToDouble, ToInteger
|
||||
*/
|
||||
inline static TimeBase FromInteger (uint64_t value, enum Unit timeUnit);
|
||||
/**
|
||||
* \param value to convert into a Time object
|
||||
* \param timeUnit the unit of the value to convert
|
||||
* \return a new Time object
|
||||
*
|
||||
* \sa FromInteger, ToInteger, ToDouble
|
||||
*/
|
||||
inline static TimeBase FromDouble (double value, enum Unit timeUnit);
|
||||
/**
|
||||
* \param time a Time object
|
||||
* \param timeUnit the unit of the value to return
|
||||
*
|
||||
* Convert the input time into an integer value according to the requested
|
||||
* time unit.
|
||||
*/
|
||||
inline static uint64_t ToInteger (const TimeBase &time, enum Unit timeUnit);
|
||||
/**
|
||||
* \param time a Time object
|
||||
* \param timeUnit the unit of the value to return
|
||||
*
|
||||
* Convert the input time into a floating point value according to the requested
|
||||
* time unit.
|
||||
*/
|
||||
inline static double ToDouble (const TimeBase &time, enum Unit timeUnit);
|
||||
|
||||
inline TimeBase ();
|
||||
inline TimeBase (const TimeBase &o);
|
||||
inline TimeBase operator = (const TimeBase &o);
|
||||
inline TimeBase (const HighPrecision &data);
|
||||
/**
|
||||
* \return true if the time is zero, false otherwise.
|
||||
*/
|
||||
inline bool IsZero (void) const;
|
||||
/**
|
||||
* \return true if the time is negative or zero, false otherwise.
|
||||
*/
|
||||
inline bool IsNegative (void) const;
|
||||
/**
|
||||
* \return true if the time is positive or zero, false otherwise.
|
||||
*/
|
||||
inline bool IsPositive (void) const;
|
||||
/**
|
||||
* \return true if the time is strictly negative, false otherwise.
|
||||
*/
|
||||
inline bool IsStrictlyNegative (void) const;
|
||||
/**
|
||||
* \return true if the time is strictly positive, false otherwise.
|
||||
*/
|
||||
inline bool IsStrictlyPositive (void) const;
|
||||
|
||||
/**
|
||||
* This is really an internal method exported for the needs of
|
||||
* the implementation. Please, Do not try to use this method, ever.
|
||||
*
|
||||
* \return the ns3::HighPrecision object which holds the value
|
||||
* stored in this instance of Time type.
|
||||
*/
|
||||
inline HighPrecision const &GetHighPrecision (void) const;
|
||||
inline HighPrecision * PeekHighPrecision (void);
|
||||
|
||||
protected:
|
||||
HighPrecision m_data;
|
||||
private:
|
||||
struct Information
|
||||
{
|
||||
bool toMul;
|
||||
bool fromMul;
|
||||
uint64_t factor;
|
||||
HighPrecision timeTo;
|
||||
HighPrecision timeFrom;
|
||||
};
|
||||
struct Resolution
|
||||
{
|
||||
struct Information info[LAST];
|
||||
enum TimeBase::Unit unit;
|
||||
};
|
||||
|
||||
inline static struct Resolution *PeekResolution (void);
|
||||
inline static struct Information *PeekInformation (enum Unit timeUnit);
|
||||
static struct Resolution GetNsResolution (void);
|
||||
static void SetResolution (enum Unit unit, struct Resolution *resolution);
|
||||
inline static TimeBase From (HighPrecision tmp, enum Unit timeUnit);
|
||||
inline static HighPrecision To (const TimeBase &time, enum Unit timeUnit);
|
||||
};
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
TimeBase::TimeBase ()
|
||||
: m_data ()
|
||||
{
|
||||
}
|
||||
TimeBase::TimeBase (const TimeBase &o)
|
||||
: m_data (o.m_data)
|
||||
{
|
||||
}
|
||||
TimeBase TimeBase::operator = (const TimeBase &o)
|
||||
{
|
||||
m_data = o.m_data;
|
||||
return *this;
|
||||
}
|
||||
TimeBase::TimeBase (const HighPrecision &data)
|
||||
: m_data (data)
|
||||
{
|
||||
}
|
||||
|
||||
HighPrecision const &
|
||||
TimeBase::GetHighPrecision (void) const
|
||||
{
|
||||
return m_data;
|
||||
}
|
||||
|
||||
HighPrecision *
|
||||
TimeBase::PeekHighPrecision (void)
|
||||
{
|
||||
return &m_data;
|
||||
}
|
||||
|
||||
bool
|
||||
TimeBase::IsZero (void) const
|
||||
{
|
||||
return m_data.Compare (HighPrecision::Zero ()) == 0;
|
||||
}
|
||||
|
||||
bool
|
||||
TimeBase::IsNegative (void) const
|
||||
{
|
||||
return m_data.Compare (HighPrecision::Zero ()) <= 0;
|
||||
}
|
||||
|
||||
bool
|
||||
TimeBase::IsPositive (void) const
|
||||
{
|
||||
return m_data.Compare (HighPrecision::Zero ()) >= 0;
|
||||
}
|
||||
|
||||
bool
|
||||
TimeBase::IsStrictlyNegative (void) const
|
||||
{
|
||||
return m_data.Compare (HighPrecision::Zero ()) < 0;
|
||||
}
|
||||
|
||||
bool
|
||||
TimeBase::IsStrictlyPositive (void) const
|
||||
{
|
||||
return m_data.Compare (HighPrecision::Zero ()) > 0;
|
||||
}
|
||||
|
||||
struct TimeBase::Resolution *
|
||||
TimeBase::PeekResolution (void)
|
||||
{
|
||||
static struct TimeBase::Resolution resolution = GetNsResolution ();
|
||||
return &resolution;
|
||||
}
|
||||
struct TimeBase::Information *
|
||||
TimeBase::PeekInformation (enum Unit timeUnit)
|
||||
{
|
||||
return &(PeekResolution ()->info[timeUnit]);
|
||||
}
|
||||
TimeBase
|
||||
TimeBase::From (HighPrecision tmp, enum Unit timeUnit)
|
||||
{
|
||||
struct Information *info = PeekInformation (timeUnit);
|
||||
if (info->fromMul)
|
||||
{
|
||||
tmp.Mul (info->timeFrom);
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp.MulByInvert (info->timeFrom);
|
||||
}
|
||||
return TimeBase (tmp);
|
||||
}
|
||||
HighPrecision
|
||||
TimeBase::To (const TimeBase &time, enum Unit timeUnit)
|
||||
{
|
||||
struct Information *info = PeekInformation (timeUnit);
|
||||
HighPrecision tmp = time.GetHighPrecision ();
|
||||
if (info->toMul)
|
||||
{
|
||||
tmp.Mul (info->timeTo);
|
||||
}
|
||||
else
|
||||
{
|
||||
tmp.MulByInvert (info->timeTo);
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
TimeBase
|
||||
TimeBase::FromInteger (uint64_t value, enum Unit timeUnit)
|
||||
{
|
||||
struct Information *info = PeekInformation (timeUnit);
|
||||
if (info->fromMul)
|
||||
{
|
||||
value *= info->factor;
|
||||
return TimeBase (HighPrecision (value, false));
|
||||
}
|
||||
return From (HighPrecision (value, false), timeUnit);
|
||||
}
|
||||
TimeBase
|
||||
TimeBase::FromDouble (double value, enum Unit timeUnit)
|
||||
{
|
||||
return From (HighPrecision (value), timeUnit);
|
||||
}
|
||||
uint64_t
|
||||
TimeBase::ToInteger (const TimeBase &time, enum Unit timeUnit)
|
||||
{
|
||||
struct Information *info = PeekInformation (timeUnit);
|
||||
uint64_t v = time.m_data.GetInteger ();
|
||||
if (info->toMul)
|
||||
{
|
||||
v *= info->factor;
|
||||
}
|
||||
else
|
||||
{
|
||||
v /= info->factor;
|
||||
}
|
||||
return v;
|
||||
}
|
||||
double
|
||||
TimeBase::ToDouble (const TimeBase &time, enum Unit timeUnit)
|
||||
{
|
||||
return To (time, timeUnit).GetDouble ();
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#endif /* TIME_BASE_H */
|
||||
@@ -20,54 +20,18 @@
|
||||
* TimeStep support by Emmanuelle Laprise <emmanuelle.laprise@bluekazoo.ca>
|
||||
*/
|
||||
#include "nstime.h"
|
||||
#include "ns3/fatal-error.h"
|
||||
#include "ns3/abort.h"
|
||||
#include "ns3/global-value.h"
|
||||
#include "ns3/enum.h"
|
||||
#include "ns3/string.h"
|
||||
#include "ns3/object.h"
|
||||
#include "ns3/config.h"
|
||||
#include <math.h>
|
||||
#include <sstream>
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
namespace TimeStepPrecision {
|
||||
|
||||
static const uint64_t MS_FACTOR = (uint64_t)1000;
|
||||
static const uint64_t US_FACTOR = (uint64_t)1000000;
|
||||
static const uint64_t NS_FACTOR = (uint64_t)1000000 * (uint64_t)1000;
|
||||
static const uint64_t PS_FACTOR = (uint64_t)1000000 * (uint64_t)1000000;
|
||||
static const uint64_t FS_FACTOR = (uint64_t)1000000 * (uint64_t)1000000 * (uint64_t)1000;
|
||||
static uint64_t g_tsPrecFactor = NS_FACTOR;
|
||||
|
||||
static GlobalValue g_precisionDefaultValue ("TimeStepPrecision",
|
||||
"The time unit of the internal 64 bit integer time.",
|
||||
EnumValue (NS),
|
||||
MakeEnumChecker (NS, "NS",
|
||||
S, "S",
|
||||
MS, "MS",
|
||||
US, "US",
|
||||
PS, "PS",
|
||||
FS, "FS")
|
||||
);
|
||||
|
||||
precision_t
|
||||
Get (void)
|
||||
{
|
||||
EnumValue v;
|
||||
g_precisionDefaultValue.GetValue (v);
|
||||
return (precision_t) v.Get ();
|
||||
}
|
||||
|
||||
void
|
||||
Set (precision_t precision)
|
||||
{
|
||||
g_precisionDefaultValue.SetValue (EnumValue (precision));
|
||||
g_tsPrecFactor = (uint64_t)pow (10, precision);
|
||||
}
|
||||
|
||||
} // namespace TimeStepPrecision
|
||||
|
||||
TimeUnit<1>::TimeUnit (const std::string& s)
|
||||
Time::Time (const std::string& s)
|
||||
{
|
||||
std::string::size_type n = s.find_first_not_of ("0123456789.");
|
||||
if (n != std::string::npos)
|
||||
@@ -79,40 +43,35 @@ TimeUnit<1>::TimeUnit (const std::string& s)
|
||||
std::string trailer = s.substr (n, std::string::npos);
|
||||
if (trailer == std::string ("s"))
|
||||
{
|
||||
m_data = HighPrecision (r * TimeStepPrecision::g_tsPrecFactor);
|
||||
*this = Time::FromDouble (r, Time::S);
|
||||
return;
|
||||
}
|
||||
if (trailer == std::string ("ms"))
|
||||
{
|
||||
m_data = HighPrecision ((int64_t)(r * (TimeStepPrecision::g_tsPrecFactor / pow (10,3))),
|
||||
false);
|
||||
*this = Time::FromDouble (r, Time::MS);
|
||||
return;
|
||||
}
|
||||
if (trailer == std::string ("us"))
|
||||
{
|
||||
m_data = HighPrecision ((int64_t)(r * (TimeStepPrecision::g_tsPrecFactor / pow (10,6))),
|
||||
false);
|
||||
*this = Time::FromDouble (r, Time::US);
|
||||
return;
|
||||
}
|
||||
if (trailer == std::string ("ns"))
|
||||
{
|
||||
m_data = HighPrecision ((int64_t)(r * (TimeStepPrecision::g_tsPrecFactor / pow (10,9))),
|
||||
false);
|
||||
*this = Time::FromDouble (r, Time::NS);
|
||||
return;
|
||||
}
|
||||
if (trailer == std::string ("ps"))
|
||||
{
|
||||
m_data = HighPrecision ((int64_t)(r * (TimeStepPrecision::g_tsPrecFactor / pow (10,12))),
|
||||
false);
|
||||
*this = Time::FromDouble (r, Time::PS);
|
||||
return;
|
||||
}
|
||||
if (trailer == std::string ("fs"))
|
||||
{
|
||||
m_data = HighPrecision ((int64_t)(r * (TimeStepPrecision::g_tsPrecFactor / pow (10,15))),
|
||||
false);
|
||||
*this = Time::FromDouble (r, Time::FS);
|
||||
return;
|
||||
}
|
||||
NS_FATAL_ERROR ("Can't Parse Time " << s);
|
||||
NS_ABORT_MSG ("Can't Parse Time " << s);
|
||||
}
|
||||
// else
|
||||
// they didn't provide units, assume seconds
|
||||
@@ -120,84 +79,60 @@ TimeUnit<1>::TimeUnit (const std::string& s)
|
||||
iss.str (s);
|
||||
double v;
|
||||
iss >> v;
|
||||
m_data = HighPrecision (v * TimeStepPrecision::g_tsPrecFactor);
|
||||
*this = Time::FromDouble (v, Time::S);
|
||||
}
|
||||
|
||||
double
|
||||
TimeUnit<1>::GetSeconds (void) const
|
||||
{
|
||||
double timeValue = GetHighPrecision ().GetDouble ();
|
||||
return timeValue / TimeStepPrecision::g_tsPrecFactor;
|
||||
struct Time::Resolution
|
||||
Time::GetNsResolution (void)
|
||||
{
|
||||
struct Resolution resolution;
|
||||
SetResolution (Time::NS, &resolution);
|
||||
return resolution;
|
||||
}
|
||||
|
||||
int64_t
|
||||
TimeUnit<1>::ConvertToUnits (int64_t timeValue, uint64_t unitFactor) const
|
||||
void
|
||||
Time::SetResolution (enum Unit resolution)
|
||||
{
|
||||
uint64_t precFactor;
|
||||
// In order to avoid conversion to double, precFactor can't be less 1
|
||||
if (TimeStepPrecision::g_tsPrecFactor < unitFactor)
|
||||
SetResolution (resolution, PeekResolution ());
|
||||
}
|
||||
void
|
||||
Time::SetResolution (enum Unit unit, struct Resolution *resolution)
|
||||
{
|
||||
int8_t power [LAST] = {15, 12, 9, 6, 3, 0};
|
||||
for (int i = 0; i < Time::LAST; i++)
|
||||
{
|
||||
precFactor = unitFactor / TimeStepPrecision::g_tsPrecFactor;
|
||||
timeValue = timeValue * precFactor;
|
||||
int shift = power[i] - power[(int)unit];
|
||||
uint64_t factor = (uint64_t) pow (10, fabs (shift));
|
||||
struct Information *info = &resolution->info[i];
|
||||
info->factor = factor;
|
||||
if (shift == 0)
|
||||
{
|
||||
info->timeFrom = HighPrecision (1, false);
|
||||
info->timeTo = HighPrecision (1, false);
|
||||
info->toMul = true;
|
||||
info->fromMul = true;
|
||||
}
|
||||
else if (shift > 0)
|
||||
{
|
||||
info->timeFrom = HighPrecision (factor, false);
|
||||
info->timeTo = HighPrecision::Invert (factor);
|
||||
info->toMul = false;
|
||||
info->fromMul = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
NS_ASSERT (shift < 0);
|
||||
info->timeFrom = HighPrecision::Invert (factor);
|
||||
info->timeTo = HighPrecision (factor, false);
|
||||
info->toMul = true;
|
||||
info->fromMul = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
precFactor = TimeStepPrecision::g_tsPrecFactor / unitFactor;
|
||||
timeValue = timeValue / precFactor;
|
||||
}
|
||||
return timeValue;
|
||||
resolution->unit = unit;
|
||||
}
|
||||
|
||||
|
||||
int64_t
|
||||
TimeUnit<1>::GetMilliSeconds (void) const
|
||||
enum Time::Unit
|
||||
Time::GetResolution (void)
|
||||
{
|
||||
int64_t ts = GetTimeStep ();
|
||||
int64_t ms = ConvertToUnits (ts, TimeStepPrecision::MS_FACTOR);
|
||||
|
||||
return ms;
|
||||
}
|
||||
int64_t
|
||||
TimeUnit<1>::GetMicroSeconds (void) const
|
||||
{
|
||||
int64_t ts = GetTimeStep ();
|
||||
int64_t us = ConvertToUnits (ts, TimeStepPrecision::US_FACTOR);
|
||||
|
||||
return us;
|
||||
}
|
||||
int64_t
|
||||
TimeUnit<1>::GetNanoSeconds (void) const
|
||||
{
|
||||
int64_t ts = GetTimeStep ();
|
||||
int64_t ns = ConvertToUnits (ts, TimeStepPrecision::NS_FACTOR);
|
||||
|
||||
return ns;
|
||||
}
|
||||
int64_t
|
||||
TimeUnit<1>::GetPicoSeconds (void) const
|
||||
{
|
||||
int64_t ts = GetTimeStep ();
|
||||
int64_t ps = ConvertToUnits (ts, TimeStepPrecision::PS_FACTOR);
|
||||
|
||||
return ps;
|
||||
}
|
||||
int64_t
|
||||
TimeUnit<1>::GetFemtoSeconds (void) const
|
||||
{
|
||||
int64_t ts = GetTimeStep ();
|
||||
int64_t fs = ConvertToUnits (ts, TimeStepPrecision::FS_FACTOR);
|
||||
|
||||
return fs;
|
||||
}
|
||||
|
||||
/**
|
||||
* This returns the value with the precision returned by TimeStepPrecision::Get
|
||||
*/
|
||||
int64_t
|
||||
TimeUnit<1>::GetTimeStep (void) const
|
||||
{
|
||||
int64_t timeValue = GetHighPrecision ().GetInteger ();
|
||||
return timeValue;
|
||||
return PeekResolution ()->unit;
|
||||
}
|
||||
|
||||
|
||||
@@ -205,491 +140,52 @@ std::ostream&
|
||||
operator<< (std::ostream& os, const Time & time)
|
||||
{
|
||||
std::string unit;
|
||||
switch (TimeStepPrecision::Get ())
|
||||
switch (Time::GetResolution ())
|
||||
{
|
||||
case TimeStepPrecision::S:
|
||||
case Time::S:
|
||||
unit = "s";
|
||||
break;
|
||||
case TimeStepPrecision::MS:
|
||||
case Time::MS:
|
||||
unit = "ms";
|
||||
break;
|
||||
case TimeStepPrecision::US:
|
||||
case Time::US:
|
||||
unit = "us";
|
||||
break;
|
||||
case TimeStepPrecision::NS:
|
||||
case Time::NS:
|
||||
unit = "ns";
|
||||
break;
|
||||
case TimeStepPrecision::PS:
|
||||
case Time::PS:
|
||||
unit = "ps";
|
||||
break;
|
||||
case TimeStepPrecision::FS:
|
||||
case Time::FS:
|
||||
unit = "fs";
|
||||
break;
|
||||
case Time::LAST:
|
||||
NS_ABORT_MSG ("can't be reached");
|
||||
unit = "unreachable";
|
||||
break;
|
||||
}
|
||||
os << time.GetTimeStep () << unit;
|
||||
double v = Time::ToDouble (time, Time::GetResolution ());
|
||||
os << v << unit;
|
||||
return os;
|
||||
}
|
||||
std::istream& operator>> (std::istream& is, Time & time)
|
||||
{
|
||||
std::string value;
|
||||
is >> value;
|
||||
std::string::size_type n = value.find_first_not_of ("0123456789.");
|
||||
if (n == std::string::npos)
|
||||
{
|
||||
is.setstate (std::ios_base::failbit);
|
||||
return is;
|
||||
}
|
||||
std::string trailer = value.substr (n, value.size () - n);
|
||||
std::istringstream iss;
|
||||
iss.str (value.substr (0, n));
|
||||
|
||||
if (trailer == std::string ("s"))
|
||||
{
|
||||
double v;
|
||||
iss >> v;
|
||||
time = Seconds (v);
|
||||
return is;
|
||||
}
|
||||
uint64_t integer;
|
||||
iss >> integer;
|
||||
if (is.bad () || is.fail ())
|
||||
{
|
||||
is.setstate (std::ios_base::failbit);
|
||||
}
|
||||
else if (trailer == std::string ("ms"))
|
||||
{
|
||||
time = MilliSeconds (integer);
|
||||
}
|
||||
else if (trailer == std::string ("us"))
|
||||
{
|
||||
time = MicroSeconds (integer);
|
||||
}
|
||||
else if (trailer == std::string ("ns"))
|
||||
{
|
||||
time = NanoSeconds (integer);
|
||||
}
|
||||
else if (trailer == std::string ("ps"))
|
||||
{
|
||||
time = PicoSeconds (integer);
|
||||
}
|
||||
else if (trailer == std::string ("fs"))
|
||||
{
|
||||
time = FemtoSeconds (integer);
|
||||
}
|
||||
else
|
||||
{
|
||||
is.setstate (std::ios_base::failbit);
|
||||
}
|
||||
time = Time (value);
|
||||
return is;
|
||||
}
|
||||
|
||||
Time Seconds (double seconds)
|
||||
{
|
||||
double d_sec = seconds * TimeStepPrecision::g_tsPrecFactor;
|
||||
return Time (HighPrecision (d_sec));
|
||||
// return Time (HighPrecision ((int64_t)d_sec, false));
|
||||
}
|
||||
|
||||
uint64_t
|
||||
TimeUnit<1>::UnitsToTimestep (uint64_t unitValue,
|
||||
uint64_t unitFactor)
|
||||
{
|
||||
uint64_t precFactor;
|
||||
// In order to avoid conversion to double, precFactor can't be less 1
|
||||
if (TimeStepPrecision::g_tsPrecFactor < unitFactor)
|
||||
{
|
||||
precFactor = unitFactor / TimeStepPrecision::g_tsPrecFactor;
|
||||
unitValue = unitValue / precFactor;
|
||||
}
|
||||
else
|
||||
{
|
||||
precFactor = TimeStepPrecision::g_tsPrecFactor / unitFactor;
|
||||
unitValue = unitValue * precFactor;
|
||||
}
|
||||
return unitValue;
|
||||
}
|
||||
|
||||
ATTRIBUTE_VALUE_IMPLEMENT (Time);
|
||||
ATTRIBUTE_CHECKER_IMPLEMENT (Time);
|
||||
|
||||
Time MilliSeconds (uint64_t ms)
|
||||
{
|
||||
uint64_t ts = TimeUnit<1>::UnitsToTimestep (ms, TimeStepPrecision::MS_FACTOR);
|
||||
return TimeStep (ts);
|
||||
}
|
||||
|
||||
Time MicroSeconds (uint64_t us)
|
||||
{
|
||||
uint64_t ts = TimeUnit<1>::UnitsToTimestep (us, TimeStepPrecision::US_FACTOR);
|
||||
return TimeStep (ts);
|
||||
}
|
||||
|
||||
Time NanoSeconds (uint64_t ns)
|
||||
{
|
||||
uint64_t ts = TimeUnit<1>::UnitsToTimestep (ns, TimeStepPrecision::NS_FACTOR);
|
||||
return TimeStep (ts);
|
||||
}
|
||||
Time PicoSeconds (uint64_t ps)
|
||||
{
|
||||
uint64_t ts = TimeUnit<1>::UnitsToTimestep (ps, TimeStepPrecision::PS_FACTOR);
|
||||
return TimeStep (ts);
|
||||
}
|
||||
Time FemtoSeconds (uint64_t fs)
|
||||
{
|
||||
uint64_t ts = TimeUnit<1>::UnitsToTimestep (fs, TimeStepPrecision::FS_FACTOR);
|
||||
return TimeStep (ts);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* The timestep value passed to this function must be of the precision
|
||||
* of TimeStepPrecision::Get
|
||||
*/
|
||||
Time TimeStep (uint64_t ts)
|
||||
{
|
||||
return Time (HighPrecision (ts, false));
|
||||
}
|
||||
|
||||
TimeUnit<0>::TimeUnit (double scalar)
|
||||
: m_data (HighPrecision (scalar))
|
||||
{
|
||||
}
|
||||
|
||||
double
|
||||
TimeUnit<0>::GetDouble (void) const
|
||||
{
|
||||
return GetHighPrecision ().GetDouble ();
|
||||
}
|
||||
|
||||
} // namespace ns3
|
||||
|
||||
#include "ns3/test.h"
|
||||
|
||||
namespace ns3 {
|
||||
|
||||
#define PRECISION(mult) (pow (10,-((double)(ns3::TimeStepPrecision::Get ()))) * mult)
|
||||
#define ASSERT_MSG_EQ(a,b,mult,msg) \
|
||||
NS_TEST_ASSERT_MSG_EQ (((a) < ((b) - PRECISION (mult)) || (a) > ((b) + PRECISION (mult))),false, \
|
||||
msg << " Values are not equal within requested precision range: " << \
|
||||
(a) << "!=" << (b) << " ~ " << PRECISION (mult))
|
||||
#define ASSERT_MSG_EQ_INT(a,b,mult,msg) \
|
||||
ASSERT_MSG_EQ (((int64_t)(a)),((int64_t)(b)),mult,msg)
|
||||
#define ASSERT_EQ(a,b) \
|
||||
ASSERT_MSG_EQ (a,b,1,"")
|
||||
|
||||
class OldTimeTestCase : public TestCase
|
||||
{
|
||||
public:
|
||||
OldTimeTestCase ();
|
||||
virtual bool DoRun (void);
|
||||
};
|
||||
|
||||
OldTimeTestCase::OldTimeTestCase ()
|
||||
: TestCase ("Sanity check of common time operations")
|
||||
{
|
||||
}
|
||||
bool
|
||||
OldTimeTestCase::DoRun (void)
|
||||
{
|
||||
NS_TEST_ASSERT_MSG_EQ (TimeStepPrecision::Get (),
|
||||
TimeStepPrecision::NS,
|
||||
"Invalid precision mode");
|
||||
|
||||
Time t0 = Seconds (10.0);
|
||||
ASSERT_EQ (t0.GetSeconds (), 10.0);
|
||||
|
||||
Time t1 = Seconds (11.0);
|
||||
ASSERT_EQ (t1.GetSeconds (), 11.0);
|
||||
|
||||
t0 = Seconds (1.5);
|
||||
ASSERT_EQ (t0.GetSeconds (), 1.5);
|
||||
|
||||
t0 = Seconds (-1.5);
|
||||
ASSERT_EQ (t0.GetSeconds (), -1.5);
|
||||
|
||||
t0 = MilliSeconds ((uint64_t)10.0);
|
||||
ASSERT_EQ (t0.GetSeconds (), 0.01);
|
||||
|
||||
t1 = MilliSeconds ((uint64_t)11.0);
|
||||
ASSERT_EQ (t1.GetSeconds (), 0.011);
|
||||
|
||||
|
||||
Time t2, t3;
|
||||
|
||||
t2 = t1 - t0;
|
||||
NS_TEST_ASSERT_MSG_EQ (t2.IsStrictlyPositive (),true, "Variable should be positive");
|
||||
ASSERT_EQ (t2.GetSeconds (), t1.GetSeconds () - t0.GetSeconds ());
|
||||
|
||||
t2 = t1 - t1;
|
||||
NS_TEST_ASSERT_MSG_EQ (t2.IsZero (),true, "Variable should be zero");
|
||||
ASSERT_EQ (t2.GetSeconds (), t1.GetSeconds () - t1.GetSeconds ());
|
||||
|
||||
t2 = t0 - t1;
|
||||
NS_TEST_ASSERT_MSG_EQ (t2.IsStrictlyNegative (),true, "Variable should be negative");
|
||||
ASSERT_EQ (t2.GetSeconds (), t0.GetSeconds () - t1.GetSeconds ());
|
||||
|
||||
Time tmp = MilliSeconds (0);
|
||||
NS_TEST_ASSERT_MSG_EQ ((MilliSeconds (0) == NanoSeconds (0)), true, "Zero is not Zero ?");
|
||||
NS_TEST_ASSERT_MSG_EQ ((MilliSeconds (0) > NanoSeconds (0)), false, "Zero is bigger than Zero ?");
|
||||
NS_TEST_ASSERT_MSG_EQ ((MilliSeconds (0) < NanoSeconds (0)), false, "Zero is smaller than Zero ?");
|
||||
|
||||
Time t4 = Seconds (10.0) * Scalar (1.5);
|
||||
ASSERT_EQ (t4.GetSeconds (), 15.0);
|
||||
|
||||
Time t5 = NanoSeconds (10) * Scalar (1.5);
|
||||
ASSERT_EQ (t5.GetNanoSeconds (), 15.0);
|
||||
|
||||
Time t6 = Seconds (10.0) * Scalar (15) / Scalar (10);
|
||||
ASSERT_EQ (t6.GetSeconds (), 15.0);
|
||||
|
||||
Time t7 = NanoSeconds (10) * Scalar (15) / Scalar (10);
|
||||
ASSERT_EQ (t7.GetNanoSeconds (), 15.0);
|
||||
|
||||
ASSERT_EQ ((t1 + t2).GetSeconds (), t1.GetSeconds () + t2.GetSeconds ());
|
||||
|
||||
ASSERT_EQ ((t1 / t2).GetDouble (), t1.GetSeconds () / t2.GetSeconds ());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
class OperationsTimeTestCase : public TestCase
|
||||
{
|
||||
public:
|
||||
OperationsTimeTestCase ();
|
||||
virtual bool DoRun (void);
|
||||
};
|
||||
|
||||
OperationsTimeTestCase::OperationsTimeTestCase ()
|
||||
: TestCase ("Check the +, -, * and / operators for the TimeUnit<1>")
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
OperationsTimeTestCase::DoRun (void)
|
||||
{
|
||||
// What happens if you set these values ?
|
||||
// t0 = Seconds ((uint64_t)10.0);
|
||||
// t1 = Seconds ((uint64_t)11.0);
|
||||
|
||||
Time t0 = MilliSeconds (10);
|
||||
Time t1 = MilliSeconds (11);
|
||||
|
||||
ASSERT_EQ ((t0 - t1).GetSeconds (),
|
||||
(t0.GetSeconds () - t1.GetSeconds ()));
|
||||
ASSERT_EQ (((t0 - t1) * t0 / t0).GetSeconds (),
|
||||
((t0.GetSeconds () - t1.GetSeconds ()) * t0.GetSeconds () / t0.GetSeconds ()));
|
||||
ASSERT_EQ (((t0 - t1) * t0 / t1).GetSeconds (),
|
||||
((t0.GetSeconds () - t1.GetSeconds ()) * t0.GetSeconds () / t1.GetSeconds ()));
|
||||
ASSERT_EQ ((t0 * (t0 - t1) / t1).GetSeconds (),
|
||||
(t0.GetSeconds () * (t0.GetSeconds () - t1.GetSeconds ()) / t1.GetSeconds ()));
|
||||
ASSERT_EQ ((t0 * t1 / (t0 - t1)).GetSeconds (),
|
||||
(t0.GetSeconds () * t1.GetSeconds () / (t0.GetSeconds () - t1.GetSeconds ())));
|
||||
ASSERT_EQ ((t0 * (t1 / (t0 - t1))).GetSeconds (),
|
||||
(t0.GetSeconds () * (t1.GetSeconds () / (t0.GetSeconds () - t1.GetSeconds ()))));
|
||||
ASSERT_EQ (((t0 * t1) / (t0 - t1)).GetSeconds (),
|
||||
((t0.GetSeconds () * t1.GetSeconds ()) / (t0.GetSeconds () - t1.GetSeconds ())));
|
||||
ASSERT_EQ ((t0 / t1 * (t0 - t1)).GetSeconds (),
|
||||
(t0.GetSeconds () / t1.GetSeconds () * (t0.GetSeconds () - t1.GetSeconds ())));
|
||||
ASSERT_EQ (((t0 / t1) * (t0 - t1)).GetSeconds (),
|
||||
(t0.GetSeconds () / t1.GetSeconds ()) * (t0.GetSeconds () - t1.GetSeconds ()));
|
||||
ASSERT_EQ ((t0 * Scalar (10.0)).GetSeconds (), (t0.GetSeconds () * 10.0));
|
||||
ASSERT_EQ ((Scalar (10.0) * t0).GetSeconds (), (10.0 * t0.GetSeconds ()));
|
||||
|
||||
// Note: we need to multiply by 1e9 because GetSeconds is multiplying
|
||||
ASSERT_EQ (((t0 / (t1 * (t0 - t1))).GetHighPrecision ().GetDouble () * 1e9),
|
||||
(t0.GetSeconds () / (t1.GetSeconds () * (t0.GetSeconds () - t1.GetSeconds ()))));
|
||||
|
||||
ASSERT_EQ ((t0 / t1).GetDouble (),(t0.GetSeconds () / t1.GetSeconds ()));
|
||||
|
||||
|
||||
ASSERT_EQ ((t0 * t1 / ((t0 - t1) * t0)).GetDouble (),
|
||||
(t0.GetSeconds () * t1.GetSeconds () / ((t0.GetSeconds () - t1.GetSeconds ()) * t0.GetSeconds ())));
|
||||
return false;
|
||||
}
|
||||
|
||||
class TimeStepTestCase : public TestCase
|
||||
{
|
||||
public:
|
||||
TimeStepTestCase ();
|
||||
virtual bool DoRun (void);
|
||||
};
|
||||
|
||||
TimeStepTestCase::TimeStepTestCase ()
|
||||
: TestCase ("Check boundaries of TimeStep")
|
||||
{
|
||||
}
|
||||
bool
|
||||
TimeStepTestCase::DoRun (void)
|
||||
{
|
||||
Time tooBig = TimeStep (0x8000000000000000LL);
|
||||
NS_TEST_ASSERT_MSG_EQ (tooBig.IsNegative (), true, "Is not negative ?");
|
||||
tooBig = TimeStep (0xffffffffffffffffLL);
|
||||
NS_TEST_ASSERT_MSG_EQ (tooBig.IsNegative (), true, "Is not negative ?");
|
||||
tooBig = TimeStep (0x7fffffffffffffffLL);
|
||||
NS_TEST_ASSERT_MSG_EQ (tooBig.IsPositive (), true, "Is not negative ?");
|
||||
tooBig += TimeStep (1);
|
||||
NS_TEST_ASSERT_MSG_EQ (tooBig.IsNegative (), true, "Is not negative ?");
|
||||
return false;
|
||||
}
|
||||
|
||||
class GlobalPrecisionTestCase : public TestCase
|
||||
{
|
||||
public:
|
||||
GlobalPrecisionTestCase ();
|
||||
virtual bool DoRun (void);
|
||||
virtual void DoTeardown (void);
|
||||
};
|
||||
|
||||
GlobalPrecisionTestCase::GlobalPrecisionTestCase ()
|
||||
: TestCase ("Check that global value actually changes the underlying precision")
|
||||
{
|
||||
}
|
||||
#define CHECK_PRECISION(prec) \
|
||||
Config::SetGlobal ("TimeStepPrecision", StringValue (# prec)); \
|
||||
NS_TEST_ASSERT_MSG_EQ (TimeStepPrecision::Get (), TimeStepPrecision::prec, "Could not set precision " << # prec)
|
||||
bool
|
||||
GlobalPrecisionTestCase::DoRun (void)
|
||||
{
|
||||
CHECK_PRECISION (S);
|
||||
CHECK_PRECISION (MS);
|
||||
CHECK_PRECISION (US);
|
||||
CHECK_PRECISION (NS);
|
||||
CHECK_PRECISION (PS);
|
||||
CHECK_PRECISION (FS);
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
GlobalPrecisionTestCase::DoTeardown (void)
|
||||
{
|
||||
TimeStepPrecision::Set (TimeStepPrecision::NS);
|
||||
}
|
||||
|
||||
#if 0
|
||||
// disable this test because it triggers crazy
|
||||
// compiler behavior (ICE+unbounded memory usage)
|
||||
class ConversionTestCase : public TestCase
|
||||
{
|
||||
public:
|
||||
ConversionTestCase ();
|
||||
virtual bool DoRun (void);
|
||||
virtual void DoTeardown (void);
|
||||
};
|
||||
|
||||
ConversionTestCase::ConversionTestCase ()
|
||||
: TestCase ("Check crazy time conversions")
|
||||
{
|
||||
}
|
||||
|
||||
void ConversionTestCase::DoTeardown (void)
|
||||
{
|
||||
TimeStepPrecision::Set (TimeStepPrecision::NS);
|
||||
}
|
||||
|
||||
#define CHECK_CONVERSIONS(tmp) \
|
||||
do { \
|
||||
double val = tmp; \
|
||||
Time t_sec = Seconds (val); \
|
||||
ASSERT_MSG_EQ (t_sec.GetSeconds (), val * 1e0, 1e0, "conv sec s"); \
|
||||
ASSERT_MSG_EQ_INT (t_sec.GetMilliSeconds (), val * 1e3, 1e3, "conv sec ms"); \
|
||||
ASSERT_MSG_EQ_INT (t_sec.GetMicroSeconds (), val * 1e6, 1e6, "conv sec us"); \
|
||||
ASSERT_MSG_EQ_INT (t_sec.GetNanoSeconds (), val * 1e9, 1e9, "conv sec ns"); \
|
||||
ASSERT_MSG_EQ_INT (t_sec.GetPicoSeconds (), val * 1e12, 1e12, "conv sec ps"); \
|
||||
ASSERT_MSG_EQ_INT (t_sec.GetFemtoSeconds (), val * 1e15, 1e15, "conv sec fs"); \
|
||||
uint64_t int_val = (uint64_t)val; \
|
||||
Time t_ms = MilliSeconds (int_val); \
|
||||
ASSERT_MSG_EQ (t_ms.GetSeconds (), val * 1e-3, 1e0, "conv ms s"); \
|
||||
ASSERT_MSG_EQ_INT (t_ms.GetMilliSeconds (), val * 1e0, 1e3, "conv ms ms"); \
|
||||
ASSERT_MSG_EQ_INT (t_ms.GetMicroSeconds (), val * 1e3, 1e6, "conv ms us"); \
|
||||
ASSERT_MSG_EQ_INT (t_ms.GetNanoSeconds (), val * 1e6, 1e9, "conv ms ns"); \
|
||||
ASSERT_MSG_EQ_INT (t_ms.GetPicoSeconds (), val * 1e9, 1e12, "conv ms fs"); \
|
||||
ASSERT_MSG_EQ_INT (t_ms.GetFemtoSeconds (), val * 1e12, 1e15, "conv ms ps"); \
|
||||
Time t_us = MicroSeconds (int_val); \
|
||||
ASSERT_MSG_EQ (t_us.GetSeconds (), val * 1e-6, 1e0, "conv us s"); \
|
||||
ASSERT_MSG_EQ_INT (t_us.GetMilliSeconds (), val * 1e-3, 1e3, "conv us ms"); \
|
||||
ASSERT_MSG_EQ_INT (t_us.GetMicroSeconds (), val * 1e0, 1e6, "conv us us"); \
|
||||
ASSERT_MSG_EQ_INT (t_us.GetNanoSeconds (), val * 1e3, 1e9, "conv us ns"); \
|
||||
ASSERT_MSG_EQ_INT (t_us.GetPicoSeconds (), val * 1e6, 1e12, "conv us ps"); \
|
||||
ASSERT_MSG_EQ_INT (t_us.GetFemtoSeconds (), val * 1e9, 1e15, "conv us fs"); \
|
||||
Time t_ns = NanoSeconds (int_val); \
|
||||
ASSERT_MSG_EQ (t_ns.GetSeconds (), val * 1e-9, 1e0, "conv ns s"); \
|
||||
ASSERT_MSG_EQ_INT (t_ns.GetMilliSeconds (), val * 1e-6, 1e3, "conv ns ms"); \
|
||||
ASSERT_MSG_EQ_INT (t_ns.GetMicroSeconds (), val * 1e-3, 1e6, "conv ns us"); \
|
||||
ASSERT_MSG_EQ_INT (t_ns.GetNanoSeconds (), val * 1e0, 1e9, "conv ns ns"); \
|
||||
ASSERT_MSG_EQ_INT (t_ns.GetPicoSeconds (), val * 1e3, 1e12, "conv ns ps"); \
|
||||
ASSERT_MSG_EQ_INT (t_ns.GetFemtoSeconds (), val * 1e6, 1e15, "conv ns fs"); \
|
||||
Time t_ps = PicoSeconds (int_val); \
|
||||
ASSERT_MSG_EQ (t_ps.GetSeconds (), val * 1e-12, 1e0, "conv ps s"); \
|
||||
ASSERT_MSG_EQ_INT (t_ps.GetMilliSeconds (), val * 1e-9, 1e3, "conv ps ms"); \
|
||||
ASSERT_MSG_EQ_INT (t_ps.GetMicroSeconds (), val * 1e-6, 1e6, "conv ps us"); \
|
||||
ASSERT_MSG_EQ_INT (t_ps.GetNanoSeconds (), val * 1e-3, 1e9, "conv ps ns"); \
|
||||
ASSERT_MSG_EQ_INT (t_ps.GetPicoSeconds (), val * 1e0, 1e12, "conv ps ps"); \
|
||||
ASSERT_MSG_EQ_INT (t_ps.GetFemtoSeconds (), val * 1e3, 1e15, "conv ps fs"); \
|
||||
Time t_fs = FemtoSeconds (int_val); \
|
||||
ASSERT_MSG_EQ (t_fs.GetSeconds (), val * 1e-15, 1e0, "conv fs sec"); \
|
||||
ASSERT_MSG_EQ_INT (t_fs.GetMilliSeconds (), val * 1e-12, 1e3, "conv fs ms"); \
|
||||
ASSERT_MSG_EQ_INT (t_fs.GetMicroSeconds (), val * 1e-9, 1e6, "conv fs us"); \
|
||||
ASSERT_MSG_EQ_INT (t_fs.GetNanoSeconds (), val * 1e-6, 1e9, "conv fs ns"); \
|
||||
ASSERT_MSG_EQ_INT (t_fs.GetPicoSeconds (), val * 1e-3, 1e12, "conv fs ps"); \
|
||||
ASSERT_MSG_EQ_INT (t_fs.GetFemtoSeconds (), val * 1e0, 1e15, "conv fs fs"); \
|
||||
} while (false)
|
||||
|
||||
bool
|
||||
ConversionTestCase::DoRun (void)
|
||||
{
|
||||
CHECK_CONVERSIONS (5);
|
||||
CHECK_CONVERSIONS (0);
|
||||
CHECK_CONVERSIONS (783);
|
||||
CHECK_CONVERSIONS (1132);
|
||||
// triggers overflow
|
||||
// XXX
|
||||
// CHECK_CONVERSIONS(3341039);
|
||||
|
||||
TimeStepPrecision::Set (TimeStepPrecision::US);
|
||||
CHECK_CONVERSIONS (7);
|
||||
CHECK_CONVERSIONS (546);
|
||||
CHECK_CONVERSIONS (6231);
|
||||
// triggers overflow
|
||||
// XXX
|
||||
// CHECK_CONVERSIONS(1234639);
|
||||
|
||||
TimeStepPrecision::Set (TimeStepPrecision::MS);
|
||||
CHECK_CONVERSIONS (3);
|
||||
CHECK_CONVERSIONS (134);
|
||||
CHECK_CONVERSIONS (2341);
|
||||
// triggers overflow
|
||||
// XXX
|
||||
// CHECK_CONVERSIONS(8956239);
|
||||
|
||||
TimeStepPrecision::Set (TimeStepPrecision::NS);
|
||||
CHECK_CONVERSIONS (4);
|
||||
CHECK_CONVERSIONS (342);
|
||||
CHECK_CONVERSIONS (1327);
|
||||
// triggers overflow
|
||||
// XXX
|
||||
// CHECK_CONVERSIONS(5439627);
|
||||
|
||||
TimeStepPrecision::Set (TimeStepPrecision::PS);
|
||||
CHECK_CONVERSIONS (4);
|
||||
CHECK_CONVERSIONS (342);
|
||||
CHECK_CONVERSIONS (1327);
|
||||
// triggers overflow
|
||||
// XXX
|
||||
// CHECK_CONVERSIONS(5439627);
|
||||
|
||||
TimeStepPrecision::Set (TimeStepPrecision::NS);
|
||||
CHECK_CONVERSIONS (12);
|
||||
|
||||
TimeStepPrecision::Set (TimeStepPrecision::S);
|
||||
CHECK_CONVERSIONS (7);
|
||||
|
||||
TimeStepPrecision::Set (TimeStepPrecision::FS);
|
||||
CHECK_CONVERSIONS (5);
|
||||
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
class Bug863TestCase : public TestCase
|
||||
{
|
||||
public:
|
||||
@@ -709,18 +205,100 @@ bool Bug863TestCase::DoRun (void)
|
||||
return false;
|
||||
}
|
||||
|
||||
class TimeSimpleTestCase : public TestCase
|
||||
{
|
||||
public:
|
||||
TimeSimpleTestCase (enum Time::Unit resolution);
|
||||
private:
|
||||
virtual bool DoRun (void);
|
||||
virtual void DoTearDown (void);
|
||||
enum Time::Unit m_originalResolution;
|
||||
enum Time::Unit m_resolution;
|
||||
};
|
||||
|
||||
TimeSimpleTestCase::TimeSimpleTestCase (enum Time::Unit resolution)
|
||||
: TestCase ("Sanity check of common time operations"),
|
||||
m_resolution (resolution)
|
||||
{}
|
||||
bool
|
||||
TimeSimpleTestCase::DoRun (void)
|
||||
{
|
||||
m_originalResolution = Time::GetResolution ();
|
||||
Time::SetResolution (m_resolution);
|
||||
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 (),
|
||||
"is 10 really 10 ?");
|
||||
NS_TEST_ASSERT_MSG_EQ (MilliSeconds (1).GetMilliSeconds (), 1,
|
||||
"is 1ms really 1ms ?");
|
||||
NS_TEST_ASSERT_MSG_EQ (MicroSeconds (1).GetMicroSeconds (), 1,
|
||||
"is 1us really 1us ?");
|
||||
#if 0
|
||||
Time ns = NanoSeconds (1);
|
||||
ns.GetNanoSeconds ();
|
||||
NS_TEST_ASSERT_MSG_EQ (NanoSeconds (1).GetNanoSeconds (), 1,
|
||||
"is 1ns really 1ns ?");
|
||||
NS_TEST_ASSERT_MSG_EQ (PicoSeconds (1).GetPicoSeconds (), 1,
|
||||
"is 1ps really 1ps ?");
|
||||
NS_TEST_ASSERT_MSG_EQ (FemtoSeconds (1).GetFemtoSeconds (), 1,
|
||||
"is 1fs really 1fs ?");
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
TimeSimpleTestCase::DoTearDown (void)
|
||||
{
|
||||
Time::SetResolution (m_originalResolution);
|
||||
}
|
||||
|
||||
class ArithTestCase : public TestCase
|
||||
{
|
||||
public:
|
||||
ArithTestCase ();
|
||||
private:
|
||||
virtual bool DoRun (void);
|
||||
};
|
||||
|
||||
ArithTestCase::ArithTestCase ()
|
||||
: TestCase ("check arithmetic operators")
|
||||
{
|
||||
}
|
||||
bool
|
||||
ArithTestCase::DoRun (void)
|
||||
{
|
||||
Time a, b, c;
|
||||
c = a + b;
|
||||
c = a * b;
|
||||
c = a / Seconds (1.0);
|
||||
c = a - b;
|
||||
c += a;
|
||||
c -= a;
|
||||
c /= Seconds (1.0);
|
||||
c *= a;
|
||||
bool x;
|
||||
x = a < b;
|
||||
x = a > b;
|
||||
x = a <= b;
|
||||
x = a >= b;
|
||||
x = a == b;
|
||||
x = a != b;
|
||||
//a = 1.0;
|
||||
//a = 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static class TimeTestSuite : public TestSuite
|
||||
{
|
||||
public:
|
||||
TimeTestSuite ()
|
||||
: TestSuite ("time", UNIT)
|
||||
{
|
||||
AddTestCase (new OldTimeTestCase ());
|
||||
AddTestCase (new OperationsTimeTestCase ());
|
||||
AddTestCase (new TimeStepTestCase ());
|
||||
AddTestCase (new GlobalPrecisionTestCase ());
|
||||
AddTestCase (new Bug863TestCase ());
|
||||
// AddTestCase(new ConversionTestCase());
|
||||
AddTestCase (new TimeSimpleTestCase (Time::US));
|
||||
AddTestCase (new ArithTestCase ());
|
||||
}
|
||||
} g_timeTestSuite;
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ def build(bld):
|
||||
sim = bld.create_ns3_module('simulator', ['core'])
|
||||
sim.source = [
|
||||
'high-precision.cc',
|
||||
'time-base.cc',
|
||||
'time.cc',
|
||||
'event-id.cc',
|
||||
'scheduler.cc',
|
||||
@@ -65,6 +66,7 @@ def build(bld):
|
||||
'ns2-calendar-scheduler.cc',
|
||||
'event-impl.cc',
|
||||
'simulator.cc',
|
||||
'simulator-impl.cc',
|
||||
'default-simulator-impl.cc',
|
||||
'timer.cc',
|
||||
'watchdog.cc',
|
||||
@@ -76,6 +78,7 @@ def build(bld):
|
||||
headers.module = 'simulator'
|
||||
headers.source = [
|
||||
'high-precision.h',
|
||||
'time-base.h',
|
||||
'nstime.h',
|
||||
'event-id.h',
|
||||
'event-impl.h',
|
||||
@@ -105,7 +108,7 @@ def build(bld):
|
||||
elif env['USE_HIGH_PRECISION_CAIRO']:
|
||||
sim.source.extend([
|
||||
'high-precision-cairo.cc',
|
||||
'cairo-wideint.c',
|
||||
# 'cairo-wideint.c',
|
||||
])
|
||||
headers.source.extend([
|
||||
'high-precision-cairo.h',
|
||||
|
||||
Reference in New Issue
Block a user