]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - tests/sys/sys/qmath_test.c
zfs: merge openzfs/zfs@f795e90a1
[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
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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);
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
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 }