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