optimize Time arithmetic operations.

This commit is contained in:
Mathieu Lacage
2007-02-02 19:37:16 +01:00
parent 57b398139b
commit 48ae43c61e
2 changed files with 261 additions and 67 deletions

View File

@@ -20,48 +20,101 @@
*/
#include "high-precision-128.h"
#include <math.h>
#include <iostream>
namespace ns3 {
int HighPrecision::m_nfastadds = 0;
int HighPrecision::m_nfastsubs = 0;
int HighPrecision::m_nfastmuls = 0;
int HighPrecision::m_nfastcmps = 0;
int HighPrecision::m_nfastgets = 0;
int HighPrecision::m_nslowadds = 0;
int HighPrecision::m_nslowsubs = 0;
int HighPrecision::m_nslowmuls = 0;
int HighPrecision::m_nslowcmps = 0;
int HighPrecision::m_nslowgets = 0;
int HighPrecision::m_ndivs = 0;
int HighPrecision::m_nconversions = 0;
void
HighPrecision::PrintStats (void)
{
double nadds = m_nfastadds + m_nslowadds;
double nsubs = m_nfastsubs + m_nslowsubs;
double ncmps = m_nfastcmps + m_nslowcmps;
double nmuls = m_nfastmuls + m_nslowmuls;
double ngets = m_nfastgets + m_nslowgets;
double fast_add_ratio = m_nfastadds / nadds;
double fast_sub_ratio = m_nfastsubs / nsubs;
double fast_cmp_ratio = m_nfastcmps / ncmps;
double fast_mul_ratio = m_nfastmuls / nmuls;
double fast_get_ratio = m_nfastgets / ngets;
std::cout <<
"add="<<fast_add_ratio<<std::endl<<
"sub="<<fast_sub_ratio<<std::endl<<
"cmp="<<fast_cmp_ratio<<std::endl<<
"mul="<<fast_mul_ratio<<std::endl<<
"get="<<fast_get_ratio<<std::endl<<
"nadds="<<nadds<<std::endl<<
"nsubs="<<nsubs<<std::endl<<
"ncmps="<<ncmps<<std::endl<<
"nmuls="<<nmuls<<std::endl<<
"ngets="<<ngets<<std::endl<<
"ndivs="<<m_ndivs<<std::endl<<
"nconversions="<<m_nconversions<<std::endl
;
}
const double HighPrecision::MAX_64 = 18446744073709551615.0;
HighPrecision::HighPrecision ()
{
m_value = _cairo_int32_to_int128 (0);
// the following statement is not really needed but it
// is here for the sake of symetry. I doubt we will
// ever see this code in the profiles...
m_value = _cairo_int128_lsl (m_value, 64);
}
HighPrecision::HighPrecision (int64_t value, bool dummy)
{
m_value = _cairo_int64_to_int128 (value);
m_value = _cairo_int128_lsl (m_value, 64);
}
HighPrecision::HighPrecision (double value)
{
int64_t hi = (int64_t) floor (value);
uint64_t lo = (uint64_t) ((value - floor (value)) * MAX_64);
m_value = _cairo_int64_to_int128 (hi);
m_value = _cairo_int128_lsl (m_value, 64);
cairo_int128_t clo = _cairo_uint128_to_int128 (_cairo_uint64_to_uint128 (lo));
m_value = _cairo_int128_add (m_value, clo);
if (lo == 0)
{
m_isFast = true;
m_fastValue = hi;
return;
}
else
{
m_isFast = false;
m_slowValue = _cairo_int64_to_int128 (hi);
m_slowValue = _cairo_int128_lsl (m_slowValue, 64);
cairo_int128_t clo = _cairo_uint128_to_int128 (_cairo_uint64_to_uint128 (lo));
m_slowValue = _cairo_int128_add (m_slowValue, clo);
}
}
void
HighPrecision::EnsureSlow (void)
{
if (m_isFast)
{
HP128INC (m_nconversions++);
m_slowValue = _cairo_int64_to_int128 (m_fastValue);
m_slowValue = _cairo_int128_lsl (m_slowValue, 64);
m_isFast = false;
}
}
int64_t
HighPrecision::GetInteger (void) const
HighPrecision::SlowGetInteger (void) const
{
cairo_int128_t value = _cairo_int128_rsa (m_value, 64);
cairo_int128_t value = _cairo_int128_rsa (m_slowValue, 64);
return _cairo_int128_to_int64 (value);
}
double
HighPrecision::GetDouble (void) const
HighPrecision::SlowGetDouble (void) const
{
bool is_negative = _cairo_int128_negative (m_value);
cairo_int128_t value = is_negative?_cairo_int128_negate (m_value):m_value;
bool is_negative = _cairo_int128_negative (m_slowValue);
cairo_int128_t value = is_negative?_cairo_int128_negate (m_slowValue):m_slowValue;
cairo_int128_t hi = _cairo_int128_rsa (value, 64);
cairo_uint128_t lo = _cairo_int128_sub (value, _cairo_uint128_lsl (hi, 64));
double flo = _cairo_uint128_to_uint64 (lo);
@@ -72,50 +125,52 @@ HighPrecision::GetDouble (void) const
return retval;
}
bool
HighPrecision::Add (HighPrecision const &o)
HighPrecision::SlowAdd (HighPrecision const &o)
{
m_value = _cairo_int128_add (m_value, o.m_value);
EnsureSlow ();
const_cast<HighPrecision &> (o).EnsureSlow ();
m_slowValue = _cairo_int128_add (m_slowValue, o.m_slowValue);
return false;
}
bool
HighPrecision::Sub (HighPrecision const &o)
HighPrecision::SlowSub (HighPrecision const &o)
{
m_value = _cairo_int128_sub (m_value, o.m_value);
EnsureSlow ();
const_cast<HighPrecision &> (o).EnsureSlow ();
m_slowValue = _cairo_int128_sub (m_slowValue, o.m_slowValue);
return false;
}
bool
HighPrecision::Mul (HighPrecision const &o)
HighPrecision::SlowMul (HighPrecision const &o)
{
cairo_int128_t other = _cairo_int128_rsa (o.m_value, 64);
m_value = _cairo_int128_mul (m_value, other);
EnsureSlow ();
const_cast<HighPrecision &> (o).EnsureSlow ();
cairo_int128_t other = _cairo_int128_rsa (o.m_slowValue, 64);
m_slowValue = _cairo_int128_mul (m_slowValue, other);
return false;
}
bool
HighPrecision::Div (HighPrecision const &o)
{
#if 1
cairo_int128_t div = _cairo_int128_rsa (o.m_value, 64);
HP128INC (m_ndivs++);
EnsureSlow ();
const_cast<HighPrecision &> (o).EnsureSlow ();
cairo_int128_t div = _cairo_int128_rsa (o.m_slowValue, 64);
cairo_quorem128_t qr;
qr = _cairo_int128_divrem (m_value, div);
m_value = qr.quo;
#else
cairo_quorem128_t qr;
qr = _cairo_int128_divrem (m_value, o.m_value);
m_value = qr.quo;
m_value = _cairo_int128_lsl (m_value, 64);
cairo_int128_t rem = _cairo_int128_rsa (qr.rem, 64);
m_value = _cairo_int128_add (m_value, rem);
#endif
qr = _cairo_int128_divrem (m_slowValue, div);
m_slowValue = qr.quo;
return false;
}
int
HighPrecision::Compare (HighPrecision const &o) const
HighPrecision::SlowCompare (HighPrecision const &o) const
{
if (_cairo_int128_lt (m_value, o.m_value))
const_cast<HighPrecision *> (this)->EnsureSlow ();
const_cast<HighPrecision &> (o).EnsureSlow ();
if (_cairo_int128_lt (m_slowValue, o.m_slowValue))
{
return -1;
}
else if (_cairo_int128_eq (m_value, o.m_value))
else if (_cairo_int128_eq (m_slowValue, o.m_slowValue))
{
return 0;
}
@@ -124,12 +179,6 @@ HighPrecision::Compare (HighPrecision const &o) const
return 1;
}
}
HighPrecision
HighPrecision::Zero (void)
{
return HighPrecision (0,0);
}
}; // namespace ns3
@@ -283,7 +332,7 @@ HighPrecision128Tests::RunTests (void)
return ok;
}
static HighPrecision128Tests g_int128_tests;
static HighPrecision128Tests g_int128Tests;
}; // namespace ns3

