]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/sys/qmath_test.c
amd64: use register macros for gdb_cpu_getreg()
[FreeBSD/FreeBSD.git] / tests / sys / sys / qmath_test.c
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 }