562 lines
14 KiB
C
562 lines
14 KiB
C
|
#include "config.h"
|
||
|
|
||
|
#include "ntp_stdlib.h"
|
||
|
#include "ntp_calendar.h"
|
||
|
#include "ntp_fp.h"
|
||
|
|
||
|
#include "unity.h"
|
||
|
|
||
|
#include <float.h>
|
||
|
#include <math.h>
|
||
|
|
||
|
|
||
|
//replaced TEST_ASSERT_EQUAL_MEMORY(&a,&b,sizeof(a)) with TEST_ASSERT_EQUAL_l_fp(a,b). It's safer this way, because structs can be compared even if they aren't initiated with memset (due to padding bytes)
|
||
|
#define TEST_ASSERT_EQUAL_l_fp(a, b) { \
|
||
|
TEST_ASSERT_EQUAL_MESSAGE(a.l_i, b.l_i, "Field l_i"); \
|
||
|
TEST_ASSERT_EQUAL_UINT_MESSAGE(a.l_uf, b.l_uf, "Field l_uf"); \
|
||
|
}
|
||
|
|
||
|
typedef struct {
|
||
|
uint32_t h, l;
|
||
|
} lfp_hl;
|
||
|
|
||
|
|
||
|
static int cmp_work(u_int32 a[3], u_int32 b[3]);
|
||
|
|
||
|
/*
|
||
|
//----------------------------------------------------------------------
|
||
|
// OO-wrapper for 'l_fp'
|
||
|
//----------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
~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;
|
||
|
|
||
|
|
||
|
|
||
|
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);
|
||
|
|
||
|
|
||
|
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 l_fp_scmp(const l_fp first, const l_fp second)
|
||
|
{
|
||
|
u_int32 a[3], b[3];
|
||
|
|
||
|
const l_fp op1 = first;
|
||
|
const l_fp op2 = second;
|
||
|
//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 l_fp_ucmp(const l_fp first, l_fp second )
|
||
|
{
|
||
|
u_int32 a[3], b[3];
|
||
|
const l_fp op1 = first;
|
||
|
const l_fp op2 = second;
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
|
||
|
//maybe rename it to lf_cmp_work ???
|
||
|
int 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...
|
||
|
//----------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
|
||
|
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)
|
||
|
{
|
||
|
l_fp temp;
|
||
|
temp = first;
|
||
|
L_ADD(&temp, &second);
|
||
|
return temp;
|
||
|
}
|
||
|
|
||
|
l_fp l_fp_subtract(const l_fp first, const l_fp second)
|
||
|
{
|
||
|
l_fp temp;
|
||
|
temp = first;
|
||
|
L_SUB(&temp, &second);
|
||
|
|
||
|
return temp;
|
||
|
}
|
||
|
|
||
|
l_fp l_fp_negate(const l_fp first)
|
||
|
{
|
||
|
l_fp temp;
|
||
|
temp = first; //is this line really necessary?
|
||
|
L_NEG(&temp);
|
||
|
|
||
|
return temp;
|
||
|
}
|
||
|
|
||
|
l_fp l_fp_abs(const l_fp first)
|
||
|
{
|
||
|
l_fp temp = first;
|
||
|
if (L_ISNEG(&temp))
|
||
|
L_NEG(&temp);
|
||
|
return temp;
|
||
|
}
|
||
|
|
||
|
int l_fp_signum(const l_fp first)
|
||
|
{
|
||
|
if (first.l_ui & 0x80000000u)
|
||
|
return -1;
|
||
|
return (first.l_ui || first.l_uf);
|
||
|
}
|
||
|
|
||
|
double l_fp_convert_to_double(const l_fp first)
|
||
|
{
|
||
|
double res;
|
||
|
LFPTOD(&first, res);
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
l_fp l_fp_init_from_double( double rhs)
|
||
|
{
|
||
|
l_fp temp;
|
||
|
DTOLFP(rhs, &temp);
|
||
|
return temp;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
void l_fp_swap(l_fp * first, l_fp *second){
|
||
|
l_fp temp = *second;
|
||
|
|
||
|
*second = *first;
|
||
|
*first = temp;
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
LFP::LFP()
|
||
|
{
|
||
|
_v.l_ui = 0;
|
||
|
_v.l_uf = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
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);
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
*/
|
||
|
|
||
|
//----------------------------------------------------------------------
|
||
|
// testing the relational macros works better with proper predicate
|
||
|
// formatting functions; it slows down the tests a bit, but makes for
|
||
|
// readable failure messages.
|
||
|
//----------------------------------------------------------------------
|
||
|
|
||
|
|
||
|
typedef int bool; //typedef enum { FALSE, TRUE } boolean; -> can't use this because TRUE and FALSE are already defined
|
||
|
|
||
|
|
||
|
bool l_isgt (const l_fp first, const l_fp second)
|
||
|
{ return L_ISGT(&first, &second); }
|
||
|
bool l_isgtu(const l_fp first, const l_fp second)
|
||
|
{ return L_ISGTU(&first, &second); }
|
||
|
bool l_ishis(const l_fp first, const l_fp second)
|
||
|
{ return L_ISHIS(&first, &second); }
|
||
|
bool l_isgeq(const l_fp first, const l_fp second)
|
||
|
{ return L_ISGEQ(&first, &second); }
|
||
|
bool l_isequ(const l_fp first, const l_fp second)
|
||
|
{ return L_ISEQU(&first, &second); }
|
||
|
|
||
|
|
||
|
//----------------------------------------------------------------------
|
||
|
// 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>
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//----------------------------------------------------------------------
|
||
|
// 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_l_fp(exp,res);
|
||
|
//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_l_fp(exp,res);
|
||
|
//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_l_fp(exp,res);
|
||
|
//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_l_fp(exp,res);
|
||
|
//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_l_fp(zero,sum);
|
||
|
//TEST_ASSERT_EQUAL_MEMORY(&zero, &sum,sizeof(sum));
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
//----------------------------------------------------------------------
|
||
|
// test absolute value
|
||
|
//----------------------------------------------------------------------
|
||
|
void test_Absolute() {
|
||
|
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_abs(op1);
|
||
|
|
||
|
TEST_ASSERT_TRUE(l_fp_signum(op2) >= 0);
|
||
|
|
||
|
if (l_fp_signum(op1) >= 0)
|
||
|
op1 = l_fp_subtract(op1,op2); //op1 -= op2;
|
||
|
|
||
|
else
|
||
|
op1 = l_fp_add(op1,op2);
|
||
|
|
||
|
l_fp zero = l_fp_init(0,0);
|
||
|
|
||
|
TEST_ASSERT_EQUAL_l_fp(zero,op1);
|
||
|
//TEST_ASSERT_EQUAL_MEMORY(&zero, &op1,sizeof(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.
|
||
|
l_fp minVal = l_fp_init(0x80000000, 0x00000000);
|
||
|
l_fp minAbs = l_fp_abs(minVal);
|
||
|
TEST_ASSERT_EQUAL(-1, l_fp_signum(minVal));
|
||
|
|
||
|
TEST_ASSERT_EQUAL_l_fp(minVal,minAbs);
|
||
|
//TEST_ASSERT_EQUAL_MEMORY(&minVal, &minAbs,sizeof(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.
|
||
|
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);
|
||
|
double op2 = l_fp_convert_to_double(op1);
|
||
|
l_fp op3 = l_fp_init_from_double(op2);
|
||
|
|
||
|
// for manual checks only:
|
||
|
// std::cout << std::setprecision(16) << op2 << std::endl;
|
||
|
|
||
|
l_fp temp = l_fp_subtract(op1,op3);
|
||
|
double d = l_fp_convert_to_double(temp);
|
||
|
TEST_ASSERT_DOUBLE_WITHIN(eps(op2),0.0, fabs(d)); //delta,epected,actual
|
||
|
|
||
|
//ASSERT_LE(fabs(op1-op3), eps(op2)); //unity has no equivalent of LE!!!
|
||
|
//you could use TEST_ASSERT_TRUE(IsLE(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]);
|
||
|
const lfp_hl * tv = (&addsub_tab[0][0]);
|
||
|
size_t lc ;
|
||
|
for (lc=addsub_tot-1; lc; --lc,++tv) {
|
||
|
l_fp op1 = l_fp_init(tv[0].h,tv[0].l);
|
||
|
l_fp op2 = l_fp_init(tv[1].h,tv[1].l);
|
||
|
//int cmp(op1.scmp(op2));
|
||
|
int cmp = l_fp_scmp(op1,op2);
|
||
|
|
||
|
switch (cmp) {
|
||
|
case -1:
|
||
|
//printf("op1:%d %d, op2:%d %d\n",op1.l_uf,op1.l_ui,op2.l_uf,op2.l_ui);
|
||
|
//std::swap(op1, op2);
|
||
|
l_fp_swap(&op1,&op2);
|
||
|
//printf("op1:%d %d, op2:%d %d\n",op1.l_uf,op1.l_ui,op2.l_uf,op2.l_ui);
|
||
|
case 1:
|
||
|
TEST_ASSERT_TRUE (l_isgt(op1,op2));
|
||
|
TEST_ASSERT_FALSE(l_isgt(op2,op1));
|
||
|
|
||
|
TEST_ASSERT_TRUE (l_isgeq(op1,op2));
|
||
|
TEST_ASSERT_FALSE(l_isgeq(op2,op1));
|
||
|
|
||
|
TEST_ASSERT_FALSE(l_isequ(op1,op2));
|
||
|
TEST_ASSERT_FALSE(l_isequ(op2,op1));
|
||
|
break;
|
||
|
case 0:
|
||
|
TEST_ASSERT_FALSE(l_isgt(op1,op2));
|
||
|
TEST_ASSERT_FALSE(l_isgt(op2,op1));
|
||
|
|
||
|
TEST_ASSERT_TRUE (l_isgeq(op1,op2));
|
||
|
TEST_ASSERT_TRUE (l_isgeq(op2,op1));
|
||
|
|
||
|
TEST_ASSERT_TRUE (l_isequ(op1,op2));
|
||
|
TEST_ASSERT_TRUE (l_isequ(op2,op1));
|
||
|
break;
|
||
|
default:
|
||
|
TEST_FAIL_MESSAGE("unexpected UCMP result: " );
|
||
|
//TEST_ASSERT_FAIL() << "unexpected SCMP result: " << cmp;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void test_UnsignedRelOps() {
|
||
|
const lfp_hl * tv =(&addsub_tab[0][0]);
|
||
|
size_t lc;
|
||
|
for (lc=addsub_tot-1; lc; --lc,++tv) {
|
||
|
l_fp op1 = l_fp_init(tv[0].h,tv[0].l);
|
||
|
l_fp op2 = l_fp_init(tv[1].h,tv[1].l);
|
||
|
int cmp = l_fp_ucmp(op1,op2);
|
||
|
|
||
|
switch (cmp) {
|
||
|
case -1:
|
||
|
//printf("op1:%d %d, op2:%d %d\n",op1.l_uf,op1.l_ui,op2.l_uf,op2.l_ui);
|
||
|
l_fp_swap(&op1, &op2);
|
||
|
//printf("op1:%d %d, op2:%d %d\n",op1.l_uf,op1.l_ui,op2.l_uf,op2.l_ui);
|
||
|
case 1:
|
||
|
TEST_ASSERT_TRUE (l_isgtu(op1,op2));
|
||
|
TEST_ASSERT_FALSE(l_isgtu(op2,op1));
|
||
|
|
||
|
TEST_ASSERT_TRUE (l_ishis(op1,op2));
|
||
|
TEST_ASSERT_FALSE(l_ishis(op2,op1));
|
||
|
break;
|
||
|
case 0:
|
||
|
TEST_ASSERT_FALSE(l_isgtu(op1,op2));
|
||
|
TEST_ASSERT_FALSE(l_isgtu(op2,op1));
|
||
|
|
||
|
TEST_ASSERT_TRUE (l_ishis(op1,op2));
|
||
|
TEST_ASSERT_TRUE (l_ishis(op2,op1));
|
||
|
break;
|
||
|
default:
|
||
|
TEST_FAIL_MESSAGE("unexpected UCMP result: " );
|
||
|
//FAIL() << "unexpected UCMP result: " << cmp;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/*
|
||
|
*/
|
||
|
|
||
|
//----------------------------------------------------------------------
|
||
|
// that's all folks... but feel free to add things!
|
||
|
//----------------------------------------------------------------------
|