View File

@@ -24,34 +24,179 @@
#include <stdint.h>
#include "cairo-wideint-private.h"
#define HP128INC(x)
//#define HP128INC(x) x++
namespace ns3 {
/**
* This should be a high-precision 128bit integer version of
* HighPrecision class. It should also be able to report
* overflow and underflow.
*/
class HighPrecision
{
public:
HighPrecision ();
HighPrecision (int64_t value, bool dummy);
inline HighPrecision ();
inline HighPrecision (int64_t value, bool dummy);
HighPrecision (double value);
static void PrintStats (void);
int64_t GetInteger (void) const;
double GetDouble (void) const;
bool Add (HighPrecision const &o);
bool Sub (HighPrecision const &o);
bool Mul (HighPrecision const &o);
inline int64_t GetInteger (void) const;
inline double GetDouble (void) const;
inline bool Add (HighPrecision const &o);
inline bool Sub (HighPrecision const &o);
inline bool Mul (HighPrecision const &o);
bool Div (HighPrecision const &o);
int Compare (HighPrecision const &o) const;
static HighPrecision Zero (void);
inline int Compare (HighPrecision const &o) const;
inline static HighPrecision Zero (void);
private:
int64_t SlowGetInteger (void) const;
double SlowGetDouble (void) const;
bool SlowAdd (HighPrecision const &o);
bool SlowSub (HighPrecision const &o);
bool SlowMul (HighPrecision const &o);
int SlowCompare (HighPrecision const &o) const;
inline void EnsureSlow (void);
static const double MAX_64;
cairo_int128_t m_value;
bool m_isFast;
int64_t m_fastValue;
cairo_int128_t m_slowValue;
static int m_nfastadds;
static int m_nfastsubs;
static int m_nfastmuls;
static int m_nfastcmps;
static int m_nfastgets;
static int m_nslowadds;
static int m_nslowsubs;
static int m_nslowmuls;
static int m_nslowcmps;
static int m_nslowgets;
static int m_ndivs;
static int m_nconversions;
};
}; // namespace ns3
namespace ns3 {
HighPrecision::HighPrecision ()
: m_isFast (true),
m_fastValue (0)
{}
HighPrecision::HighPrecision (int64_t value, bool dummy)
: m_isFast (true),
m_fastValue (value)
{}
int64_t
HighPrecision::GetInteger (void) const
{
if (m_isFast)
{
HP128INC (m_nfastgets);
return m_fastValue;
}
else
{
HP128INC (m_nslowgets);
return SlowGetInteger ();
}
}
double HighPrecision::GetDouble (void) const
{
if (m_isFast)
{
HP128INC (m_nfastgets);
double retval = m_fastValue;
return retval;
}
else
{
HP128INC (m_nslowgets);
return SlowGetDouble ();
}
}
bool
HighPrecision::Add (HighPrecision const &o)
{
if (m_isFast && o.m_isFast)
{
HP128INC (m_nfastadds);
m_fastValue += o.m_fastValue;
return false;
}
else
{
HP128INC (m_nslowadds);
return SlowAdd (o);
}
}
bool
HighPrecision::Sub (HighPrecision const &o)
{
if (m_isFast && o.m_isFast)
{
HP128INC (m_nfastsubs);
m_fastValue -= o.m_fastValue;
return false;
}
else
{
HP128INC (m_nslowsubs);
return SlowSub (o);
}
}
bool
HighPrecision::Mul (HighPrecision const &o)
{
if (m_isFast && o.m_isFast)
{
HP128INC (m_nfastmuls);
m_fastValue *= o.m_fastValue;
return false;
}
else
{
HP128INC (m_nslowmuls);
return SlowMul (o);
}
}
int
HighPrecision::Compare (HighPrecision const &o) const
{
if (m_isFast && o.m_isFast)
{
HP128INC (m_nfastcmps);
if (m_fastValue < o.m_fastValue)
{
return -1;
}
else if (m_fastValue == o.m_fastValue)
{
return 0;
}
else
{
return +1;
}
}
else
{
HP128INC (m_nslowcmps);
return SlowCompare (o);
}
}
HighPrecision
HighPrecision::Zero (void)
{
return HighPrecision ();
}
}; // namespace ns3
#endif /* HIGH_PRECISION_128_H */