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