3 #include "ntp_stdlib.h"
13 replaced: TEST_ASSERT_EQUAL_MEMORY(&a, &b, sizeof(a))
14 with: TEST_ASSERT_EQUAL_l_fp(a, b).
15 It's safer this way, because structs can be compared even if they
16 aren't initiated with memset (due to padding bytes).
18 #define TEST_ASSERT_EQUAL_l_fp(a, b) { \
19 TEST_ASSERT_EQUAL_MESSAGE(a.l_i, b.l_i, "Field l_i"); \
20 TEST_ASSERT_EQUAL_UINT_MESSAGE(a.l_uf, b.l_uf, "Field l_uf"); \
24 typedef int bool; // typedef enum { FALSE, TRUE } boolean; -> can't use this because TRUE and FALSE are already defined
32 int l_fp_scmp(const l_fp first, const l_fp second);
33 int l_fp_ucmp(const l_fp first, l_fp second);
34 l_fp l_fp_init(int32 i, u_int32 f);
35 l_fp l_fp_add(const l_fp first, const l_fp second);
36 l_fp l_fp_subtract(const l_fp first, const l_fp second);
37 l_fp l_fp_negate(const l_fp first);
38 l_fp l_fp_abs(const l_fp first);
39 int l_fp_signum(const l_fp first);
40 double l_fp_convert_to_double(const l_fp first);
41 l_fp l_fp_init_from_double( double rhs);
42 void l_fp_swap(l_fp * first, l_fp *second);
43 bool l_isgt(const l_fp first, const l_fp second);
44 bool l_isgtu(const l_fp first, const l_fp second);
45 bool l_ishis(const l_fp first, const l_fp second);
46 bool l_isgeq(const l_fp first, const l_fp second);
47 bool l_isequ(const l_fp first, const l_fp second);
51 void test_AdditionLR(void);
52 void test_AdditionRL(void);
53 void test_SubtractionLR(void);
54 void test_SubtractionRL(void);
55 void test_Negation(void);
56 void test_Absolute(void);
57 void test_FDF_RoundTrip(void);
58 void test_SignedRelOps(void);
59 void test_UnsignedRelOps(void);
62 static int cmp_work(u_int32 a[3], u_int32 b[3]);
64 //----------------------------------------------------------------------
65 // reference comparision
66 // This is implementad as a full signed MP-subtract in 3 limbs, where
67 // the operands are zero or sign extended before the subtraction is
69 //----------------------------------------------------------------------
72 l_fp_scmp(const l_fp first, const l_fp second)
76 const l_fp op1 = first;
77 const l_fp op2 = second;
79 a[0] = op1.l_uf; a[1] = op1.l_ui; a[2] = 0;
80 b[0] = op2.l_uf; b[1] = op2.l_ui; b[2] = 0;
82 a[2] -= (op1.l_i < 0);
83 b[2] -= (op2.l_i < 0);
89 l_fp_ucmp(const l_fp first, l_fp second)
92 const l_fp op1 = first;
93 const l_fp op2 = second;
95 a[0] = op1.l_uf; a[1] = op1.l_ui; a[2] = 0;
96 b[0] = op2.l_uf; b[1] = op2.l_ui; b[2] = 0;
101 // maybe rename it to lf_cmp_work
103 cmp_work(u_int32 a[3], u_int32 b[3])
105 u_int32 cy, idx, tmp;
106 for (cy = idx = 0; idx < 3; ++idx) {
107 tmp = a[idx]; cy = (a[idx] -= cy ) > tmp;
108 tmp = a[idx]; cy |= (a[idx] -= b[idx]) > tmp;
116 //----------------------------------------------------------------------
117 // imlementation of the LFP stuff
118 // This should be easy enough...
119 //----------------------------------------------------------------------
122 l_fp_init(int32 i, u_int32 f)
132 l_fp_add(const l_fp first, const l_fp second)
135 L_ADD(&temp, &second);
141 l_fp_subtract(const l_fp first, const l_fp second)
144 L_SUB(&temp, &second);
150 l_fp_negate(const l_fp first)
159 l_fp_abs(const l_fp first)
168 l_fp_signum(const l_fp first)
170 if (first.l_ui & 0x80000000u)
172 return (first.l_ui || first.l_uf);
176 l_fp_convert_to_double(const l_fp first)
184 l_fp_init_from_double( double rhs)
192 l_fp_swap(l_fp * first, l_fp *second)
202 //----------------------------------------------------------------------
203 // testing the relational macros works better with proper predicate
204 // formatting functions; it slows down the tests a bit, but makes for
205 // readable failure messages.
206 //----------------------------------------------------------------------
210 l_isgt (const l_fp first, const l_fp second)
213 return L_ISGT(&first, &second);
217 l_isgtu(const l_fp first, const l_fp second)
220 return L_ISGTU(&first, &second);
224 l_ishis(const l_fp first, const l_fp second)
227 return L_ISHIS(&first, &second);
231 l_isgeq(const l_fp first, const l_fp second)
234 return L_ISGEQ(&first, &second);
238 l_isequ(const l_fp first, const l_fp second)
241 return L_ISEQU(&first, &second);
245 //----------------------------------------------------------------------
246 // test data table for add/sub and compare
247 //----------------------------------------------------------------------
250 static const lfp_hl addsub_tab[][3] = {
252 {{0 ,0 }, { 0,0 }, { 0,0}},
253 // with carry from fraction and sign change:
254 {{-1,0x80000000}, { 0,0x80000000}, { 0,0}},
255 // without carry from fraction
256 {{ 1,0x40000000}, { 1,0x40000000}, { 2,0x80000000}},
257 // with carry from fraction:
258 {{ 1,0xC0000000}, { 1,0xC0000000}, { 3,0x80000000}},
259 // with carry from fraction and sign change:
260 {{0x7FFFFFFF, 0x7FFFFFFF}, {0x7FFFFFFF,0x7FFFFFFF}, {0xFFFFFFFE,0xFFFFFFFE}},
261 // two tests w/o carry (used for l_fp<-->double):
262 {{0x55555555,0xAAAAAAAA}, {0x11111111,0x11111111}, {0x66666666,0xBBBBBBBB}},
263 {{0x55555555,0x55555555}, {0x11111111,0x11111111}, {0x66666666,0x66666666}},
264 // wide-range test, triggers compare trouble
265 {{0x80000000,0x00000001}, {0xFFFFFFFF,0xFFFFFFFE}, {0x7FFFFFFF,0xFFFFFFFF}}
267 static const size_t addsub_cnt = (sizeof(addsub_tab)/sizeof(addsub_tab[0]));
268 static const size_t addsub_tot = (sizeof(addsub_tab)/sizeof(addsub_tab[0][0]));
272 //----------------------------------------------------------------------
273 // epsilon estimation for the precision of a conversion double --> l_fp
275 // The error estimation limit is as follows:
276 // * The 'l_fp' fixed point fraction has 32 bits precision, so we allow
277 // for the LSB to toggle by clamping the epsilon to be at least 2^(-31)
279 // * The double mantissa has a precsion 54 bits, so the other minimum is
282 // The maximum of those two boundaries is used for the check.
284 // Note: once there are more than 54 bits between the highest and lowest
285 // '1'-bit of the l_fp value, the roundtrip *will* create truncation
286 // errors. This is an inherent property caused by the 54-bit mantissa of
287 // the 'double' type.
292 return fmax(ldexp(1.0, -31), ldexp(fabs(d), -53));
295 //----------------------------------------------------------------------
297 //----------------------------------------------------------------------
299 test_AdditionLR(void)
303 for (idx = 0; idx < addsub_cnt; ++idx) {
304 l_fp op1 = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
305 l_fp op2 = l_fp_init(addsub_tab[idx][1].h, addsub_tab[idx][1].l);
306 l_fp e_res = l_fp_init(addsub_tab[idx][2].h, addsub_tab[idx][2].l);
307 l_fp res = l_fp_add(op1, op2);
309 TEST_ASSERT_EQUAL_l_fp(e_res, res);
315 test_AdditionRL(void)
319 for (idx = 0; idx < addsub_cnt; ++idx) {
320 l_fp op2 = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
321 l_fp op1 = l_fp_init(addsub_tab[idx][1].h, addsub_tab[idx][1].l);
322 l_fp e_res = l_fp_init(addsub_tab[idx][2].h, addsub_tab[idx][2].l);
323 l_fp res = l_fp_add(op1, op2);
325 TEST_ASSERT_EQUAL_l_fp(e_res, res);
331 //----------------------------------------------------------------------
333 //----------------------------------------------------------------------
335 test_SubtractionLR(void)
339 for (idx = 0; idx < addsub_cnt; ++idx) {
340 l_fp op2 = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
341 l_fp e_res = l_fp_init(addsub_tab[idx][1].h, addsub_tab[idx][1].l);
342 l_fp op1 = l_fp_init(addsub_tab[idx][2].h, addsub_tab[idx][2].l);
343 l_fp res = l_fp_subtract(op1, op2);
345 TEST_ASSERT_EQUAL_l_fp(e_res, res);
351 test_SubtractionRL(void)
355 for (idx = 0; idx < addsub_cnt; ++idx) {
356 l_fp e_res = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
357 l_fp op2 = l_fp_init(addsub_tab[idx][1].h, addsub_tab[idx][1].l);
358 l_fp op1 = l_fp_init(addsub_tab[idx][2].h, addsub_tab[idx][2].l);
359 l_fp res = l_fp_subtract(op1, op2);
361 TEST_ASSERT_EQUAL_l_fp(e_res, res);
366 //----------------------------------------------------------------------
368 //----------------------------------------------------------------------
375 for (idx = 0; idx < addsub_cnt; ++idx) {
376 l_fp op1 = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
377 l_fp op2 = l_fp_negate(op1);
378 l_fp sum = l_fp_add(op1, op2);
380 l_fp zero = l_fp_init(0, 0);
382 TEST_ASSERT_EQUAL_l_fp(zero, sum);
389 //----------------------------------------------------------------------
390 // test absolute value
391 //----------------------------------------------------------------------
397 for (idx = 0; idx < addsub_cnt; ++idx) {
398 l_fp op1 = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
399 l_fp op2 = l_fp_abs(op1);
401 TEST_ASSERT_TRUE(l_fp_signum(op2) >= 0);
403 if (l_fp_signum(op1) >= 0)
404 op1 = l_fp_subtract(op1, op2);
406 op1 = l_fp_add(op1, op2);
408 l_fp zero = l_fp_init(0, 0);
410 TEST_ASSERT_EQUAL_l_fp(zero, op1);
413 // There is one special case we have to check: the minimum
414 // value cannot be negated, or, to be more precise, the
415 // negation reproduces the original pattern.
416 l_fp minVal = l_fp_init(0x80000000, 0x00000000);
417 l_fp minAbs = l_fp_abs(minVal);
418 TEST_ASSERT_EQUAL(-1, l_fp_signum(minVal));
420 TEST_ASSERT_EQUAL_l_fp(minVal, minAbs);
426 //----------------------------------------------------------------------
427 // fp -> double -> fp rountrip test
428 //----------------------------------------------------------------------
430 test_FDF_RoundTrip(void)
434 // since a l_fp has 64 bits in it's mantissa and a double has
435 // only 54 bits available (including the hidden '1') we have to
436 // make a few concessions on the roundtrip precision. The 'eps()'
437 // function makes an educated guess about the avilable precision
438 // and checks the difference in the two 'l_fp' values against
441 for (idx = 0; idx < addsub_cnt; ++idx) {
442 l_fp op1 = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
443 double op2 = l_fp_convert_to_double(op1);
444 l_fp op3 = l_fp_init_from_double(op2);
446 l_fp temp = l_fp_subtract(op1, op3);
447 double d = l_fp_convert_to_double(temp);
448 TEST_ASSERT_DOUBLE_WITHIN(eps(op2), 0.0, fabs(d));
455 //----------------------------------------------------------------------
456 // test the compare stuff
458 // This uses the local compare and checks if the operations using the
459 // macros in 'ntp_fp.h' produce mathing results.
460 // ----------------------------------------------------------------------
462 test_SignedRelOps(void)
464 const lfp_hl * tv = (&addsub_tab[0][0]);
467 for (lc = addsub_tot - 1; lc; --lc, ++tv) {
468 l_fp op1 = l_fp_init(tv[0].h, tv[0].l);
469 l_fp op2 = l_fp_init(tv[1].h, tv[1].l);
470 int cmp = l_fp_scmp(op1, op2);
474 //printf("op1:%d %d, op2:%d %d\n",op1.l_uf,op1.l_ui,op2.l_uf,op2.l_ui);
475 l_fp_swap(&op1, &op2);
476 //printf("op1:%d %d, op2:%d %d\n",op1.l_uf,op1.l_ui,op2.l_uf,op2.l_ui);
478 TEST_ASSERT_TRUE (l_isgt(op1, op2));
479 TEST_ASSERT_FALSE(l_isgt(op2, op1));
481 TEST_ASSERT_TRUE (l_isgeq(op1, op2));
482 TEST_ASSERT_FALSE(l_isgeq(op2, op1));
484 TEST_ASSERT_FALSE(l_isequ(op1, op2));
485 TEST_ASSERT_FALSE(l_isequ(op2, op1));
488 TEST_ASSERT_FALSE(l_isgt(op1, op2));
489 TEST_ASSERT_FALSE(l_isgt(op2, op1));
491 TEST_ASSERT_TRUE (l_isgeq(op1, op2));
492 TEST_ASSERT_TRUE (l_isgeq(op2, op1));
494 TEST_ASSERT_TRUE (l_isequ(op1, op2));
495 TEST_ASSERT_TRUE (l_isequ(op2, op1));
498 TEST_FAIL_MESSAGE("unexpected UCMP result: ");
506 test_UnsignedRelOps(void)
508 const lfp_hl * tv =(&addsub_tab[0][0]);
511 for (lc = addsub_tot - 1; lc; --lc, ++tv) {
512 l_fp op1 = l_fp_init(tv[0].h, tv[0].l);
513 l_fp op2 = l_fp_init(tv[1].h, tv[1].l);
514 int cmp = l_fp_ucmp(op1, op2);
518 //printf("op1:%d %d, op2:%d %d\n",op1.l_uf,op1.l_ui,op2.l_uf,op2.l_ui);
519 l_fp_swap(&op1, &op2);
520 //printf("op1:%d %d, op2:%d %d\n",op1.l_uf,op1.l_ui,op2.l_uf,op2.l_ui);
522 TEST_ASSERT_TRUE (l_isgtu(op1, op2));
523 TEST_ASSERT_FALSE(l_isgtu(op2, op1));
525 TEST_ASSERT_TRUE (l_ishis(op1, op2));
526 TEST_ASSERT_FALSE(l_ishis(op2, op1));
529 TEST_ASSERT_FALSE(l_isgtu(op1, op2));
530 TEST_ASSERT_FALSE(l_isgtu(op2, op1));
532 TEST_ASSERT_TRUE (l_ishis(op1, op2));
533 TEST_ASSERT_TRUE (l_ishis(op2, op1));
536 TEST_FAIL_MESSAGE("unexpected UCMP result: ");
546 //----------------------------------------------------------------------
547 // that's all folks... but feel free to add things!
548 //----------------------------------------------------------------------