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"); \
29 int l_fp_scmp(const l_fp first, const l_fp second);
30 int l_fp_ucmp(const l_fp first, l_fp second);
31 l_fp l_fp_init(int32 i, u_int32 f);
32 l_fp l_fp_add(const l_fp first, const l_fp second);
33 l_fp l_fp_subtract(const l_fp first, const l_fp second);
34 l_fp l_fp_negate(const l_fp first);
35 l_fp l_fp_abs(const l_fp first);
36 int l_fp_signum(const l_fp first);
37 double l_fp_convert_to_double(const l_fp first);
38 l_fp l_fp_init_from_double( double rhs);
39 void l_fp_swap(l_fp * first, l_fp *second);
40 bool l_isgt(const l_fp first, const l_fp second);
41 bool l_isgtu(const l_fp first, const l_fp second);
42 bool l_ishis(const l_fp first, const l_fp second);
43 bool l_isgeq(const l_fp first, const l_fp second);
44 bool l_isequ(const l_fp first, const l_fp second);
48 void test_AdditionLR(void);
49 void test_AdditionRL(void);
50 void test_SubtractionLR(void);
51 void test_SubtractionRL(void);
52 void test_Negation(void);
53 void test_Absolute(void);
54 void test_FDF_RoundTrip(void);
55 void test_SignedRelOps(void);
56 void test_UnsignedRelOps(void);
59 static int cmp_work(u_int32 a[3], u_int32 b[3]);
61 //----------------------------------------------------------------------
62 // reference comparision
63 // This is implementad as a full signed MP-subtract in 3 limbs, where
64 // the operands are zero or sign extended before the subtraction is
66 //----------------------------------------------------------------------
69 l_fp_scmp(const l_fp first, const l_fp second)
73 const l_fp op1 = first;
74 const l_fp op2 = second;
76 a[0] = op1.l_uf; a[1] = op1.l_ui; a[2] = 0;
77 b[0] = op2.l_uf; b[1] = op2.l_ui; b[2] = 0;
79 a[2] -= (op1.l_i < 0);
80 b[2] -= (op2.l_i < 0);
86 l_fp_ucmp(const l_fp first, l_fp second)
89 const l_fp op1 = first;
90 const l_fp op2 = second;
92 a[0] = op1.l_uf; a[1] = op1.l_ui; a[2] = 0;
93 b[0] = op2.l_uf; b[1] = op2.l_ui; b[2] = 0;
98 // maybe rename it to lf_cmp_work
100 cmp_work(u_int32 a[3], u_int32 b[3])
102 u_int32 cy, idx, tmp;
103 for (cy = idx = 0; idx < 3; ++idx) {
104 tmp = a[idx]; cy = (a[idx] -= cy ) > tmp;
105 tmp = a[idx]; cy |= (a[idx] -= b[idx]) > tmp;
113 //----------------------------------------------------------------------
114 // imlementation of the LFP stuff
115 // This should be easy enough...
116 //----------------------------------------------------------------------
119 l_fp_init(int32 i, u_int32 f)
129 l_fp_add(const l_fp first, const l_fp second)
132 L_ADD(&temp, &second);
138 l_fp_subtract(const l_fp first, const l_fp second)
141 L_SUB(&temp, &second);
147 l_fp_negate(const l_fp first)
156 l_fp_abs(const l_fp first)
165 l_fp_signum(const l_fp first)
167 if (first.l_ui & 0x80000000u)
169 return (first.l_ui || first.l_uf);
173 l_fp_convert_to_double(const l_fp first)
181 l_fp_init_from_double( double rhs)
189 l_fp_swap(l_fp * first, l_fp *second)
199 //----------------------------------------------------------------------
200 // testing the relational macros works better with proper predicate
201 // formatting functions; it slows down the tests a bit, but makes for
202 // readable failure messages.
203 //----------------------------------------------------------------------
207 l_isgt (const l_fp first, const l_fp second)
210 return L_ISGT(&first, &second);
214 l_isgtu(const l_fp first, const l_fp second)
217 return L_ISGTU(&first, &second);
221 l_ishis(const l_fp first, const l_fp second)
224 return L_ISHIS(&first, &second);
228 l_isgeq(const l_fp first, const l_fp second)
231 return L_ISGEQ(&first, &second);
235 l_isequ(const l_fp first, const l_fp second)
238 return L_ISEQU(&first, &second);
242 //----------------------------------------------------------------------
243 // test data table for add/sub and compare
244 //----------------------------------------------------------------------
247 static const lfp_hl addsub_tab[][3] = {
249 {{0 ,0 }, { 0,0 }, { 0,0}},
250 // with carry from fraction and sign change:
251 {{-1,0x80000000}, { 0,0x80000000}, { 0,0}},
252 // without carry from fraction
253 {{ 1,0x40000000}, { 1,0x40000000}, { 2,0x80000000}},
254 // with carry from fraction:
255 {{ 1,0xC0000000}, { 1,0xC0000000}, { 3,0x80000000}},
256 // with carry from fraction and sign change:
257 {{0x7FFFFFFF, 0x7FFFFFFF}, {0x7FFFFFFF,0x7FFFFFFF}, {0xFFFFFFFE,0xFFFFFFFE}},
258 // two tests w/o carry (used for l_fp<-->double):
259 {{0x55555555,0xAAAAAAAA}, {0x11111111,0x11111111}, {0x66666666,0xBBBBBBBB}},
260 {{0x55555555,0x55555555}, {0x11111111,0x11111111}, {0x66666666,0x66666666}},
261 // wide-range test, triggers compare trouble
262 {{0x80000000,0x00000001}, {0xFFFFFFFF,0xFFFFFFFE}, {0x7FFFFFFF,0xFFFFFFFF}}
264 static const size_t addsub_cnt = (sizeof(addsub_tab)/sizeof(addsub_tab[0]));
265 static const size_t addsub_tot = (sizeof(addsub_tab)/sizeof(addsub_tab[0][0]));
269 //----------------------------------------------------------------------
270 // epsilon estimation for the precision of a conversion double --> l_fp
272 // The error estimation limit is as follows:
273 // * The 'l_fp' fixed point fraction has 32 bits precision, so we allow
274 // for the LSB to toggle by clamping the epsilon to be at least 2^(-31)
276 // * The double mantissa has a precsion 54 bits, so the other minimum is
279 // The maximum of those two boundaries is used for the check.
281 // Note: once there are more than 54 bits between the highest and lowest
282 // '1'-bit of the l_fp value, the roundtrip *will* create truncation
283 // errors. This is an inherent property caused by the 54-bit mantissa of
284 // the 'double' type.
289 return fmax(ldexp(1.0, -31), ldexp(fabs(d), -53));
292 //----------------------------------------------------------------------
294 //----------------------------------------------------------------------
296 test_AdditionLR(void)
300 for (idx = 0; idx < addsub_cnt; ++idx) {
301 l_fp op1 = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
302 l_fp op2 = l_fp_init(addsub_tab[idx][1].h, addsub_tab[idx][1].l);
303 l_fp e_res = l_fp_init(addsub_tab[idx][2].h, addsub_tab[idx][2].l);
304 l_fp res = l_fp_add(op1, op2);
306 TEST_ASSERT_EQUAL_l_fp(e_res, res);
312 test_AdditionRL(void)
316 for (idx = 0; idx < addsub_cnt; ++idx) {
317 l_fp op2 = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
318 l_fp op1 = l_fp_init(addsub_tab[idx][1].h, addsub_tab[idx][1].l);
319 l_fp e_res = l_fp_init(addsub_tab[idx][2].h, addsub_tab[idx][2].l);
320 l_fp res = l_fp_add(op1, op2);
322 TEST_ASSERT_EQUAL_l_fp(e_res, res);
328 //----------------------------------------------------------------------
330 //----------------------------------------------------------------------
332 test_SubtractionLR(void)
336 for (idx = 0; idx < addsub_cnt; ++idx) {
337 l_fp op2 = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
338 l_fp e_res = l_fp_init(addsub_tab[idx][1].h, addsub_tab[idx][1].l);
339 l_fp op1 = l_fp_init(addsub_tab[idx][2].h, addsub_tab[idx][2].l);
340 l_fp res = l_fp_subtract(op1, op2);
342 TEST_ASSERT_EQUAL_l_fp(e_res, res);
348 test_SubtractionRL(void)
352 for (idx = 0; idx < addsub_cnt; ++idx) {
353 l_fp e_res = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
354 l_fp op2 = l_fp_init(addsub_tab[idx][1].h, addsub_tab[idx][1].l);
355 l_fp op1 = l_fp_init(addsub_tab[idx][2].h, addsub_tab[idx][2].l);
356 l_fp res = l_fp_subtract(op1, op2);
358 TEST_ASSERT_EQUAL_l_fp(e_res, res);
363 //----------------------------------------------------------------------
365 //----------------------------------------------------------------------
372 for (idx = 0; idx < addsub_cnt; ++idx) {
373 l_fp op1 = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
374 l_fp op2 = l_fp_negate(op1);
375 l_fp sum = l_fp_add(op1, op2);
377 l_fp zero = l_fp_init(0, 0);
379 TEST_ASSERT_EQUAL_l_fp(zero, sum);
386 //----------------------------------------------------------------------
387 // test absolute value
388 //----------------------------------------------------------------------
394 for (idx = 0; idx < addsub_cnt; ++idx) {
395 l_fp op1 = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
396 l_fp op2 = l_fp_abs(op1);
398 TEST_ASSERT_TRUE(l_fp_signum(op2) >= 0);
400 if (l_fp_signum(op1) >= 0)
401 op1 = l_fp_subtract(op1, op2);
403 op1 = l_fp_add(op1, op2);
405 l_fp zero = l_fp_init(0, 0);
407 TEST_ASSERT_EQUAL_l_fp(zero, op1);
410 // There is one special case we have to check: the minimum
411 // value cannot be negated, or, to be more precise, the
412 // negation reproduces the original pattern.
413 l_fp minVal = l_fp_init(0x80000000, 0x00000000);
414 l_fp minAbs = l_fp_abs(minVal);
415 TEST_ASSERT_EQUAL(-1, l_fp_signum(minVal));
417 TEST_ASSERT_EQUAL_l_fp(minVal, minAbs);
423 //----------------------------------------------------------------------
424 // fp -> double -> fp rountrip test
425 //----------------------------------------------------------------------
427 test_FDF_RoundTrip(void)
431 // since a l_fp has 64 bits in it's mantissa and a double has
432 // only 54 bits available (including the hidden '1') we have to
433 // make a few concessions on the roundtrip precision. The 'eps()'
434 // function makes an educated guess about the avilable precision
435 // and checks the difference in the two 'l_fp' values against
438 for (idx = 0; idx < addsub_cnt; ++idx) {
439 l_fp op1 = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
440 double op2 = l_fp_convert_to_double(op1);
441 l_fp op3 = l_fp_init_from_double(op2);
443 l_fp temp = l_fp_subtract(op1, op3);
444 double d = l_fp_convert_to_double(temp);
445 TEST_ASSERT_DOUBLE_WITHIN(eps(op2), 0.0, fabs(d));
452 //----------------------------------------------------------------------
453 // test the compare stuff
455 // This uses the local compare and checks if the operations using the
456 // macros in 'ntp_fp.h' produce mathing results.
457 // ----------------------------------------------------------------------
459 test_SignedRelOps(void)
461 const lfp_hl * tv = (&addsub_tab[0][0]);
464 for (lc = addsub_tot - 1; lc; --lc, ++tv) {
465 l_fp op1 = l_fp_init(tv[0].h, tv[0].l);
466 l_fp op2 = l_fp_init(tv[1].h, tv[1].l);
467 int cmp = l_fp_scmp(op1, op2);
471 //printf("op1:%d %d, op2:%d %d\n",op1.l_uf,op1.l_ui,op2.l_uf,op2.l_ui);
472 l_fp_swap(&op1, &op2);
473 //printf("op1:%d %d, op2:%d %d\n",op1.l_uf,op1.l_ui,op2.l_uf,op2.l_ui);
475 TEST_ASSERT_TRUE (l_isgt(op1, op2));
476 TEST_ASSERT_FALSE(l_isgt(op2, op1));
478 TEST_ASSERT_TRUE (l_isgeq(op1, op2));
479 TEST_ASSERT_FALSE(l_isgeq(op2, op1));
481 TEST_ASSERT_FALSE(l_isequ(op1, op2));
482 TEST_ASSERT_FALSE(l_isequ(op2, op1));
485 TEST_ASSERT_FALSE(l_isgt(op1, op2));
486 TEST_ASSERT_FALSE(l_isgt(op2, op1));
488 TEST_ASSERT_TRUE (l_isgeq(op1, op2));
489 TEST_ASSERT_TRUE (l_isgeq(op2, op1));
491 TEST_ASSERT_TRUE (l_isequ(op1, op2));
492 TEST_ASSERT_TRUE (l_isequ(op2, op1));
495 TEST_FAIL_MESSAGE("unexpected UCMP result: ");
503 test_UnsignedRelOps(void)
505 const lfp_hl * tv =(&addsub_tab[0][0]);
508 for (lc = addsub_tot - 1; lc; --lc, ++tv) {
509 l_fp op1 = l_fp_init(tv[0].h, tv[0].l);
510 l_fp op2 = l_fp_init(tv[1].h, tv[1].l);
511 int cmp = l_fp_ucmp(op1, op2);
515 //printf("op1:%d %d, op2:%d %d\n",op1.l_uf,op1.l_ui,op2.l_uf,op2.l_ui);
516 l_fp_swap(&op1, &op2);
517 //printf("op1:%d %d, op2:%d %d\n",op1.l_uf,op1.l_ui,op2.l_uf,op2.l_ui);
519 TEST_ASSERT_TRUE (l_isgtu(op1, op2));
520 TEST_ASSERT_FALSE(l_isgtu(op2, op1));
522 TEST_ASSERT_TRUE (l_ishis(op1, op2));
523 TEST_ASSERT_FALSE(l_ishis(op2, op1));
526 TEST_ASSERT_FALSE(l_isgtu(op1, op2));
527 TEST_ASSERT_FALSE(l_isgtu(op2, op1));
529 TEST_ASSERT_TRUE (l_ishis(op1, op2));
530 TEST_ASSERT_TRUE (l_ishis(op2, op1));
533 TEST_FAIL_MESSAGE("unexpected UCMP result: ");
543 //----------------------------------------------------------------------
544 // that's all folks... but feel free to add things!
545 //----------------------------------------------------------------------