1 #include "g_libntptest.h"
2 #include "g_timestructs.h"
14 class lfpTest : public libntptest
16 // nothing new right now
23 //----------------------------------------------------------------------
24 // OO-wrapper for 'l_fp'
25 //----------------------------------------------------------------------
33 LFP(int32 i, u_int32 f);
35 LFP operator+ (const LFP &rhs) const;
36 LFP& operator+=(const LFP &rhs);
38 LFP operator- (const LFP &rhs) const;
39 LFP& operator-=(const LFP &rhs);
41 LFP& operator=(const LFP &rhs);
42 LFP operator-() const;
44 bool operator==(const LFP &rhs) const;
50 bool l_isgt (const LFP &rhs) const
51 { return L_ISGT(&_v, &rhs._v); }
52 bool l_isgtu(const LFP &rhs) const
53 { return L_ISGTU(&_v, &rhs._v); }
54 bool l_ishis(const LFP &rhs) const
55 { return L_ISHIS(&_v, &rhs._v); }
56 bool l_isgeq(const LFP &rhs) const
57 { return L_ISGEQ(&_v, &rhs._v); }
58 bool l_isequ(const LFP &rhs) const
59 { return L_ISEQU(&_v, &rhs._v); }
61 int ucmp(const LFP & rhs) const;
62 int scmp(const LFP & rhs) const;
64 std::string toString() const;
65 std::ostream& toStream(std::ostream &oo) const;
67 operator double() const;
73 static int cmp_work(u_int32 a[3], u_int32 b[3]);
78 static std::ostream& operator<<(std::ostream &oo, const LFP& rhs)
80 return rhs.toStream(oo);
83 //----------------------------------------------------------------------
84 // reference comparision
85 // This is implementad as a full signed MP-subtract in 3 limbs, where
86 // the operands are zero or sign extended before the subtraction is
88 //----------------------------------------------------------------------
89 int LFP::scmp(const LFP & rhs) const
92 const l_fp &op1(_v), &op2(rhs._v);
94 a[0] = op1.l_uf; a[1] = op1.l_ui; a[2] = 0;
95 b[0] = op2.l_uf; b[1] = op2.l_ui; b[2] = 0;
97 a[2] -= (op1.l_i < 0);
98 b[2] -= (op2.l_i < 0);
100 return cmp_work(a,b);
103 int LFP::ucmp(const LFP & rhs) const
106 const l_fp &op1(_v), &op2(rhs._v);
108 a[0] = op1.l_uf; a[1] = op1.l_ui; a[2] = 0;
109 b[0] = op2.l_uf; b[1] = op2.l_ui; b[2] = 0;
111 return cmp_work(a,b);
114 int LFP::cmp_work(u_int32 a[3], u_int32 b[3])
116 u_int32 cy, idx, tmp;
117 for (cy = idx = 0; idx < 3; ++idx) {
118 tmp = a[idx]; cy = (a[idx] -= cy ) > tmp;
119 tmp = a[idx]; cy |= (a[idx] -= b[idx]) > tmp;
126 //----------------------------------------------------------------------
127 // imlementation of the LFP stuff
128 // This should be easy enough...
129 //----------------------------------------------------------------------
142 LFP::LFP(int32 i, u_int32 f)
148 LFP::LFP(const LFP &rhs)
153 LFP::LFP(const l_fp & rhs)
158 LFP& LFP::operator=(const LFP & rhs)
164 LFP& LFP::operator+=(const LFP & rhs)
170 LFP& LFP::operator-=(const LFP & rhs)
176 LFP LFP::operator+(const LFP &rhs) const
182 LFP LFP::operator-(const LFP &rhs) const
188 LFP LFP::operator-() const
207 if (L_ISNEG(&tmp._v))
215 if (_v.l_ui & 0x80000000u)
217 return (_v.l_ui || _v.l_uf);
221 LFP::toString() const
223 std::ostringstream oss;
229 LFP::toStream(std::ostream &os) const
232 << mfptoa(_v.l_ui, _v.l_uf, 9)
233 << " [$" << std::setw(8) << std::setfill('0') << std::hex << _v.l_ui
234 << ':' << std::setw(8) << std::setfill('0') << std::hex << _v.l_uf
238 bool LFP::operator==(const LFP &rhs) const
240 return L_ISEQU(&_v, &rhs._v);
244 LFP::operator double() const
257 //----------------------------------------------------------------------
258 // testing the relational macros works better with proper predicate
259 // formatting functions; it slows down the tests a bit, but makes for
260 // readable failure messages.
261 //----------------------------------------------------------------------
263 testing::AssertionResult isgt_p(
264 const LFP &op1, const LFP &op2)
267 return testing::AssertionSuccess()
268 << "L_ISGT(" << op1 << "," << op2 << ") is true";
270 return testing::AssertionFailure()
271 << "L_ISGT(" << op1 << "," << op2 << ") is false";
274 testing::AssertionResult isgeq_p(
275 const LFP &op1, const LFP &op2)
277 if (op1.l_isgeq(op2))
278 return testing::AssertionSuccess()
279 << "L_ISGEQ(" << op1 << "," << op2 << ") is true";
281 return testing::AssertionFailure()
282 << "L_ISGEQ(" << op1 << "," << op2 << ") is false";
285 testing::AssertionResult isgtu_p(
286 const LFP &op1, const LFP &op2)
288 if (op1.l_isgtu(op2))
289 return testing::AssertionSuccess()
290 << "L_ISGTU(" << op1 << "," << op2 << ") is true";
292 return testing::AssertionFailure()
293 << "L_ISGTU(" << op1 << "," << op2 << ") is false";
296 testing::AssertionResult ishis_p(
297 const LFP &op1, const LFP &op2)
299 if (op1.l_ishis(op2))
300 return testing::AssertionSuccess()
301 << "L_ISHIS(" << op1 << "," << op2 << ") is true";
303 return testing::AssertionFailure()
304 << "L_ISHIS(" << op1 << "," << op2 << ") is false";
307 testing::AssertionResult isequ_p(
308 const LFP &op1, const LFP &op2)
310 if (op1.l_isequ(op2))
311 return testing::AssertionSuccess()
312 << "L_ISEQU(" << op1 << "," << op2 << ") is true";
314 return testing::AssertionFailure()
315 << "L_ISEQU(" << op1 << "," << op2 << ") is false";
318 //----------------------------------------------------------------------
319 // test data table for add/sub and compare
320 //----------------------------------------------------------------------
322 static const lfp_hl addsub_tab[][3] = {
324 {{0 ,0 }, { 0,0 }, { 0,0}},
325 // with carry from fraction and sign change:
326 {{-1,0x80000000}, { 0,0x80000000}, { 0,0}},
327 // without carry from fraction
328 {{ 1,0x40000000}, { 1,0x40000000}, { 2,0x80000000}},
329 // with carry from fraction:
330 {{ 1,0xC0000000}, { 1,0xC0000000}, { 3,0x80000000}},
331 // with carry from fraction and sign change:
332 {{0x7FFFFFFF, 0x7FFFFFFF}, {0x7FFFFFFF,0x7FFFFFFF}, {0xFFFFFFFE,0xFFFFFFFE}},
333 // two tests w/o carry (used for l_fp<-->double):
334 {{0x55555555,0xAAAAAAAA}, {0x11111111,0x11111111}, {0x66666666,0xBBBBBBBB}},
335 {{0x55555555,0x55555555}, {0x11111111,0x11111111}, {0x66666666,0x66666666}},
336 // wide-range test, triggers compare trouble
337 {{0x80000000,0x00000001}, {0xFFFFFFFF,0xFFFFFFFE}, {0x7FFFFFFF,0xFFFFFFFF}}
339 static const size_t addsub_cnt(sizeof(addsub_tab)/sizeof(addsub_tab[0]));
340 static const size_t addsub_tot(sizeof(addsub_tab)/sizeof(addsub_tab[0][0]));
343 //----------------------------------------------------------------------
344 // epsilon estimation for the precision of a conversion double --> l_fp
346 // The error estimation limit is as follows:
347 // * The 'l_fp' fixed point fraction has 32 bits precision, so we allow
348 // for the LSB to toggle by clamping the epsilon to be at least 2^(-31)
350 // * The double mantissa has a precsion 54 bits, so the other minimum is
353 // The maximum of those two boundaries is used for the check.
355 // Note: once there are more than 54 bits between the highest and lowest
356 // '1'-bit of the l_fp value, the roundtrip *will* create truncation
357 // errors. This is an inherent property caused by the 54-bit mantissa of
358 // the 'double' type.
361 return std::max<double>(ldexp(1.0, -31), ldexp(fabs(d), -53));
364 //----------------------------------------------------------------------
366 //----------------------------------------------------------------------
367 TEST_F(lfpTest, AdditionLR) {
368 for (size_t idx=0; idx < addsub_cnt; ++idx) {
369 LFP op1(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
370 LFP op2(addsub_tab[idx][1].h, addsub_tab[idx][1].l);
371 LFP exp(addsub_tab[idx][2].h, addsub_tab[idx][2].l);
378 TEST_F(lfpTest, AdditionRL) {
379 for (size_t idx=0; idx < addsub_cnt; ++idx) {
380 LFP op2(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
381 LFP op1(addsub_tab[idx][1].h, addsub_tab[idx][1].l);
382 LFP exp(addsub_tab[idx][2].h, addsub_tab[idx][2].l);
389 //----------------------------------------------------------------------
391 //----------------------------------------------------------------------
392 TEST_F(lfpTest, SubtractionLR) {
393 for (size_t idx=0; idx < addsub_cnt; ++idx) {
394 LFP op2(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
395 LFP exp(addsub_tab[idx][1].h, addsub_tab[idx][1].l);
396 LFP op1(addsub_tab[idx][2].h, addsub_tab[idx][2].l);
403 TEST_F(lfpTest, SubtractionRL) {
404 for (size_t idx=0; idx < addsub_cnt; ++idx) {
405 LFP exp(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
406 LFP op2(addsub_tab[idx][1].h, addsub_tab[idx][1].l);
407 LFP op1(addsub_tab[idx][2].h, addsub_tab[idx][2].l);
414 //----------------------------------------------------------------------
416 //----------------------------------------------------------------------
417 TEST_F(lfpTest, Negation) {
418 for (size_t idx=0; idx < addsub_cnt; ++idx) {
419 LFP op1(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
423 ASSERT_EQ(LFP(0,0), sum);
427 //----------------------------------------------------------------------
428 // test absolute value
429 //----------------------------------------------------------------------
430 TEST_F(lfpTest, Absolute) {
431 for (size_t idx=0; idx < addsub_cnt; ++idx) {
432 LFP op1(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
435 ASSERT_TRUE(op2.signum() >= 0);
437 if (op1.signum() >= 0)
441 ASSERT_EQ(LFP(0,0), op1);
444 // There is one special case we have to check: the minimum
445 // value cannot be negated, or, to be more precise, the
446 // negation reproduces the original pattern.
447 LFP minVal(0x80000000, 0x00000000);
448 LFP minAbs(minVal.abs());
449 ASSERT_EQ(-1, minVal.signum());
450 ASSERT_EQ(minVal, minAbs);
453 //----------------------------------------------------------------------
454 // fp -> double -> fp rountrip test
455 //----------------------------------------------------------------------
456 TEST_F(lfpTest, FDF_RoundTrip) {
457 // since a l_fp has 64 bits in it's mantissa and a double has
458 // only 54 bits available (including the hidden '1') we have to
459 // make a few concessions on the roundtrip precision. The 'eps()'
460 // function makes an educated guess about the avilable precision
461 // and checks the difference in the two 'l_fp' values against
463 for (size_t idx=0; idx < addsub_cnt; ++idx) {
464 LFP op1(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
467 // for manual checks only:
468 // std::cout << std::setprecision(16) << op2 << std::endl;
469 ASSERT_LE(fabs(op1-op3), eps(op2));
473 //----------------------------------------------------------------------
474 // test the compare stuff
476 // This uses the local compare and checks if the operations using the
477 // macros in 'ntp_fp.h' produce mathing results.
478 // ----------------------------------------------------------------------
479 TEST_F(lfpTest, SignedRelOps) {
480 const lfp_hl * tv(&addsub_tab[0][0]);
481 for (size_t lc=addsub_tot-1; lc; --lc,++tv) {
482 LFP op1(tv[0].h,tv[0].l);
483 LFP op2(tv[1].h,tv[1].l);
484 int cmp(op1.scmp(op2));
490 EXPECT_TRUE (isgt_p(op1,op2));
491 EXPECT_FALSE(isgt_p(op2,op1));
493 EXPECT_TRUE (isgeq_p(op1,op2));
494 EXPECT_FALSE(isgeq_p(op2,op1));
496 EXPECT_FALSE(isequ_p(op1,op2));
497 EXPECT_FALSE(isequ_p(op2,op1));
500 EXPECT_FALSE(isgt_p(op1,op2));
501 EXPECT_FALSE(isgt_p(op2,op1));
503 EXPECT_TRUE (isgeq_p(op1,op2));
504 EXPECT_TRUE (isgeq_p(op2,op1));
506 EXPECT_TRUE (isequ_p(op1,op2));
507 EXPECT_TRUE (isequ_p(op2,op1));
510 FAIL() << "unexpected SCMP result: " << cmp;
515 TEST_F(lfpTest, UnsignedRelOps) {
516 const lfp_hl * tv(&addsub_tab[0][0]);
517 for (size_t lc=addsub_tot-1; lc; --lc,++tv) {
518 LFP op1(tv[0].h,tv[0].l);
519 LFP op2(tv[1].h,tv[1].l);
520 int cmp(op1.ucmp(op2));
526 EXPECT_TRUE (isgtu_p(op1,op2));
527 EXPECT_FALSE(isgtu_p(op2,op1));
529 EXPECT_TRUE (ishis_p(op1,op2));
530 EXPECT_FALSE(ishis_p(op2,op1));
533 EXPECT_FALSE(isgtu_p(op1,op2));
534 EXPECT_FALSE(isgtu_p(op2,op1));
536 EXPECT_TRUE (ishis_p(op1,op2));
537 EXPECT_TRUE (ishis_p(op2,op1));
540 FAIL() << "unexpected UCMP result: " << cmp;
545 //----------------------------------------------------------------------
546 // that's all folks... but feel free to add things!
547 //----------------------------------------------------------------------