xref: /freebsd/tests/sys/sys/qmath_test.c (revision b3e76948)
1 /*-
2  * Copyright (c) 2018 Netflix, Inc.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 /*
28  * Author: Lawrence Stewart <lstewart@netflix.com>
29  */
30 
31 #include <sys/param.h>
32 #include <sys/qmath.h>
33 
34 #include <errno.h>
35 #include <math.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 
39 #include <atf-c.h>
40 
41 #define	QTEST_IV 3
42 #define	QTEST_IVSTR "3.00"
43 #define	QTEST_RPSHFT 2
44 #define	QTEST_INTBITS(q) (Q_NTBITS(q) - Q_SIGNED(q) - Q_NFBITS(q) - Q_NCBITS)
45 #define	QTEST_QITRUNC(q, iv) ((iv) >> Q_RPSHFT(q))
46 #define	QTEST_FFACTOR 32.0
47 
48 #define	bitsperrand 31
49 #define	GENRAND(a, lb, ub)						\
50 ({									\
51 	int _rembits;							\
52 	do {								\
53 		_rembits = Q_BITSPERBASEUP(ub) + Q_LTZ(lb);		\
54 		*(a) = (__typeof(*(a)))0;				\
55 		while (_rembits > 0) {					\
56 			*(a) |= (((uint64_t)random()) &			\
57 			    ((1ULL << (_rembits > bitsperrand ?		\
58 			    bitsperrand : _rembits)) - 1));		\
59 			*(a) <<= (_rembits - (_rembits > bitsperrand ?	\
60 			    bitsperrand : _rembits));			\
61 			_rembits -= bitsperrand;			\
62 		}							\
63 		*(a) += lb;						\
64 	} while (*(a) < (lb) || (uint64_t)*(a) > (ub));			\
65 	*(a);								\
66 })
67 
68 /*
69  * Smoke tests for basic qmath operations, such as initialization
70  * or string formatting.
71  */
72 ATF_TC_WITHOUT_HEAD(basic_s8q);
ATF_TC_BODY(basic_s8q,tc)73 ATF_TC_BODY(basic_s8q, tc)
74 {
75 	char buf[128];
76 	s8q_t s8;
77 
78 	Q_INI(&s8, QTEST_IV, 0, QTEST_RPSHFT);
79 	Q_TOSTR(s8, -1, 10, buf, sizeof(buf));
80 	ATF_CHECK_STREQ(QTEST_IVSTR, buf);
81 	ATF_CHECK_EQ(sizeof(s8) << 3, Q_NTBITS(s8));
82 	ATF_CHECK_EQ(QTEST_RPSHFT, Q_NFBITS(s8));
83 	ATF_CHECK_EQ(QTEST_INTBITS(s8), Q_NIBITS(s8));
84 	ATF_CHECK_EQ(QTEST_QITRUNC(s8, INT8_MAX), Q_IMAXVAL(s8));
85 	ATF_CHECK_EQ(-Q_IMAXVAL(s8), Q_IMINVAL(s8));
86 }
87 
88 ATF_TC_WITHOUT_HEAD(basic_s16q);
ATF_TC_BODY(basic_s16q,tc)89 ATF_TC_BODY(basic_s16q, tc)
90 {
91 	char buf[128];
92 	s16q_t s16;
93 
94 	Q_INI(&s16, QTEST_IV, 0, QTEST_RPSHFT);
95 	Q_TOSTR(s16, -1, 10, buf, sizeof(buf));
96 	ATF_CHECK_STREQ(QTEST_IVSTR, buf);
97 	ATF_CHECK_EQ(sizeof(s16) << 3, Q_NTBITS(s16));
98 	ATF_CHECK_EQ(QTEST_RPSHFT, Q_NFBITS(s16));
99 	ATF_CHECK_EQ(QTEST_INTBITS(s16), Q_NIBITS(s16));
100 	ATF_CHECK_EQ(QTEST_QITRUNC(s16, INT16_MAX), Q_IMAXVAL(s16));
101 	ATF_CHECK_EQ(-Q_IMAXVAL(s16), Q_IMINVAL(s16));
102 }
103 
104 ATF_TC_WITHOUT_HEAD(basic_s32q);
ATF_TC_BODY(basic_s32q,tc)105 ATF_TC_BODY(basic_s32q, tc)
106 {
107 	char buf[128];
108 	s32q_t s32;
109 
110 	Q_INI(&s32, QTEST_IV, 0, QTEST_RPSHFT);
111 	Q_TOSTR(s32, -1, 10, buf, sizeof(buf));
112 	ATF_CHECK_STREQ(QTEST_IVSTR, buf);
113 	ATF_CHECK_EQ(sizeof(s32) << 3, Q_NTBITS(s32));
114 	ATF_CHECK_EQ(QTEST_RPSHFT, Q_NFBITS(s32));
115 	ATF_CHECK_EQ(QTEST_INTBITS(s32), Q_NIBITS(s32));
116 	ATF_CHECK_EQ(QTEST_QITRUNC(s32, INT32_MAX), Q_IMAXVAL(s32));
117 	ATF_CHECK_EQ(-Q_IMAXVAL(s32), Q_IMINVAL(s32));
118 }
119 
120 ATF_TC_WITHOUT_HEAD(basic_s64q);
ATF_TC_BODY(basic_s64q,tc)121 ATF_TC_BODY(basic_s64q, tc)
122 {
123 	char buf[128];
124 	s64q_t s64;
125 
126 	Q_INI(&s64, QTEST_IV, 0, QTEST_RPSHFT);
127 	Q_TOSTR(s64, -1, 10, buf, sizeof(buf));
128 	ATF_CHECK_STREQ(QTEST_IVSTR, buf);
129 	ATF_CHECK_EQ(sizeof(s64) << 3, Q_NTBITS(s64));
130 	ATF_CHECK_EQ(QTEST_RPSHFT, Q_NFBITS(s64));
131 	ATF_CHECK_EQ(QTEST_INTBITS(s64), Q_NIBITS(s64));
132 	ATF_CHECK_EQ(QTEST_QITRUNC(s64, INT64_MAX), Q_IMAXVAL(s64));
133 	ATF_CHECK_EQ(-Q_IMAXVAL(s64), Q_IMINVAL(s64));
134 }
135 
136 ATF_TC_WITHOUT_HEAD(basic_u8q);
ATF_TC_BODY(basic_u8q,tc)137 ATF_TC_BODY(basic_u8q, tc)
138 {
139 	char buf[128];
140 	u8q_t u8;
141 
142 	Q_INI(&u8, QTEST_IV, 0, QTEST_RPSHFT);
143 	Q_TOSTR(u8, -1, 10, buf, sizeof(buf));
144 	ATF_CHECK_STREQ(QTEST_IVSTR, buf);
145 	ATF_CHECK_EQ(sizeof(u8) << 3, Q_NTBITS(u8));
146 	ATF_CHECK_EQ(QTEST_RPSHFT, Q_NFBITS(u8));
147 	ATF_CHECK_EQ(QTEST_INTBITS(u8), Q_NIBITS(u8));
148 	ATF_CHECK_EQ(QTEST_QITRUNC(u8, UINT8_MAX), Q_IMAXVAL(u8));
149 	ATF_CHECK_EQ(0, Q_IMINVAL(u8));
150 }
151 
152 ATF_TC_WITHOUT_HEAD(basic_u16q);
ATF_TC_BODY(basic_u16q,tc)153 ATF_TC_BODY(basic_u16q, tc)
154 {
155 	char buf[128];
156 	u16q_t u16;
157 
158 	Q_INI(&u16, QTEST_IV, 0, QTEST_RPSHFT);
159 	Q_TOSTR(u16, -1, 10, buf, sizeof(buf));
160 	ATF_CHECK_STREQ(QTEST_IVSTR, buf);
161 	ATF_CHECK_EQ(sizeof(u16) << 3, Q_NTBITS(u16));
162 	ATF_CHECK_EQ(QTEST_RPSHFT, Q_NFBITS(u16));
163 	ATF_CHECK_EQ(QTEST_INTBITS(u16), Q_NIBITS(u16));
164 	ATF_CHECK_EQ(QTEST_QITRUNC(u16, UINT16_MAX), Q_IMAXVAL(u16));
165 	ATF_CHECK_EQ(0, Q_IMINVAL(u16));
166 }
167 
168 ATF_TC_WITHOUT_HEAD(basic_u32q);
ATF_TC_BODY(basic_u32q,tc)169 ATF_TC_BODY(basic_u32q, tc)
170 {
171 	char buf[128];
172 	u32q_t u32;
173 
174 	Q_INI(&u32, QTEST_IV, 0, QTEST_RPSHFT);
175 	Q_TOSTR(u32, -1, 10, buf, sizeof(buf));
176 	ATF_CHECK_STREQ(QTEST_IVSTR, buf);
177 	ATF_CHECK_EQ(sizeof(u32) << 3, Q_NTBITS(u32));
178 	ATF_CHECK_EQ(QTEST_RPSHFT, Q_NFBITS(u32));
179 	ATF_CHECK_EQ(QTEST_INTBITS(u32), Q_NIBITS(u32));
180 	ATF_CHECK_EQ(QTEST_QITRUNC(u32, UINT32_MAX), Q_IMAXVAL(u32));
181 	ATF_CHECK_EQ(0, Q_IMINVAL(u32));
182 }
183 
184 ATF_TC_WITHOUT_HEAD(basic_u64q);
ATF_TC_BODY(basic_u64q,tc)185 ATF_TC_BODY(basic_u64q, tc)
186 {
187 	char buf[128];
188 	u64q_t u64;
189 
190 	Q_INI(&u64, QTEST_IV, 0, QTEST_RPSHFT);
191 	Q_TOSTR(u64, -1, 10, buf, sizeof(buf));
192 	ATF_CHECK_STREQ(QTEST_IVSTR, buf);
193 	ATF_CHECK_EQ(sizeof(u64) << 3, Q_NTBITS(u64));
194 	ATF_CHECK_EQ(QTEST_RPSHFT, Q_NFBITS(u64));
195 	ATF_CHECK_EQ(QTEST_INTBITS(u64), Q_NIBITS(u64));
196 	ATF_CHECK_EQ(QTEST_QITRUNC(u64, UINT64_MAX), Q_IMAXVAL(u64));
197 	ATF_CHECK_EQ(0, Q_IMINVAL(u64));
198 }
199 
200 /*
201  * Test Q_QMULQ(3) by applying it to two random Q numbers and comparing
202  * the result with its floating-point counterpart.
203  */
204 ATF_TC_WITHOUT_HEAD(qmulq_s64q);
ATF_TC_BODY(qmulq_s64q,tc)205 ATF_TC_BODY(qmulq_s64q, tc)
206 {
207 	s64q_t a_s64q, b_s64q, r_s64q;
208 	double a_dbl, b_dbl, r_dbl, maxe_dbl, delta_dbl;
209 #ifdef notyet
210 	int64_t a_int, b_int;
211 #endif
212 	int error;
213 
214 	srandomdev();
215 
216 	for (int i = 0; i < 10;) {
217 		GENRAND(&a_s64q, INT64_MIN, UINT64_MAX);
218 		GENRAND(&b_s64q, INT64_MIN, UINT64_MAX);
219 
220 		/*
221 		 * XXX: We cheat a bit, to stand any chance of multiplying
222 		 * 	without overflow.
223 		 */
224 		error = Q_QDIVQ(&a_s64q, b_s64q);
225 		if (error == EOVERFLOW || error == ERANGE)
226 			continue;
227 		ATF_CHECK_EQ(0, error);
228 
229 		/*
230 		 * XXXLAS: Until Qmath handles precision normalisation, only
231 		 * test with equal precision.
232 		 */
233 		Q_SCVAL(b_s64q, Q_GCVAL(a_s64q));
234 
235 		/* Q<op>Q testing. */
236 		a_dbl = Q_Q2D(a_s64q);
237 		b_dbl = Q_Q2D(b_s64q);
238 
239 		r_s64q = a_s64q;
240 		error = Q_QMULQ(&r_s64q, b_s64q);
241 		if (error == EOVERFLOW || error == ERANGE)
242 			continue;
243 		i++;
244 		ATF_CHECK_EQ(0, error);
245 
246 		r_dbl = a_dbl * b_dbl;
247 #ifdef notyet
248 		a_int = Q_GIVAL(a_s64q);
249 		b_int = Q_GIVAL(b_s64q);
250 
251 		maxe_dbl = fabs(((1.0 / Q_NFBITS(a_s64q)) * (double)b_int) +
252 		    ((1.0 / Q_NFBITS(b_s64q)) * (double)a_int));
253 #else
254 		maxe_dbl = QTEST_FFACTOR;
255 #endif
256 		delta_dbl = fabs(r_dbl - Q_Q2D(r_s64q));
257 		ATF_CHECK_MSG(delta_dbl <= maxe_dbl,
258 		    "\tQMULQ(%10f * %10f): |%10f - %10f| = %10f "
259 		    "(max err %f)\n",
260 		    Q_Q2D(a_s64q), Q_Q2D(b_s64q), Q_Q2D(r_s64q), r_dbl,
261 		    delta_dbl, maxe_dbl);
262 	}
263 }
264 
265 /*
266  * Test Q_QDIVQ(3) by applying it to two random Q numbers and comparing
267  * the result with its floating-point counterpart.
268  */
269 ATF_TC_WITHOUT_HEAD(qdivq_s64q);
ATF_TC_BODY(qdivq_s64q,tc)270 ATF_TC_BODY(qdivq_s64q, tc)
271 {
272 	s64q_t a_s64q, b_s64q, r_s64q;
273 	double a_dbl, b_dbl, r_dbl, maxe_dbl, delta_dbl;
274 	int error;
275 
276 	if (atf_tc_get_config_var_as_bool_wd(tc, "ci", false))
277 		atf_tc_skip("https://bugs.freebsd.org/240219");
278 
279 
280 	srandomdev();
281 
282 	for (int i = 0; i < 10; i++) {
283 		GENRAND(&a_s64q, INT64_MIN, UINT64_MAX);
284 		GENRAND(&b_s64q, INT64_MIN, UINT64_MAX);
285 		/*
286 		 * XXXLAS: Until Qmath handles precision normalisation, only
287 		 * test with equal precision.
288 		 */
289 		Q_SCVAL(b_s64q, Q_GCVAL(a_s64q));
290 
291 		/* Q<op>Q testing. */
292 		a_dbl = Q_Q2D(a_s64q);
293 		b_dbl = Q_Q2D(b_s64q);
294 
295 		r_s64q = a_s64q;
296 		error = Q_QDIVQ(&r_s64q, b_s64q);
297 		ATF_CHECK_EQ(0, error);
298 
299 		r_dbl = a_dbl / b_dbl;
300 #ifdef notyet
301 		maxe_dbl = fabs(1.0 / (1ULL << Q_NFBITS(a_s64q)));
302 #else
303 		maxe_dbl = QTEST_FFACTOR * 2;
304 #endif
305 		delta_dbl = fabs(r_dbl - Q_Q2D(r_s64q));
306 		ATF_CHECK_MSG(delta_dbl <= maxe_dbl,
307 		    "\tQDIVQ(%10f / %10f): |%10f - %10f| = %10f "
308 		    "(max err %f)\n",
309 		    Q_Q2D(a_s64q), Q_Q2D(b_s64q), Q_Q2D(r_s64q), r_dbl,
310 		    delta_dbl, maxe_dbl);
311 	}
312 }
313 
314 /*
315  * Test Q_QADDQ(3) by applying it to two random Q numbers and comparing
316  * the result with its floating-point counterpart.
317  */
318 ATF_TC_WITHOUT_HEAD(qaddq_s64q);
ATF_TC_BODY(qaddq_s64q,tc)319 ATF_TC_BODY(qaddq_s64q, tc)
320 {
321 	s64q_t a_s64q, b_s64q, r_s64q;
322 	double a_dbl, b_dbl, r_dbl, maxe_dbl, delta_dbl;
323 	int error;
324 
325 	srandomdev();
326 
327 	for (int i = 0; i < 10;) {
328 		GENRAND(&a_s64q, INT64_MIN, UINT64_MAX);
329 		GENRAND(&b_s64q, INT64_MIN, UINT64_MAX);
330 		/*
331 		 * XXXLAS: Until Qmath handles precision normalisation, only
332 		 * test with equal precision.
333 		 */
334 		Q_SCVAL(b_s64q, Q_GCVAL(a_s64q));
335 
336 		/* Q<op>Q testing. */
337 		a_dbl = Q_Q2D(a_s64q);
338 		b_dbl = Q_Q2D(b_s64q);
339 
340 		r_s64q = a_s64q;
341 		error = Q_QADDQ(&r_s64q, b_s64q);
342 		if (error == EOVERFLOW || error == ERANGE)
343 			continue;
344 		i++;
345 		ATF_CHECK_EQ(0, error);
346 
347 		r_dbl = a_dbl + b_dbl;
348 #ifdef notyet
349 		maxe_dbl = 0.5;
350 #else
351 		maxe_dbl = QTEST_FFACTOR;
352 #endif
353 		delta_dbl = fabs(r_dbl - Q_Q2D(r_s64q));
354 		ATF_CHECK_MSG(delta_dbl <= maxe_dbl,
355 		    "\tQADDQ(%10f + %10f): |%10f - %10f| = %10f "
356 		    "(max err %f)\n",
357 		    Q_Q2D(a_s64q), Q_Q2D(b_s64q), Q_Q2D(r_s64q), r_dbl,
358 		    delta_dbl, maxe_dbl);
359 	}
360 }
361 
362 /*
363  * Test Q_QSUBQ(3) by applying it to two random Q numbers and comparing
364  * the result with its floating-point counterpart.
365  */
366 ATF_TC_WITHOUT_HEAD(qsubq_s64q);
ATF_TC_BODY(qsubq_s64q,tc)367 ATF_TC_BODY(qsubq_s64q, tc)
368 {
369 	s64q_t a_s64q, b_s64q, r_s64q;
370 	double a_dbl, b_dbl, r_dbl, maxe_dbl, delta_dbl;
371 	int error;
372 
373 	srandomdev();
374 
375 	for (int i = 0; i < 10; i++) {
376 		GENRAND(&a_s64q, INT64_MIN, UINT64_MAX);
377 		GENRAND(&b_s64q, INT64_MIN, UINT64_MAX);
378 		/*
379 		 * XXXLAS: Until Qmath handles precision normalisation, only
380 		 * test with equal precision.
381 		 */
382 		Q_SCVAL(b_s64q, Q_GCVAL(a_s64q));
383 
384 		/* Q<op>Q testing. */
385 		a_dbl = Q_Q2D(a_s64q);
386 		b_dbl = Q_Q2D(b_s64q);
387 
388 		r_s64q = a_s64q;
389 		error = Q_QSUBQ(&r_s64q, b_s64q);
390 		ATF_CHECK_EQ(0, error);
391 
392 		r_dbl = a_dbl - b_dbl;
393 #ifdef notyet
394 		maxe_dbl = 0.5;
395 #else
396 		maxe_dbl = QTEST_FFACTOR;
397 #endif
398 		delta_dbl = fabs(r_dbl - Q_Q2D(r_s64q));
399 		ATF_CHECK_MSG(delta_dbl <= maxe_dbl,
400 		    "\tQSUBQ(%10f - %10f): |%10f - %10f| = %10f "
401 		    "(max err %f)\n",
402 		    Q_Q2D(a_s64q), Q_Q2D(b_s64q), Q_Q2D(r_s64q), r_dbl,
403 		    delta_dbl, maxe_dbl);
404 	}
405 }
406 
407 /*
408  * Test Q_QFRACI(3) by applying it to two random integers and comparing
409  * the result with its floating-point counterpart.
410  */
411 ATF_TC_WITHOUT_HEAD(qfraci_s64q);
ATF_TC_BODY(qfraci_s64q,tc)412 ATF_TC_BODY(qfraci_s64q, tc)
413 {
414 	s64q_t a_s64q, b_s64q, r_s64q;
415 	double a_dbl, b_dbl, r_dbl, maxe_dbl, delta_dbl;
416 	int64_t a_int, b_int;
417 	int error;
418 
419 	srandomdev();
420 
421 	for (int i = 0; i < 10;) {
422 		GENRAND(&a_s64q, INT64_MIN, UINT64_MAX);
423 		GENRAND(&b_s64q, INT64_MIN, UINT64_MAX);
424 		/*
425 		 * XXXLAS: Until Qmath handles precision normalisation, only
426 		 * test with equal precision.
427 		 */
428 		Q_SCVAL(b_s64q, Q_GCVAL(a_s64q));
429 		a_int = Q_GIVAL(a_s64q);
430 		b_int = Q_GIVAL(b_s64q);
431 
432 		/* Q<op>I testing. */
433 		a_dbl = a_int;
434 		b_dbl = b_int;
435 
436 		Q_INI(&r_s64q, 0, 0, Q_NFBITS(a_s64q));
437 		error = Q_QFRACI(&r_s64q, a_int, b_int);
438 		if (error == EOVERFLOW || error == ERANGE || error == EINVAL)
439 			continue;
440 		i++;
441 		ATF_CHECK_EQ(0, error);
442 
443 		r_dbl = a_dbl / b_dbl;
444 		maxe_dbl = fabs(1.0 / Q_NFBITS(a_s64q));
445 		delta_dbl = fabs(r_dbl - Q_Q2D(r_s64q));
446 		ATF_CHECK_MSG(delta_dbl <= maxe_dbl,
447 		    "\tQFRACI(%jd / %jd): |%10f - %10f| = %10f "
448 		    "(max err %f)\n",
449 		    (intmax_t)a_int, (intmax_t)b_int, Q_Q2D(r_s64q),
450 		    r_dbl, delta_dbl, maxe_dbl);
451 	}
452 }
453 
454 /*
455  * Test Q_QMULI(3) by applying it to a random Q number and a random integer
456  * and comparing the result with its floating-point counterpart.
457  */
458 ATF_TC_WITHOUT_HEAD(qmuli_s64q);
ATF_TC_BODY(qmuli_s64q,tc)459 ATF_TC_BODY(qmuli_s64q, tc)
460 {
461 	s64q_t a_s64q, b_s64q, r_s64q;
462 	double a_dbl, b_dbl, r_dbl, maxe_dbl, delta_dbl;
463 	int64_t a_int, b_int;
464 	int error;
465 
466 	srandomdev();
467 
468 	for (int i = 0; i < 10;) {
469 		GENRAND(&a_s64q, INT64_MIN, UINT64_MAX);
470 		GENRAND(&b_s64q, INT64_MIN, UINT64_MAX);
471 		/*
472 		 * XXXLAS: Until Qmath handles precision normalisation, only
473 		 * test with equal precision.
474 		 */
475 		Q_SCVAL(b_s64q, Q_GCVAL(a_s64q));
476 		a_int = Q_GIVAL(a_s64q);
477 		b_int = Q_GIVAL(b_s64q);
478 
479 		/* Q<op>I testing. */
480 		a_dbl = a_int;
481 		b_dbl = b_int;
482 
483 		Q_INI(&r_s64q, a_int, 0, Q_NFBITS(a_s64q));
484 		error = Q_QMULI(&r_s64q, b_int);
485 		if (error == EOVERFLOW || error == ERANGE)
486 			continue;
487 		i++;
488 		ATF_CHECK_EQ(0, error);
489 
490 		r_dbl = a_dbl * b_dbl;
491 		maxe_dbl = fabs((1.0 / Q_NFBITS(a_s64q)) * (double)b_int);
492 		delta_dbl = fabs(r_dbl - Q_Q2D(r_s64q));
493 		ATF_CHECK_MSG(delta_dbl <= maxe_dbl,
494 		    "\tQMULI(%jd * %jd): |%10f - %10f| = %10f "
495 		    "(max err %f)\n",
496 		    (intmax_t)(intmax_t)a_int, b_int, Q_Q2D(r_s64q),
497 		    r_dbl, delta_dbl, maxe_dbl);
498 	}
499 }
500 
501 /*
502  * Test Q_QADDI(3) by applying it to a random Q number and a random integer
503  * and comparing the result with its floating-point counterpart.
504  */
505 ATF_TC_WITHOUT_HEAD(qaddi_s64q);
ATF_TC_BODY(qaddi_s64q,tc)506 ATF_TC_BODY(qaddi_s64q, tc)
507 {
508 	s64q_t a_s64q, b_s64q, r_s64q;
509 	double a_dbl, b_dbl, r_dbl, maxe_dbl, delta_dbl;
510 	int64_t a_int, b_int;
511 	int error;
512 
513 	srandomdev();
514 
515 	for (int i = 0; i < 10;) {
516 		GENRAND(&a_s64q, INT64_MIN, UINT64_MAX);
517 		GENRAND(&b_s64q, INT64_MIN, UINT64_MAX);
518 		/*
519 		 * XXXLAS: Until Qmath handles precision normalisation, only
520 		 * test with equal precision.
521 		 */
522 		Q_SCVAL(b_s64q, Q_GCVAL(a_s64q));
523 		a_int = Q_GIVAL(a_s64q);
524 		b_int = Q_GIVAL(b_s64q);
525 
526 		/* Q<op>I testing. */
527 		a_dbl = a_int;
528 		b_dbl = b_int;
529 
530 		Q_INI(&r_s64q, a_int, 0, Q_NFBITS(a_s64q));
531 		error = Q_QADDI(&r_s64q, b_int);
532 		if (error == EOVERFLOW || error == ERANGE)
533 			continue;
534 		i++;
535 		ATF_CHECK_EQ(0, error);
536 
537 		r_dbl = a_dbl + b_dbl;
538 #ifdef notyet
539 		maxe_dbl = 0.5;
540 #else
541 		maxe_dbl = QTEST_FFACTOR;
542 #endif
543 		delta_dbl = fabs(r_dbl - Q_Q2D(r_s64q));
544 		ATF_CHECK_MSG(delta_dbl <= maxe_dbl,
545 		    "\tQADDI(%jd + %jd): |%10f - %10f| = %10f "
546 		    "(max err %f)\n",
547 		    (intmax_t)a_int, (intmax_t)b_int, Q_Q2D(r_s64q),
548 		    r_dbl, delta_dbl, maxe_dbl);
549 	}
550 }
551 
552 /*
553  * Test Q_QSUBI(3) by applying it to a random Q number and a random integer
554  * and comparing the result with its floating-point counterpart.
555  */
556 ATF_TC_WITHOUT_HEAD(qsubi_s64q);
ATF_TC_BODY(qsubi_s64q,tc)557 ATF_TC_BODY(qsubi_s64q, tc)
558 {
559 	s64q_t a_s64q, b_s64q, r_s64q;
560 	double a_dbl, b_dbl, r_dbl, maxe_dbl, delta_dbl;
561 	int64_t a_int, b_int;
562 	int error;
563 
564 	srandomdev();
565 
566 	for (int i = 0; i < 10; i++) {
567 		GENRAND(&a_s64q, INT64_MIN, UINT64_MAX);
568 		GENRAND(&b_s64q, INT64_MIN, UINT64_MAX);
569 		/*
570 		 * XXXLAS: Until Qmath handles precision normalisation, only
571 		 * test with equal precision.
572 		 */
573 		Q_SCVAL(b_s64q, Q_GCVAL(a_s64q));
574 		a_int = Q_GIVAL(a_s64q);
575 		b_int = Q_GIVAL(b_s64q);
576 
577 		/* Q<op>I testing. */
578 		a_dbl = a_int;
579 		b_dbl = b_int;
580 
581 		Q_INI(&r_s64q, a_int, 0, Q_NFBITS(a_s64q));
582 		error = Q_QSUBI(&r_s64q, b_int);
583 		ATF_CHECK_EQ(0, error);
584 
585 		r_dbl = a_dbl - b_dbl;
586 #ifdef notyet
587 		maxe_dbl = 0.5;
588 #else
589 		maxe_dbl = QTEST_FFACTOR;
590 #endif
591 		delta_dbl = fabs(r_dbl - Q_Q2D(r_s64q));
592 		ATF_CHECK_MSG(delta_dbl <= maxe_dbl,
593 		    "\tQSUBI(%jd - %jd): |%10f - %10f| = %10f "
594 		    "(max err %f)\n",
595 		    (intmax_t)a_int, (intmax_t)b_int, Q_Q2D(r_s64q),
596 		    r_dbl, delta_dbl, maxe_dbl);
597 	}
598 }
599 
600 /*
601  * Calculate area of a circle with r=42.
602  */
603 ATF_TC_WITHOUT_HEAD(circle_u64q);
ATF_TC_BODY(circle_u64q,tc)604 ATF_TC_BODY(circle_u64q, tc)
605 {
606 	char buf[128];
607 	u64q_t a, pi, r;
608 	int error;
609 
610 	Q_INI(&a, 0, 0, 16);
611 	Q_INI(&pi, 3, 14159, 16);
612 	Q_INI(&r, 4, 2, 16);
613 
614 	error = Q_QCLONEQ(&a, r);
615 	ATF_CHECK_EQ(0, error);
616 	error = Q_QMULQ(&a, r);
617 	ATF_CHECK_EQ(0, error);
618 	error = Q_QMULQ(&a, pi);
619 	ATF_CHECK_EQ(0, error);
620 
621 	Q_TOSTR(a, -1, 10, buf, sizeof(buf));
622 	ATF_CHECK_STREQ("55.4174804687500000", buf);
623 }
624 
ATF_TP_ADD_TCS(tp)625 ATF_TP_ADD_TCS(tp)
626 {
627 
628 	ATF_TP_ADD_TC(tp, basic_s8q);
629 	ATF_TP_ADD_TC(tp, basic_s16q);
630 	ATF_TP_ADD_TC(tp, basic_s32q);
631 	ATF_TP_ADD_TC(tp, basic_s64q);
632 	ATF_TP_ADD_TC(tp, basic_u8q);
633 	ATF_TP_ADD_TC(tp, basic_u16q);
634 	ATF_TP_ADD_TC(tp, basic_u32q);
635 	ATF_TP_ADD_TC(tp, basic_u64q);
636 
637 	ATF_TP_ADD_TC(tp, qmulq_s64q);
638 	ATF_TP_ADD_TC(tp, qdivq_s64q);
639 	ATF_TP_ADD_TC(tp, qaddq_s64q);
640 	ATF_TP_ADD_TC(tp, qsubq_s64q);
641 	ATF_TP_ADD_TC(tp, qfraci_s64q);
642 	ATF_TP_ADD_TC(tp, qmuli_s64q);
643 	ATF_TP_ADD_TC(tp, qaddi_s64q);
644 	ATF_TP_ADD_TC(tp, qsubi_s64q);
645 
646 	ATF_TP_ADD_TC(tp, circle_u64q);
647 
648 	return (atf_no_error());
649 }
650