--- /dev/null
+/*
+ * timestructs.h -- test bed adaptors for time structs.
+ *
+ * Written by Juergen Perlinger (perlinger@ntp.org) for the NTP project.
+ * The contents of 'html/copyright.html' apply.
+ *
+ * Some wrapper classes and a closeness predicate that are used to
+ * bridge the gap between the goggletest framework and the structs used
+ * for representing time stamps (l_fp, struct timeval, struct timespec).
+ *
+ * Some ostream conversion operators are provided to give diagnostic
+ * output on errors. The normal string conversion functions will give
+ * HRVs (human readable values) but we might also be interested in the
+ * machine representation for diagnostic purposes.
+ */
+
+
+//#ifndef TESTCALSHIMS_H
+#include "testcalshims.h"
+//#endif
+
+
+#ifndef TIMESTRUCTS_H
+#define TIMESTRUCTS_H
+
+#include "ntp_fp.h"
+
+
+l_fp test ;
+//namespace timeStruct {
+
+// wrap a l_fp struct with common operations
+struct l_fp_wrap {
+
+ l_fp V;
+
+
+ //bool operator == (const l_fp_wrap& rhs) const
+ // { return L_ISEQU(&V, &rhs.V); }
+
+//---------------THIS HAS TO BE MANUALLY CONVERTED IN CODE!!!
+ //operator l_fp* ()
+ // { return &V; }
+ //operator l_fp& ()
+ // { return V; }
+//-----------------------------------------
+/*
+ l_fp_wrap & operator = (const l_fp_wrap& rhs)
+ { V = rhs.V; return *this; }
+ l_fp_wrap& operator = (const l_fp& rhs)
+ { V = rhs; return *this; }
+*/
+};
+
+l_fp_wrap(l_fp V){
+ ZERO(V); }
+l_fp_wrap(l_fp V, u_int32 hi, u_int32 lo){
+ V.l_ui = hi; V.l_uf = lo; }
+l_fp_wrap(l_fp V, const l_fp &rhs){
+ V = rhs; }
+
+l_fp_wrap_equals(const l_fp_wrap& current, const l_fp_wrap& rhs) const // operator ==
+ { return L_ISEQU(¤t.V, &rhs.V); }
+
+l_fp_wrap_and(const l_fp_wrap& current, const l_fp_wrap& rhs){
+ V = rhs.V;
+ return current//*this;
+}
+l_fp_wrap_and(const l_fp& current, const l_fp& rhs){
+ V = rhs;
+ return current//*this;
+}
+
+
+
+// wrap a 'struct timeval' with common operations
+struct timeval_wrap {
+
+ struct timeval V;
+
+ timeval_wrap()
+ { ZERO(V); }
+ timeval_wrap(time_t hi, long lo)
+ { V.tv_sec = hi; V.tv_usec = lo; }
+ timeval_wrap(const struct timeval & rhs)
+ { V = rhs; }
+ timeval_wrap(const timeval_wrap & rhs)
+ { V = rhs.V; }
+ bool operator == (const timeval_wrap& rhs) const
+ { return V.tv_sec == rhs.V.tv_sec &&
+ V.tv_usec == rhs.V.tv_usec ; }
+ bool valid() const
+ { return V.tv_usec >= 0 && V.tv_usec < 1000000; }
+ operator struct timeval* ()
+ { return &V; }
+ operator struct timeval& ()
+ { return V; }
+ timeval_wrap& operator = (const timeval_wrap& rhs)
+ { V = rhs.V; return *this; }
+ timeval_wrap& operator = (const struct timeval& rhs)
+ { V = rhs; return *this; }
+};
+
+// wrap a 'struct timespec' with common operations
+struct timespec_wrap {
+
+ struct timespec V;
+
+ timespec_wrap()
+ { ZERO(V); }
+ timespec_wrap(time_t hi, long lo)
+ { V.tv_sec = hi; V.tv_nsec = lo; }
+ timespec_wrap(const struct timespec & rhs)
+ { V = rhs; }
+ timespec_wrap(const timespec_wrap & rhs)
+ { V = rhs.V; }
+ bool operator == (const timespec_wrap& rhs) const
+ { return V.tv_sec == rhs.V.tv_sec &&
+ V.tv_nsec == rhs.V.tv_nsec ; }
+ bool valid() const
+ { return V.tv_nsec >= 0 && V.tv_nsec < 1000000000; }
+ operator struct timespec* ()
+ { return &V; }
+ operator struct timespec& ()
+ { return V; }
+ timespec_wrap& operator = (const timespec_wrap& rhs)
+ { V = rhs.V; return *this; }
+ timespec_wrap& operator = (const struct timespec& rhs)
+ { V = rhs; return *this; }
+};
+
+// l_fp closeness testing predicate
+//
+// This predicate is used for the closeness ('near') testing of l_fp
+// values. Once constructed with a limit, it can be used to check the
+// absolute difference of two l_fp structs against that limit; if the
+// difference is less or equal to this limit, the test passes.
+class AssertFpClose {
+private:
+ l_fp limit;
+
+public:
+ AssertFpClose(u_int32 hi, u_int32 lo);
+
+ ::testing::AssertionResult
+ operator()(const char* m_expr, const char* n_expr,
+ const l_fp & m, const l_fp & n);
+};
+
+
+// timeval closeness testing predicate
+//
+// CAVEAT: This class uses the timevalops functions
+// - sub_tval
+// - abs_tval
+// - cmp_tval
+//
+// This creates a dependency loop of sorts. The loop is defused by the
+// fact that these basic operations can be tested by exact value tests,
+// so once the basic timeval operations passed it's safe to use this
+// predicate.
+class AssertTimevalClose {
+private:
+ struct timeval limit;
+
+public:
+ // note: (hi,lo) should be a positive normalised timeval;
+ // the constructor does not normalise the values!
+ AssertTimevalClose(time_t hi, int32 lo);
+
+ ::testing::AssertionResult
+ operator()(const char* m_expr, const char* n_expr,
+ const struct timeval & m, const struct timeval & n);
+};
+
+
+// timespec closeness testing predicate
+//
+// CAVEAT: This class uses the timespecops functions
+// - sub_tspec
+// - abs_tspec
+// - cmp_tspec
+//
+// See the equivalent timeval helper.
+class AssertTimespecClose {
+private:
+ struct timespec limit;
+
+public:
+ // note: (hi,lo) should be a positive normalised timespec;
+ // the constructor does not normalise the values!
+ AssertTimespecClose(time_t hi, int32 lo);
+
+ ::testing::AssertionResult
+ operator()(const char* m_expr, const char* n_expr,
+ const struct timespec & m, const struct timespec & n);
+};
+
+
+// since googletest wants to string format items, we declare the
+// necessary operators. Since all adaptors have only public members
+// there is need for friend declarations anywhere.
+
+extern std::ostream& operator << (std::ostream& os,
+ const timeStruct::l_fp_wrap& val);
+extern std::ostream& operator << (std::ostream& os,
+ const timeStruct::timeval_wrap& val);
+extern std::ostream& operator << (std::ostream& os,
+ const timeStruct::timespec_wrap& val);
+
+//} // namespace timeStruct
+
+#endif // TIMESTRUCTS_H
--- /dev/null
+//#include "c_timestructs.h"
+
+#include "testcalshims.h"
+#include "unity.h"
+
+//#include "libntptest.h"
+//#include "timestructs.h"
+
+
+
+#include "ntp_fp.h"
+
+
+#include <float.h>
+#include <math.h>
+
+#include <string.h> //
+//#include <sstream>
+
+
+typedef struct {
+ uint32_t h, l;
+} lfp_hl;
+
+
+/*
+//----------------------------------------------------------------------
+// OO-wrapper for 'l_fp'
+//----------------------------------------------------------------------
+
+class LFP
+{
+public:
+ ~LFP();
+ LFP();
+ LFP(const LFP& rhs);
+ LFP(int32 i, u_int32 f);
+
+ LFP operator+ (const LFP &rhs) const;
+ LFP& operator+=(const LFP &rhs);
+
+ LFP operator- (const LFP &rhs) const;
+ LFP& operator-=(const LFP &rhs);
+
+ LFP& operator=(const LFP &rhs);
+ LFP operator-() const;
+
+ bool operator==(const LFP &rhs) const;
+
+ LFP neg() const;
+ LFP abs() const;
+ int signum() const;
+
+ bool l_isgt (const LFP &rhs) const
+ { return L_ISGT(&_v, &rhs._v); }
+ bool l_isgtu(const LFP &rhs) const
+ { return L_ISGTU(&_v, &rhs._v); }
+ bool l_ishis(const LFP &rhs) const
+ { return L_ISHIS(&_v, &rhs._v); }
+ bool l_isgeq(const LFP &rhs) const
+ { return L_ISGEQ(&_v, &rhs._v); }
+ bool l_isequ(const LFP &rhs) const
+ { return L_ISEQU(&_v, &rhs._v); }
+
+ int ucmp(const LFP & rhs) const;
+ int scmp(const LFP & rhs) const;
+
+ std::string toString() const;
+ std::ostream& toStream(std::ostream &oo) const;
+
+ operator double() const;
+ explicit LFP(double);
+
+protected:
+ LFP(const l_fp &rhs);
+
+ static int cmp_work(u_int32 a[3], u_int32 b[3]);
+
+ l_fp _v;
+};
+
+static std::ostream& operator<<(std::ostream &oo, const LFP& rhs)
+{
+ return rhs.toStream(oo);
+}
+
+//----------------------------------------------------------------------
+// reference comparision
+// This is implementad as a full signed MP-subtract in 3 limbs, where
+// the operands are zero or sign extended before the subtraction is
+// executed.
+//----------------------------------------------------------------------
+int LFP::scmp(const LFP & rhs) const
+{
+ u_int32 a[3], b[3];
+ const l_fp &op1(_v), &op2(rhs._v);
+
+ a[0] = op1.l_uf; a[1] = op1.l_ui; a[2] = 0;
+ b[0] = op2.l_uf; b[1] = op2.l_ui; b[2] = 0;
+
+ a[2] -= (op1.l_i < 0);
+ b[2] -= (op2.l_i < 0);
+
+ return cmp_work(a,b);
+}
+
+int LFP::ucmp(const LFP & rhs) const
+{
+ u_int32 a[3], b[3];
+ const l_fp &op1(_v), &op2(rhs._v);
+
+ a[0] = op1.l_uf; a[1] = op1.l_ui; a[2] = 0;
+ b[0] = op2.l_uf; b[1] = op2.l_ui; b[2] = 0;
+
+ return cmp_work(a,b);
+}
+
+int LFP::cmp_work(u_int32 a[3], u_int32 b[3])
+{
+ u_int32 cy, idx, tmp;
+ for (cy = idx = 0; idx < 3; ++idx) {
+ tmp = a[idx]; cy = (a[idx] -= cy ) > tmp;
+ tmp = a[idx]; cy |= (a[idx] -= b[idx]) > tmp;
+ }
+ if (a[2])
+ return -1;
+ return a[0] || a[1];
+}
+
+//----------------------------------------------------------------------
+// imlementation of the LFP stuff
+// This should be easy enough...
+//----------------------------------------------------------------------
+
+LFP::~LFP()
+{
+ // NOP
+}
+
+LFP::LFP()
+{
+ _v.l_ui = 0;
+ _v.l_uf = 0;
+}
+
+LFP::LFP(int32 i, u_int32 f)
+{
+ _v.l_i = i;
+ _v.l_uf = f;
+}
+
+LFP::LFP(const LFP &rhs)
+{
+ _v = rhs._v;
+}
+
+LFP::LFP(const l_fp & rhs)
+{
+ _v = rhs;
+}
+
+LFP& LFP::operator=(const LFP & rhs)
+{
+ _v = rhs._v;
+ return *this;
+}
+
+LFP& LFP::operator+=(const LFP & rhs)
+{
+ L_ADD(&_v, &rhs._v);
+ return *this;
+}
+
+LFP& LFP::operator-=(const LFP & rhs)
+{
+ L_SUB(&_v, &rhs._v);
+ return *this;
+}
+
+LFP LFP::operator+(const LFP &rhs) const
+{
+ LFP tmp(*this);
+ return tmp += rhs;
+}
+
+LFP LFP::operator-(const LFP &rhs) const
+{
+ LFP tmp(*this);
+ return tmp -= rhs;
+}
+
+LFP LFP::operator-() const
+{
+ LFP tmp(*this);
+ L_NEG(&tmp._v);
+ return tmp;
+}
+
+LFP
+LFP::neg() const
+{
+ LFP tmp(*this);
+ L_NEG(&tmp._v);
+ return tmp;
+}
+
+LFP
+LFP::abs() const
+{
+ LFP tmp(*this);
+ if (L_ISNEG(&tmp._v))
+ L_NEG(&tmp._v);
+ return tmp;
+}
+
+int
+LFP::signum() const
+{
+ if (_v.l_ui & 0x80000000u)
+ return -1;
+ return (_v.l_ui || _v.l_uf);
+}
+
+std::string
+LFP::toString() const
+{
+ std::ostringstream oss;
+ toStream(oss);
+ return oss.str();
+}
+
+std::ostream&
+LFP::toStream(std::ostream &os) const
+{
+ return os
+ << mfptoa(_v.l_ui, _v.l_uf, 9)
+ << " [$" << std::setw(8) << std::setfill('0') << std::hex << _v.l_ui
+ << ':' << std::setw(8) << std::setfill('0') << std::hex << _v.l_uf
+ << ']';
+}
+
+bool LFP::operator==(const LFP &rhs) const
+{
+ return L_ISEQU(&_v, &rhs._v);
+}
+
+
+LFP::operator double() const
+{
+ double res;
+ LFPTOD(&_v, res);
+ return res;
+}
+
+LFP::LFP(double rhs)
+{
+ DTOLFP(rhs, &_v);
+}
+
+
+//----------------------------------------------------------------------
+// testing the relational macros works better with proper predicate
+// formatting functions; it slows down the tests a bit, but makes for
+// readable failure messages.
+//----------------------------------------------------------------------
+
+testing::AssertionResult isgt_p(
+ const LFP &op1, const LFP &op2)
+{
+ if (op1.l_isgt(op2))
+ return testing::AssertionSuccess()
+ << "L_ISGT(" << op1 << "," << op2 << ") is true";
+ else
+ return testing::AssertionFailure()
+ << "L_ISGT(" << op1 << "," << op2 << ") is false";
+}
+
+testing::AssertionResult isgeq_p(
+ const LFP &op1, const LFP &op2)
+{
+ if (op1.l_isgeq(op2))
+ return testing::AssertionSuccess()
+ << "L_ISGEQ(" << op1 << "," << op2 << ") is true";
+ else
+ return testing::AssertionFailure()
+ << "L_ISGEQ(" << op1 << "," << op2 << ") is false";
+}
+
+testing::AssertionResult isgtu_p(
+ const LFP &op1, const LFP &op2)
+{
+ if (op1.l_isgtu(op2))
+ return testing::AssertionSuccess()
+ << "L_ISGTU(" << op1 << "," << op2 << ") is true";
+ else
+ return testing::AssertionFailure()
+ << "L_ISGTU(" << op1 << "," << op2 << ") is false";
+}
+
+testing::AssertionResult ishis_p(
+ const LFP &op1, const LFP &op2)
+{
+ if (op1.l_ishis(op2))
+ return testing::AssertionSuccess()
+ << "L_ISHIS(" << op1 << "," << op2 << ") is true";
+ else
+ return testing::AssertionFailure()
+ << "L_ISHIS(" << op1 << "," << op2 << ") is false";
+}
+
+testing::AssertionResult isequ_p(
+ const LFP &op1, const LFP &op2)
+{
+ if (op1.l_isequ(op2))
+ return testing::AssertionSuccess()
+ << "L_ISEQU(" << op1 << "," << op2 << ") is true";
+ else
+ return testing::AssertionFailure()
+ << "L_ISEQU(" << op1 << "," << op2 << ") is false";
+}
+
+*/
+
+//----------------------------------------------------------------------
+// test data table for add/sub and compare
+//----------------------------------------------------------------------
+
+
+static const lfp_hl addsub_tab[][3] = {
+ // trivial idendity:
+ {{0 ,0 }, { 0,0 }, { 0,0}},
+ // with carry from fraction and sign change:
+ {{-1,0x80000000}, { 0,0x80000000}, { 0,0}},
+ // without carry from fraction
+ {{ 1,0x40000000}, { 1,0x40000000}, { 2,0x80000000}},
+ // with carry from fraction:
+ {{ 1,0xC0000000}, { 1,0xC0000000}, { 3,0x80000000}},
+ // with carry from fraction and sign change:
+ {{0x7FFFFFFF, 0x7FFFFFFF}, {0x7FFFFFFF,0x7FFFFFFF}, {0xFFFFFFFE,0xFFFFFFFE}},
+ // two tests w/o carry (used for l_fp<-->double):
+ {{0x55555555,0xAAAAAAAA}, {0x11111111,0x11111111}, {0x66666666,0xBBBBBBBB}},
+ {{0x55555555,0x55555555}, {0x11111111,0x11111111}, {0x66666666,0x66666666}},
+ // wide-range test, triggers compare trouble
+ {{0x80000000,0x00000001}, {0xFFFFFFFF,0xFFFFFFFE}, {0x7FFFFFFF,0xFFFFFFFF}}
+};
+static const size_t addsub_cnt = (sizeof(addsub_tab)/sizeof(addsub_tab[0]));
+static const size_t addsub_tot = (sizeof(addsub_tab)/sizeof(addsub_tab[0][0]));
+
+
+
+//----------------------------------------------------------------------
+// epsilon estimation for the precision of a conversion double --> l_fp
+//
+// The error estimation limit is as follows:
+// * The 'l_fp' fixed point fraction has 32 bits precision, so we allow
+// for the LSB to toggle by clamping the epsilon to be at least 2^(-31)
+//
+// * The double mantissa has a precsion 54 bits, so the other minimum is
+// dval * (2^(-53))
+//
+// The maximum of those two boundaries is used for the check.
+//
+// Note: once there are more than 54 bits between the highest and lowest
+// '1'-bit of the l_fp value, the roundtrip *will* create truncation
+// errors. This is an inherent property caused by the 54-bit mantissa of
+// the 'double' type.
+double eps(double d)
+{
+ return fmax(ldexp(1.0, -31), ldexp(fabs(d), -53)); //max<double>
+}
+
+//Y U NO OVERLOAD, C XD
+/*
+l_fp l_fp_init()
+{
+ l_fp temp;
+ temp.l_ui = 0;
+ temp.l_uf = 0;
+ return temp;
+}
+*/
+
+l_fp l_fp_init(int32 i, u_int32 f)
+{
+ l_fp temp;
+ temp.l_i = i;
+ temp.l_uf = f;
+
+ return temp;
+}
+
+
+
+l_fp l_fp_add(const l_fp first, const l_fp second) //&rhs!!!
+{
+ l_fp temp;
+ //LFP tmp(*this);
+ //return tmp += rhs;
+ temp = first;
+ L_ADD(&temp, &second);
+ //return first + second;
+ return temp;
+}
+
+l_fp l_fp_subtract(const l_fp first, const l_fp second) //&rhs!!!
+{
+ l_fp temp;
+ //LFP tmp(*this);
+ //return tmp += rhs;
+ temp = first;
+ L_SUB(&temp, &second);
+
+ return temp;
+}
+
+l_fp l_fp_negate(const l_fp first)
+{
+ l_fp temp;
+ //LFP tmp(*this);
+ //return tmp += rhs;
+ temp = first;
+ L_NEG(&temp);
+
+ return temp;
+}
+/*
+//negation!
+LFP LFP::operator-() const
+{
+ LFP tmp(*this);
+ L_NEG(&tmp._v);
+ return tmp;
+}
+*/
+//----------------------------------------------------------------------
+// test addition
+//----------------------------------------------------------------------
+void test_AdditionLR() {
+
+ size_t idx=0;
+ for (idx=0; idx < addsub_cnt; ++idx) {
+
+
+ l_fp op1 = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
+ //LFP op1(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
+ l_fp op2 = l_fp_init(addsub_tab[idx][1].h, addsub_tab[idx][1].l);
+ //LFP exp(addsub_tab[idx][2].h, addsub_tab[idx][2].l);
+ l_fp exp = l_fp_init(addsub_tab[idx][2].h, addsub_tab[idx][2].l);
+ //LFP res(op1 + op2);
+ l_fp res = l_fp_add(op1,op2);
+
+ TEST_ASSERT_EQUAL_MEMORY(&exp, &res,sizeof(exp));
+ }
+}
+
+void test_AdditionRL() {
+
+ size_t idx=0;
+ for (idx=0; idx < addsub_cnt; ++idx) {
+ l_fp op2 = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
+ l_fp op1 = l_fp_init(addsub_tab[idx][1].h, addsub_tab[idx][1].l);
+ l_fp exp = l_fp_init(addsub_tab[idx][2].h, addsub_tab[idx][2].l);
+ l_fp res = l_fp_add(op1,op2);
+
+ TEST_ASSERT_EQUAL_MEMORY(&exp, &res,sizeof(exp));
+ }
+}
+
+
+
+//----------------------------------------------------------------------
+// test subtraction
+//----------------------------------------------------------------------
+void test_SubtractionLR() {
+
+ size_t idx=0;
+ for (idx=0; idx < addsub_cnt; ++idx) {
+ l_fp op2 = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
+ l_fp exp = l_fp_init(addsub_tab[idx][1].h, addsub_tab[idx][1].l);
+ l_fp op1 = l_fp_init(addsub_tab[idx][2].h, addsub_tab[idx][2].l);
+ l_fp res = l_fp_subtract(op1,op2);
+ //LFP res(op1 - op2);
+
+ TEST_ASSERT_EQUAL_MEMORY(&exp, &res,sizeof(exp));
+ }
+}
+
+void test_SubtractionRL() {
+
+ size_t idx=0;
+ for (idx=0; idx < addsub_cnt; ++idx) {
+ l_fp exp = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
+ l_fp op2 = l_fp_init(addsub_tab[idx][1].h, addsub_tab[idx][1].l);
+ l_fp op1 = l_fp_init(addsub_tab[idx][2].h, addsub_tab[idx][2].l);
+ l_fp res = l_fp_subtract(op1,op2);
+
+ TEST_ASSERT_EQUAL_MEMORY(&exp, &res,sizeof(exp));
+ }
+}
+
+//----------------------------------------------------------------------
+// test negation
+//----------------------------------------------------------------------
+
+void test_Negation() {
+
+ size_t idx=0;
+ for (idx=0; idx < addsub_cnt; ++idx) {
+ l_fp op1 = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
+ l_fp op2 = l_fp_negate(op1);
+ l_fp sum = l_fp_add(op1, op2);
+
+ l_fp zero = l_fp_init(0,0);
+ TEST_ASSERT_EQUAL_MEMORY(&zero, &sum,sizeof(sum));
+
+ }
+}
+
+/*
+
+//----------------------------------------------------------------------
+// test absolute value
+//----------------------------------------------------------------------
+void test_Absolute() {
+ for (size_t idx=0; idx < addsub_cnt; ++idx) {
+ LFP op1(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
+ LFP op2(op1.abs());
+
+ TEST_ASSERT_TRUE(op2.signum() >= 0);
+
+ if (op1.signum() >= 0)
+ op1 -= op2;
+ else
+ op1 += op2;
+ TEST_ASSERT_EQUAL(LFP(0,0), op1);
+ }
+
+ // There is one special case we have to check: the minimum
+ // value cannot be negated, or, to be more precise, the
+ // negation reproduces the original pattern.
+ LFP minVal(0x80000000, 0x00000000);
+ LFP minAbs(minVal.abs());
+ TEST_ASSERT_EQUAL(-1, minVal.signum());
+ TEST_ASSERT_EQUAL(minVal, minAbs);
+}
+
+//----------------------------------------------------------------------
+// fp -> double -> fp rountrip test
+//----------------------------------------------------------------------
+void test_FDF_RoundTrip() {
+ // since a l_fp has 64 bits in it's mantissa and a double has
+ // only 54 bits available (including the hidden '1') we have to
+ // make a few concessions on the roundtrip precision. The 'eps()'
+ // function makes an educated guess about the avilable precision
+ // and checks the difference in the two 'l_fp' values against
+ // that limit.
+ for (size_t idx=0; idx < addsub_cnt; ++idx) {
+ LFP op1(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
+ double op2(op1);
+ LFP op3(op2);
+ // for manual checks only:
+ // std::cout << std::setprecision(16) << op2 << std::endl;
+ ASSERT_LE(fabs(op1-op3), eps(op2));
+ }
+}
+
+//----------------------------------------------------------------------
+// test the compare stuff
+//
+// This uses the local compare and checks if the operations using the
+// macros in 'ntp_fp.h' produce mathing results.
+// ----------------------------------------------------------------------
+void test_SignedRelOps() {
+ const lfp_hl * tv(&addsub_tab[0][0]);
+ for (size_t lc=addsub_tot-1; lc; --lc,++tv) {
+ LFP op1(tv[0].h,tv[0].l);
+ LFP op2(tv[1].h,tv[1].l);
+ int cmp(op1.scmp(op2));
+
+ switch (cmp) {
+ case -1:
+ std::swap(op1, op2);
+ case 1:
+ TEST_ASSERT_TRUE (isgt_p(op1,op2));
+ TEST_ASSERT_FALSE(isgt_p(op2,op1));
+
+ TEST_ASSERT_TRUE (isgeq_p(op1,op2));
+ TEST_ASSERT_FALSE(isgeq_p(op2,op1));
+
+ TEST_ASSERT_FALSE(isequ_p(op1,op2));
+ TEST_ASSERT_FALSE(isequ_p(op2,op1));
+ break;
+ case 0:
+ TEST_ASSERT_FALSE(isgt_p(op1,op2));
+ TEST_ASSERT_FALSE(isgt_p(op2,op1));
+
+ TEST_ASSERT_TRUE (isgeq_p(op1,op2));
+ TEST_ASSERT_TRUE (isgeq_p(op2,op1));
+
+ TEST_ASSERT_TRUE (isequ_p(op1,op2));
+ TEST_ASSERT_TRUE (isequ_p(op2,op1));
+ break;
+ default:
+ FAIL() << "unexpected SCMP result: " << cmp;
+ }
+ }
+}
+
+void test_UnsignedRelOps() {
+ const lfp_hl * tv(&addsub_tab[0][0]);
+ for (size_t lc=addsub_tot-1; lc; --lc,++tv) {
+ LFP op1(tv[0].h,tv[0].l);
+ LFP op2(tv[1].h,tv[1].l);
+ int cmp(op1.ucmp(op2));
+
+ switch (cmp) {
+ case -1:
+ std::swap(op1, op2);
+ case 1:
+ TEST_ASSERT_TRUE (isgtu_p(op1,op2));
+ TEST_ASSERT_FALSE(isgtu_p(op2,op1));
+
+ TEST_ASSERT_TRUE (ishis_p(op1,op2));
+ TEST_ASSERT_FALSE(ishis_p(op2,op1));
+ break;
+ case 0:
+ TEST_ASSERT_FALSE(isgtu_p(op1,op2));
+ TEST_ASSERT_FALSE(isgtu_p(op2,op1));
+
+ TEST_ASSERT_TRUE (ishis_p(op1,op2));
+ TEST_ASSERT_TRUE (ishis_p(op2,op1));
+ break;
+ default:
+ FAIL() << "unexpected UCMP result: " << cmp;
+ }
+ }
+}
+
+*/
+
+//----------------------------------------------------------------------
+// that's all folks... but feel free to add things!
+//----------------------------------------------------------------------