lfpfunc.c revision 293893
1284990Scy#include "config.h"
2284990Scy
3284990Scy#include "ntp_stdlib.h"
4284990Scy#include "ntp_fp.h"
5284990Scy
6284990Scy#include "unity.h"
7284990Scy
8284990Scy#include <float.h>
9284990Scy#include <math.h>
10284990Scy
11284990Scy
12293893Sglebius/*
13293893Sglebius   replaced:	TEST_ASSERT_EQUAL_MEMORY(&a, &b, sizeof(a))
14293893Sglebius   with:	TEST_ASSERT_EQUAL_l_fp(a, b).
15293893Sglebius   It's safer this way, because structs can be compared even if they
16293893Sglebius   aren't initiated with memset (due to padding bytes).
17289999Sglebius*/
18293893Sglebius#define TEST_ASSERT_EQUAL_l_fp(a, b) {					\
19293893Sglebius	TEST_ASSERT_EQUAL_MESSAGE(a.l_i, b.l_i, "Field l_i");		\
20293893Sglebius	TEST_ASSERT_EQUAL_UINT_MESSAGE(a.l_uf, b.l_uf, "Field l_uf");	\
21284990Scy}
22284990Scy
23284990Scy
24289999Sglebiustypedef int bool; // typedef enum { FALSE, TRUE } boolean; -> can't use this because TRUE and FALSE are already defined
25284990Scy
26284990Scy
27289999Sglebiustypedef struct  {
28289999Sglebius	uint32_t h, l;
29289999Sglebius} lfp_hl;
30284990Scy
31284990Scy
32293893Sglebiusint	l_fp_scmp(const l_fp first, const l_fp second);
33293893Sglebiusint	l_fp_ucmp(const l_fp first, l_fp second);
34293893Sglebiusl_fp	l_fp_init(int32 i, u_int32 f);
35293893Sglebiusl_fp	l_fp_add(const l_fp first, const l_fp second);
36293893Sglebiusl_fp	l_fp_subtract(const l_fp first, const l_fp second);
37293893Sglebiusl_fp	l_fp_negate(const l_fp first);
38293893Sglebiusl_fp	l_fp_abs(const l_fp first);
39293893Sglebiusint	l_fp_signum(const l_fp first);
40293893Sglebiusdouble	l_fp_convert_to_double(const l_fp first);
41293893Sglebiusl_fp	l_fp_init_from_double( double rhs);
42293893Sglebiusvoid	l_fp_swap(l_fp * first, l_fp *second);
43293893Sglebiusbool	l_isgt(const l_fp first, const l_fp second);
44293893Sglebiusbool	l_isgtu(const l_fp first, const l_fp second);
45293893Sglebiusbool	l_ishis(const l_fp first, const l_fp second);
46293893Sglebiusbool	l_isgeq(const l_fp first, const l_fp second);
47293893Sglebiusbool	l_isequ(const l_fp first, const l_fp second);
48293893Sglebiusdouble	eps(double d);
49284990Scy
50284990Scy
51289999Sglebiusvoid test_AdditionLR(void);
52289999Sglebiusvoid test_AdditionRL(void);
53289999Sglebiusvoid test_SubtractionLR(void);
54289999Sglebiusvoid test_SubtractionRL(void);
55289999Sglebiusvoid test_Negation(void);
56289999Sglebiusvoid test_Absolute(void);
57289999Sglebiusvoid test_FDF_RoundTrip(void);
58289999Sglebiusvoid test_SignedRelOps(void);
59289999Sglebiusvoid test_UnsignedRelOps(void);
60284990Scy
61284990Scy
62289999Sglebiusstatic int cmp_work(u_int32 a[3], u_int32 b[3]);
63284990Scy
64284990Scy//----------------------------------------------------------------------
65284990Scy// reference comparision
66284990Scy// This is implementad as a full signed MP-subtract in 3 limbs, where
67284990Scy// the operands are zero or sign extended before the subtraction is
68284990Scy// executed.
69284990Scy//----------------------------------------------------------------------
70289999Sglebius
71289999Sglebiusint
72289999Sglebiusl_fp_scmp(const l_fp first, const l_fp second)
73284990Scy{
74284990Scy	u_int32 a[3], b[3];
75293893Sglebius
76284990Scy	const l_fp op1 = first;
77284990Scy	const l_fp op2 = second;
78293893Sglebius
79284990Scy	a[0] = op1.l_uf; a[1] = op1.l_ui; a[2] = 0;
80284990Scy	b[0] = op2.l_uf; b[1] = op2.l_ui; b[2] = 0;
81284990Scy
82284990Scy	a[2] -= (op1.l_i < 0);
83284990Scy	b[2] -= (op2.l_i < 0);
84284990Scy
85284990Scy	return cmp_work(a,b);
86284990Scy}
87284990Scy
88289999Sglebiusint
89293893Sglebiusl_fp_ucmp(const l_fp first, l_fp second)
90284990Scy{
91284990Scy	u_int32 a[3], b[3];
92284990Scy	const l_fp op1 = first;
93284990Scy	const l_fp op2 = second;
94293893Sglebius
95284990Scy	a[0] = op1.l_uf; a[1] = op1.l_ui; a[2] = 0;
96284990Scy	b[0] = op2.l_uf; b[1] = op2.l_ui; b[2] = 0;
97284990Scy
98284990Scy	return cmp_work(a,b);
99284990Scy}
100284990Scy
101289999Sglebius// maybe rename it to lf_cmp_work
102289999Sglebiusint
103289999Sglebiuscmp_work(u_int32 a[3], u_int32 b[3])
104284990Scy{
105284990Scy	u_int32 cy, idx, tmp;
106284990Scy	for (cy = idx = 0; idx < 3; ++idx) {
107284990Scy		tmp = a[idx]; cy  = (a[idx] -=   cy  ) > tmp;
108284990Scy		tmp = a[idx]; cy |= (a[idx] -= b[idx]) > tmp;
109284990Scy	}
110284990Scy	if (a[2])
111284990Scy		return -1;
112284990Scy	return a[0] || a[1];
113284990Scy}
114284990Scy
115284990Scy
116284990Scy//----------------------------------------------------------------------
117284990Scy// imlementation of the LFP stuff
118284990Scy// This should be easy enough...
119284990Scy//----------------------------------------------------------------------
120284990Scy
121289999Sglebiusl_fp
122289999Sglebiusl_fp_init(int32 i, u_int32 f)
123284990Scy{
124284990Scy	l_fp temp;
125284990Scy	temp.l_i  = i;
126284990Scy	temp.l_uf = f;
127284990Scy
128284990Scy	return temp;
129284990Scy}
130284990Scy
131289999Sglebiusl_fp
132289999Sglebiusl_fp_add(const l_fp first, const l_fp second)
133284990Scy{
134289999Sglebius	l_fp temp = first;
135284990Scy	L_ADD(&temp, &second);
136289999Sglebius
137284990Scy	return temp;
138284990Scy}
139284990Scy
140289999Sglebiusl_fp
141289999Sglebiusl_fp_subtract(const l_fp first, const l_fp second)
142284990Scy{
143289999Sglebius	l_fp temp = first;
144284990Scy	L_SUB(&temp, &second);
145293893Sglebius
146284990Scy	return temp;
147284990Scy}
148284990Scy
149289999Sglebiusl_fp
150289999Sglebiusl_fp_negate(const l_fp first)
151284990Scy{
152289999Sglebius	l_fp temp = first;
153284990Scy	L_NEG(&temp);
154293893Sglebius
155284990Scy	return temp;
156284990Scy}
157284990Scy
158289999Sglebiusl_fp
159289999Sglebiusl_fp_abs(const l_fp first)
160284990Scy{
161284990Scy	l_fp temp = first;
162284990Scy	if (L_ISNEG(&temp))
163284990Scy		L_NEG(&temp);
164284990Scy	return temp;
165284990Scy}
166284990Scy
167289999Sglebiusint
168289999Sglebiusl_fp_signum(const l_fp first)
169284990Scy{
170284990Scy	if (first.l_ui & 0x80000000u)
171284990Scy		return -1;
172284990Scy	return (first.l_ui || first.l_uf);
173284990Scy}
174284990Scy
175289999Sglebiusdouble
176289999Sglebiusl_fp_convert_to_double(const l_fp first)
177284990Scy{
178284990Scy	double res;
179284990Scy	LFPTOD(&first, res);
180284990Scy	return res;
181284990Scy}
182284990Scy
183289999Sglebiusl_fp
184289999Sglebiusl_fp_init_from_double( double rhs)
185284990Scy{
186284990Scy	l_fp temp;
187284990Scy	DTOLFP(rhs, &temp);
188284990Scy	return temp;
189284990Scy}
190284990Scy
191289999Sglebiusvoid
192293893Sglebiusl_fp_swap(l_fp * first, l_fp *second)
193293893Sglebius{
194284990Scy	l_fp temp = *second;
195284990Scy
196284990Scy	*second = *first;
197284990Scy	*first = temp;
198293893Sglebius
199293893Sglebius	return;
200284990Scy}
201284990Scy
202289999Sglebius//----------------------------------------------------------------------
203289999Sglebius// testing the relational macros works better with proper predicate
204289999Sglebius// formatting functions; it slows down the tests a bit, but makes for
205289999Sglebius// readable failure messages.
206289999Sglebius//----------------------------------------------------------------------
207284990Scy
208289999Sglebius
209289999Sglebiusbool
210293893Sglebiusl_isgt (const l_fp first, const l_fp second)
211293893Sglebius{
212293893Sglebius
213289999Sglebius	return L_ISGT(&first, &second);
214284990Scy}
215284990Scy
216289999Sglebiusbool
217293893Sglebiusl_isgtu(const l_fp first, const l_fp second)
218293893Sglebius{
219293893Sglebius
220289999Sglebius	return L_ISGTU(&first, &second);
221289999Sglebius}
222284990Scy
223289999Sglebiusbool
224293893Sglebiusl_ishis(const l_fp first, const l_fp second)
225293893Sglebius{
226293893Sglebius
227289999Sglebius	return L_ISHIS(&first, &second);
228284990Scy}
229284990Scy
230289999Sglebiusbool
231293893Sglebiusl_isgeq(const l_fp first, const l_fp second)
232293893Sglebius{
233293893Sglebius
234289999Sglebius	return L_ISGEQ(&first, &second);
235284990Scy}
236284990Scy
237289999Sglebiusbool
238293893Sglebiusl_isequ(const l_fp first, const l_fp second)
239293893Sglebius{
240293893Sglebius
241289999Sglebius	return L_ISEQU(&first, &second);
242284990Scy}
243284990Scy
244284990Scy
245284990Scy//----------------------------------------------------------------------
246284990Scy// test data table for add/sub and compare
247284990Scy//----------------------------------------------------------------------
248284990Scy
249284990Scy
250284990Scystatic const lfp_hl addsub_tab[][3] = {
251284990Scy	// trivial idendity:
252284990Scy	{{0 ,0         }, { 0,0         }, { 0,0}},
253284990Scy	// with carry from fraction and sign change:
254284990Scy	{{-1,0x80000000}, { 0,0x80000000}, { 0,0}},
255284990Scy	// without carry from fraction
256284990Scy	{{ 1,0x40000000}, { 1,0x40000000}, { 2,0x80000000}},
257284990Scy	// with carry from fraction:
258284990Scy	{{ 1,0xC0000000}, { 1,0xC0000000}, { 3,0x80000000}},
259284990Scy	// with carry from fraction and sign change:
260284990Scy	{{0x7FFFFFFF, 0x7FFFFFFF}, {0x7FFFFFFF,0x7FFFFFFF}, {0xFFFFFFFE,0xFFFFFFFE}},
261284990Scy	// two tests w/o carry (used for l_fp<-->double):
262284990Scy	{{0x55555555,0xAAAAAAAA}, {0x11111111,0x11111111}, {0x66666666,0xBBBBBBBB}},
263284990Scy	{{0x55555555,0x55555555}, {0x11111111,0x11111111}, {0x66666666,0x66666666}},
264284990Scy	// wide-range test, triggers compare trouble
265284990Scy	{{0x80000000,0x00000001}, {0xFFFFFFFF,0xFFFFFFFE}, {0x7FFFFFFF,0xFFFFFFFF}}
266284990Scy};
267284990Scystatic const size_t addsub_cnt = (sizeof(addsub_tab)/sizeof(addsub_tab[0]));
268284990Scystatic const size_t addsub_tot = (sizeof(addsub_tab)/sizeof(addsub_tab[0][0]));
269284990Scy
270284990Scy
271284990Scy
272284990Scy//----------------------------------------------------------------------
273284990Scy// epsilon estimation for the precision of a conversion double --> l_fp
274284990Scy//
275284990Scy// The error estimation limit is as follows:
276284990Scy//  * The 'l_fp' fixed point fraction has 32 bits precision, so we allow
277284990Scy//    for the LSB to toggle by clamping the epsilon to be at least 2^(-31)
278284990Scy//
279284990Scy//  * The double mantissa has a precsion 54 bits, so the other minimum is
280284990Scy//    dval * (2^(-53))
281284990Scy//
282284990Scy//  The maximum of those two boundaries is used for the check.
283284990Scy//
284284990Scy// Note: once there are more than 54 bits between the highest and lowest
285284990Scy// '1'-bit of the l_fp value, the roundtrip *will* create truncation
286284990Scy// errors. This is an inherent property caused by the 54-bit mantissa of
287284990Scy// the 'double' type.
288289999Sglebiusdouble
289289999Sglebiuseps(double d)
290284990Scy{
291293893Sglebius
292289999Sglebius	return fmax(ldexp(1.0, -31), ldexp(fabs(d), -53));
293284990Scy}
294284990Scy
295284990Scy//----------------------------------------------------------------------
296284990Scy// test addition
297284990Scy//----------------------------------------------------------------------
298289999Sglebiusvoid
299293893Sglebiustest_AdditionLR(void)
300293893Sglebius{
301289999Sglebius	size_t idx = 0;
302293893Sglebius
303289999Sglebius	for (idx = 0; idx < addsub_cnt; ++idx) {
304284990Scy		l_fp op1 = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
305284990Scy		l_fp op2 = l_fp_init(addsub_tab[idx][1].h, addsub_tab[idx][1].l);
306293893Sglebius		l_fp e_res = l_fp_init(addsub_tab[idx][2].h, addsub_tab[idx][2].l);
307293893Sglebius		l_fp res = l_fp_add(op1, op2);
308284990Scy
309293893Sglebius		TEST_ASSERT_EQUAL_l_fp(e_res, res);
310293893Sglebius	}
311293893Sglebius	return;
312284990Scy}
313284990Scy
314289999Sglebiusvoid
315293893Sglebiustest_AdditionRL(void)
316293893Sglebius{
317289999Sglebius	size_t idx = 0;
318293893Sglebius
319289999Sglebius	for (idx = 0; idx < addsub_cnt; ++idx) {
320284990Scy		l_fp op2 = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
321284990Scy		l_fp op1 = l_fp_init(addsub_tab[idx][1].h, addsub_tab[idx][1].l);
322293893Sglebius		l_fp e_res = l_fp_init(addsub_tab[idx][2].h, addsub_tab[idx][2].l);
323289999Sglebius		l_fp res = l_fp_add(op1, op2);
324284990Scy
325293893Sglebius		TEST_ASSERT_EQUAL_l_fp(e_res, res);
326293893Sglebius	}
327293893Sglebius	return;
328284990Scy}
329284990Scy
330284990Scy
331284990Scy//----------------------------------------------------------------------
332284990Scy// test subtraction
333284990Scy//----------------------------------------------------------------------
334289999Sglebiusvoid
335293893Sglebiustest_SubtractionLR(void)
336293893Sglebius{
337289999Sglebius	size_t idx = 0;
338293893Sglebius
339289999Sglebius	for (idx = 0; idx < addsub_cnt; ++idx) {
340284990Scy		l_fp op2 = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
341293893Sglebius		l_fp e_res = l_fp_init(addsub_tab[idx][1].h, addsub_tab[idx][1].l);
342284990Scy		l_fp op1 = l_fp_init(addsub_tab[idx][2].h, addsub_tab[idx][2].l);
343289999Sglebius		l_fp res = l_fp_subtract(op1, op2);
344293893Sglebius
345293893Sglebius		TEST_ASSERT_EQUAL_l_fp(e_res, res);
346293893Sglebius	}
347293893Sglebius	return;
348284990Scy}
349284990Scy
350289999Sglebiusvoid
351293893Sglebiustest_SubtractionRL(void)
352293893Sglebius{
353289999Sglebius	size_t idx = 0;
354293893Sglebius
355289999Sglebius	for (idx = 0; idx < addsub_cnt; ++idx) {
356293893Sglebius		l_fp e_res = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
357284990Scy		l_fp op2 = l_fp_init(addsub_tab[idx][1].h, addsub_tab[idx][1].l);
358284990Scy		l_fp op1 = l_fp_init(addsub_tab[idx][2].h, addsub_tab[idx][2].l);
359289999Sglebius		l_fp res = l_fp_subtract(op1, op2);
360284990Scy
361293893Sglebius		TEST_ASSERT_EQUAL_l_fp(e_res, res);
362293893Sglebius	}
363293893Sglebius	return;
364284990Scy}
365284990Scy
366284990Scy//----------------------------------------------------------------------
367284990Scy// test negation
368284990Scy//----------------------------------------------------------------------
369284990Scy
370289999Sglebiusvoid
371293893Sglebiustest_Negation(void)
372293893Sglebius{
373293893Sglebius	size_t idx = 0;
374284990Scy
375289999Sglebius	for (idx = 0; idx < addsub_cnt; ++idx) {
376284990Scy		l_fp op1 = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
377284990Scy		l_fp op2 = l_fp_negate(op1);
378284990Scy		l_fp sum = l_fp_add(op1, op2);
379293893Sglebius
380289999Sglebius		l_fp zero = l_fp_init(0, 0);
381284990Scy
382289999Sglebius		TEST_ASSERT_EQUAL_l_fp(zero, sum);
383293893Sglebius	}
384293893Sglebius	return;
385284990Scy}
386284990Scy
387284990Scy
388284990Scy
389284990Scy//----------------------------------------------------------------------
390284990Scy// test absolute value
391284990Scy//----------------------------------------------------------------------
392289999Sglebiusvoid
393293893Sglebiustest_Absolute(void)
394293893Sglebius{
395289999Sglebius	size_t idx = 0;
396293893Sglebius
397289999Sglebius	for (idx = 0; idx < addsub_cnt; ++idx) {
398284990Scy		l_fp op1 = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
399284990Scy		l_fp op2 = l_fp_abs(op1);
400284990Scy
401293893Sglebius		TEST_ASSERT_TRUE(l_fp_signum(op2) >= 0);
402284990Scy
403284990Scy		if (l_fp_signum(op1) >= 0)
404293893Sglebius			op1 = l_fp_subtract(op1, op2);
405284990Scy		else
406289999Sglebius			op1 = l_fp_add(op1, op2);
407293893Sglebius
408289999Sglebius		l_fp zero = l_fp_init(0, 0);
409293893Sglebius
410289999Sglebius		TEST_ASSERT_EQUAL_l_fp(zero, op1);
411284990Scy	}
412284990Scy
413284990Scy	// There is one special case we have to check: the minimum
414284990Scy	// value cannot be negated, or, to be more precise, the
415284990Scy	// negation reproduces the original pattern.
416284990Scy	l_fp minVal = l_fp_init(0x80000000, 0x00000000);
417284990Scy	l_fp minAbs = l_fp_abs(minVal);
418284990Scy	TEST_ASSERT_EQUAL(-1, l_fp_signum(minVal));
419284990Scy
420289999Sglebius	TEST_ASSERT_EQUAL_l_fp(minVal, minAbs);
421293893Sglebius
422293893Sglebius	return;
423284990Scy}
424284990Scy
425284990Scy
426284990Scy//----------------------------------------------------------------------
427284990Scy// fp -> double -> fp rountrip test
428284990Scy//----------------------------------------------------------------------
429289999Sglebiusvoid
430293893Sglebiustest_FDF_RoundTrip(void)
431293893Sglebius{
432293893Sglebius	size_t idx = 0;
433293893Sglebius
434284990Scy	// since a l_fp has 64 bits in it's mantissa and a double has
435284990Scy	// only 54 bits available (including the hidden '1') we have to
436284990Scy	// make a few concessions on the roundtrip precision. The 'eps()'
437284990Scy	// function makes an educated guess about the avilable precision
438284990Scy	// and checks the difference in the two 'l_fp' values against
439284990Scy	// that limit.
440293893Sglebius
441289999Sglebius	for (idx = 0; idx < addsub_cnt; ++idx) {
442284990Scy		l_fp op1 = l_fp_init(addsub_tab[idx][0].h, addsub_tab[idx][0].l);
443284990Scy		double op2 = l_fp_convert_to_double(op1);
444284990Scy		l_fp op3 = l_fp_init_from_double(op2);
445284990Scy
446289999Sglebius		l_fp temp = l_fp_subtract(op1, op3);
447284990Scy		double d = l_fp_convert_to_double(temp);
448293893Sglebius		TEST_ASSERT_DOUBLE_WITHIN(eps(op2), 0.0, fabs(d));
449293893Sglebius	}
450293893Sglebius
451293893Sglebius	return;
452284990Scy}
453284990Scy
454284990Scy
455284990Scy//----------------------------------------------------------------------
456284990Scy// test the compare stuff
457284990Scy//
458284990Scy// This uses the local compare and checks if the operations using the
459284990Scy// macros in 'ntp_fp.h' produce mathing results.
460284990Scy// ----------------------------------------------------------------------
461289999Sglebiusvoid
462293893Sglebiustest_SignedRelOps(void)
463293893Sglebius{
464284990Scy	const lfp_hl * tv = (&addsub_tab[0][0]);
465284990Scy	size_t lc ;
466293893Sglebius
467289999Sglebius	for (lc = addsub_tot - 1; lc; --lc, ++tv) {
468289999Sglebius		l_fp op1 = l_fp_init(tv[0].h, tv[0].l);
469289999Sglebius		l_fp op2 = l_fp_init(tv[1].h, tv[1].l);
470293893Sglebius		int cmp = l_fp_scmp(op1, op2);
471293893Sglebius
472284990Scy		switch (cmp) {
473284990Scy		case -1:
474284990Scy			//printf("op1:%d %d, op2:%d %d\n",op1.l_uf,op1.l_ui,op2.l_uf,op2.l_ui);
475289999Sglebius			l_fp_swap(&op1, &op2);
476284990Scy			//printf("op1:%d %d, op2:%d %d\n",op1.l_uf,op1.l_ui,op2.l_uf,op2.l_ui);
477284990Scy		case 1:
478289999Sglebius			TEST_ASSERT_TRUE (l_isgt(op1, op2));
479289999Sglebius			TEST_ASSERT_FALSE(l_isgt(op2, op1));
480284990Scy
481289999Sglebius			TEST_ASSERT_TRUE (l_isgeq(op1, op2));
482289999Sglebius			TEST_ASSERT_FALSE(l_isgeq(op2, op1));
483284990Scy
484289999Sglebius			TEST_ASSERT_FALSE(l_isequ(op1, op2));
485289999Sglebius			TEST_ASSERT_FALSE(l_isequ(op2, op1));
486284990Scy			break;
487284990Scy		case 0:
488289999Sglebius			TEST_ASSERT_FALSE(l_isgt(op1, op2));
489289999Sglebius			TEST_ASSERT_FALSE(l_isgt(op2, op1));
490284990Scy
491289999Sglebius			TEST_ASSERT_TRUE (l_isgeq(op1, op2));
492289999Sglebius			TEST_ASSERT_TRUE (l_isgeq(op2, op1));
493284990Scy
494289999Sglebius			TEST_ASSERT_TRUE (l_isequ(op1, op2));
495289999Sglebius			TEST_ASSERT_TRUE (l_isequ(op2, op1));
496284990Scy			break;
497284990Scy		default:
498293893Sglebius			TEST_FAIL_MESSAGE("unexpected UCMP result: ");
499284990Scy		}
500284990Scy	}
501293893Sglebius
502293893Sglebius	return;
503284990Scy}
504284990Scy
505289999Sglebiusvoid
506293893Sglebiustest_UnsignedRelOps(void)
507293893Sglebius{
508293893Sglebius	const lfp_hl * tv =(&addsub_tab[0][0]);
509284990Scy	size_t lc;
510293893Sglebius
511289999Sglebius	for (lc = addsub_tot - 1; lc; --lc, ++tv) {
512289999Sglebius		l_fp op1 = l_fp_init(tv[0].h, tv[0].l);
513289999Sglebius		l_fp op2 = l_fp_init(tv[1].h, tv[1].l);
514289999Sglebius		int cmp = l_fp_ucmp(op1, op2);
515284990Scy
516284990Scy		switch (cmp) {
517284990Scy		case -1:
518284990Scy			//printf("op1:%d %d, op2:%d %d\n",op1.l_uf,op1.l_ui,op2.l_uf,op2.l_ui);
519284990Scy			l_fp_swap(&op1, &op2);
520284990Scy			//printf("op1:%d %d, op2:%d %d\n",op1.l_uf,op1.l_ui,op2.l_uf,op2.l_ui);
521284990Scy		case 1:
522289999Sglebius			TEST_ASSERT_TRUE (l_isgtu(op1, op2));
523289999Sglebius			TEST_ASSERT_FALSE(l_isgtu(op2, op1));
524284990Scy
525289999Sglebius			TEST_ASSERT_TRUE (l_ishis(op1, op2));
526289999Sglebius			TEST_ASSERT_FALSE(l_ishis(op2, op1));
527284990Scy			break;
528284990Scy		case 0:
529289999Sglebius			TEST_ASSERT_FALSE(l_isgtu(op1, op2));
530289999Sglebius			TEST_ASSERT_FALSE(l_isgtu(op2, op1));
531284990Scy
532289999Sglebius			TEST_ASSERT_TRUE (l_ishis(op1, op2));
533289999Sglebius			TEST_ASSERT_TRUE (l_ishis(op2, op1));
534284990Scy			break;
535284990Scy		default:
536293893Sglebius			TEST_FAIL_MESSAGE("unexpected UCMP result: ");
537284990Scy		}
538284990Scy	}
539293893Sglebius
540293893Sglebius	return;
541284990Scy}
542293893Sglebius
543284990Scy/*
544284990Scy*/
545284990Scy
546284990Scy//----------------------------------------------------------------------
547284990Scy// that's all folks... but feel free to add things!
548284990Scy//----------------------------------------------------------------------
549