xref: /netbsd-src/external/lgpl3/mpfr/dist/tests/tstckintc.c (revision ba125506a622fe649968631a56eba5d42ff57863)
1 /* Test file for mpfr_custom_*
2 
3 Copyright 2005-2023 Free Software Foundation, Inc.
4 Contributed by the AriC and Caramba projects, INRIA.
5 
6 This file is part of the GNU MPFR Library.
7 
8 The GNU MPFR Library is free software; you can redistribute it and/or modify
9 it under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 3 of the License, or (at your
11 option) any later version.
12 
13 The GNU MPFR Library is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16 License for more details.
17 
18 You should have received a copy of the GNU Lesser General Public License
19 along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
20 https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
21 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
22 
23 #include "mpfr-test.h"
24 
25 /*************************************************************************/
26 
27 /* Bug found on 2022-05-05 in the mpfr_custom_get_size macro.
28    With the buggy macro, this test will fail if mpfr_prec_t > int,
29    typically on LP64 platforms (usual 64-bit machines).
30    This bug could occur only for precisions close to INT_MAX or higher. */
31 static void
test_get_size(void)32 test_get_size (void)
33 {
34   unsigned int u = UINT_MAX;
35   int i = INT_MAX;
36 
37   if (u <= MPFR_PREC_MAX)
38     {
39       mpfr_prec_t p = u;
40       size_t s1, s2;
41 
42       s1 = mpfr_custom_get_size (p);
43       s2 = mpfr_custom_get_size (u);
44       if (s1 != s2)
45         {
46           printf ("Error 1 in test_get_size (mpfr_custom_get_size macro).\n");
47           printf ("Expected %lu\n", (unsigned long) s1);
48           printf ("Got      %lu\n", (unsigned long) s2);
49           exit (1);
50         }
51     }
52 
53   if (i <= MPFR_PREC_MAX)
54     {
55       mpfr_prec_t p = i;
56       size_t s1, s2;
57 
58       s1 = mpfr_custom_get_size (p);
59       s2 = mpfr_custom_get_size (i);
60       if (s1 != s2)
61         {
62           printf ("Error 2 in test_get_size (mpfr_custom_get_size macro).\n");
63           printf ("Expected %lu\n", (unsigned long) s1);
64           printf ("Got      %lu\n", (unsigned long) s2);
65           exit (1);
66         }
67     }
68 }
69 
70 /*************************************************************************/
71 
72 #define BUFFER_SIZE 250
73 #define PREC_TESTED 200
74 
75 long Buffer[BUFFER_SIZE];
76 char *stack = (char *) Buffer;
77 long *org = (long *) Buffer;
78 mpfr_prec_t p = PREC_TESTED;
79 
80 #define ALIGNED(s) (((s) + sizeof (long) - 1) / sizeof (long) * sizeof (long))
81 
82 /* This code ensures alignment to "long". However, this might not be
83    sufficient on some platforms. GCC's -Wcast-align=strict option can
84    be useful, but this needs successive casts to help GCC, e.g.
85 
86    newx = (mpfr_ptr) (long *) (void *) old_stack;
87 
88    successively casts old_stack (of type char *) to
89    - void *: avoid a false positive for the following cast to long *
90      (as the code takes care of alignment to "long");
91    - long *: this corresponds to the alignment checked by MPFR; coming
92      from void *, it will not trigger a warning (even if incorrect);
93    - mpfr_ptr: -Wcast-align=strict will emit a warning if mpfr_ptr has
94      an alignment requirement stronger than long *. In such a case,
95      the code will have to be fixed.
96 */
97 
98 static void *
new_st(size_t s)99 new_st (size_t s)
100 {
101   void *p = (void *) stack;
102 
103   if (MPFR_UNLIKELY (s > (char *) &Buffer[BUFFER_SIZE] - stack))
104     {
105       printf ("[INTERNAL TEST ERROR] Stack overflow.\n");
106       exit (1);
107     }
108   stack += ALIGNED (s);
109   return p;
110 }
111 
112 static void
reset_stack(void)113 reset_stack (void)
114 {
115   stack = (char *) Buffer;
116 }
117 
118 /*************************************************************************/
119 
120 /* Alloc a new mpfr_t on the main stack */
121 static mpfr_ptr
new_mpfr(mpfr_prec_t p)122 new_mpfr (mpfr_prec_t p)
123 {
124   mpfr_ptr x = (mpfr_ptr) new_st (sizeof (mpfr_t));
125   void *mantissa = new_st (mpfr_custom_get_size (p));
126 
127   mpfr_custom_init (mantissa, p);
128   mpfr_custom_init_set (x, 0, 0, p, mantissa);
129   return x;
130 }
131 
132 /* Alloc a new mpfr_t on the main stack */
133 static mpfr_ptr
new_nan1(mpfr_prec_t p)134 new_nan1 (mpfr_prec_t p)
135 {
136   mpfr_ptr x = (mpfr_ptr) new_st (sizeof (mpfr_t));
137   void *mantissa = new_st ((mpfr_custom_get_size) (p));
138 
139   (mpfr_custom_init) (mantissa, p);
140   (mpfr_custom_init_set) (x, MPFR_NAN_KIND, 0, p, mantissa);
141   return x;
142 }
143 
144 /* Alloc a new mpfr_t on the main stack */
145 static mpfr_ptr
new_nan2(mpfr_prec_t p)146 new_nan2 (mpfr_prec_t p)
147 {
148   mpfr_ptr x = (mpfr_ptr) new_st (sizeof (mpfr_t));
149   void *mantissa = new_st ((mpfr_custom_get_size) (p));
150   int i1, i2, i3, i4, i5;
151 
152   /* Check side effects. */
153   i1 = i2 = 0;
154   mpfr_custom_init ((i1++, mantissa), (i2++, p));
155   MPFR_ASSERTN (i1 == 1);
156   MPFR_ASSERTN (i2 == 1);
157 
158   /* Check that the type "void *" can be used in C, like with the function
159      (forbidden in C++). Also check side effects. */
160   i1 = i2 = i3 = i4 = i5 = 0;
161 #ifdef IGNORE_CPP_COMPAT
162 #pragma GCC diagnostic push
163 #pragma GCC diagnostic ignored "-Wc++-compat"
164 #endif
165   mpfr_custom_init_set ((i1++, VOIDP_CAST(x)),
166                         (i2++, MPFR_NAN_KIND),
167                         (i3++, 0),
168                         (i4++, p),
169                         (i5++, mantissa));
170 #ifdef IGNORE_CPP_COMPAT
171 #pragma GCC diagnostic pop
172 #endif
173   MPFR_ASSERTN (i1 == 1);
174   MPFR_ASSERTN (i2 == 1);
175   MPFR_ASSERTN (i3 == 1);
176   MPFR_ASSERTN (i4 == 1);
177   MPFR_ASSERTN (i5 == 1);
178 
179   return x;
180 }
181 
182 /* Alloc a new mpfr_t on the main stack */
183 static mpfr_ptr
new_inf(mpfr_prec_t p)184 new_inf (mpfr_prec_t p)
185 {
186   mpfr_ptr x = (mpfr_ptr) new_st (sizeof (mpfr_t));
187   void *mantissa = new_st ((mpfr_custom_get_size) (p));
188 
189   (mpfr_custom_init) (mantissa, p);
190   (mpfr_custom_init_set) (x, -MPFR_INF_KIND, 0, p, mantissa);
191   return x;
192 }
193 
194 /* Garbage the stack by keeping only x and save it in old_stack */
195 static mpfr_ptr
return_mpfr(mpfr_ptr x,char * old_stack)196 return_mpfr (mpfr_ptr x, char *old_stack)
197 {
198   void *mantissa       = mpfr_custom_get_significand (x);
199   size_t size_mantissa = mpfr_custom_get_size (mpfr_get_prec (x));
200   mpfr_ptr newx;
201   long *newx2;
202   int i1, i2;
203 
204   /* Check that the type "void *" can be used in C, like with the function
205      (forbidden in C++). Also check side effects. */
206   i1 = 0;
207 #ifdef IGNORE_CPP_COMPAT
208 #pragma GCC diagnostic push
209 #pragma GCC diagnostic ignored "-Wc++-compat"
210 #endif
211   MPFR_ASSERTN (mpfr_custom_get_significand ((i1++, VOIDP_CAST(x)))
212                 == mantissa);
213 #ifdef IGNORE_CPP_COMPAT
214 #pragma GCC diagnostic pop
215 #endif
216   MPFR_ASSERTN (i1 == 1);
217 
218   memmove (old_stack, x, sizeof (mpfr_t));
219   memmove (old_stack + ALIGNED (sizeof (mpfr_t)), mantissa, size_mantissa);
220   newx = (mpfr_ptr) (long *) (void *) old_stack;
221   newx2 = (long *) (void *) (old_stack + ALIGNED (sizeof (mpfr_t)));
222 
223   /* Check that the type "void *" can be used in C, like with the function
224      (forbidden in C++). Also check side effects. */
225   i1 = i2 = 0;
226 #ifdef IGNORE_CPP_COMPAT
227 #pragma GCC diagnostic push
228 #pragma GCC diagnostic ignored "-Wc++-compat"
229 #endif
230   mpfr_custom_move ((i1++, VOIDP_CAST(newx)), (i2++, newx2));
231 #ifdef IGNORE_CPP_COMPAT
232 #pragma GCC diagnostic pop
233 #endif
234   MPFR_ASSERTN (i1 == 1);
235   MPFR_ASSERTN (i2 == 1);
236 
237   stack = (char *) newx2 + ALIGNED (size_mantissa);
238   return newx;
239 }
240 
241 /* Garbage the stack by keeping only x and save it in old_stack */
242 static mpfr_ptr
return_mpfr_func(mpfr_ptr x,char * old_stack)243 return_mpfr_func (mpfr_ptr x, char *old_stack)
244 {
245   void *mantissa       = (mpfr_custom_get_significand) (x);
246   size_t size_mantissa = (mpfr_custom_get_size) (mpfr_get_prec (x));
247   mpfr_ptr newx;
248 
249   memmove (old_stack, x, sizeof (mpfr_t));
250   memmove (old_stack + ALIGNED (sizeof (mpfr_t)), mantissa, size_mantissa);
251   newx = (mpfr_ptr) (long *) (void *) old_stack;
252   (mpfr_custom_move) (newx, old_stack + ALIGNED (sizeof (mpfr_t)));
253   stack = old_stack + ALIGNED (sizeof (mpfr_t)) + ALIGNED (size_mantissa);
254   return newx;
255 }
256 
257 /*************************************************************************/
258 
259 static void
test1(void)260 test1 (void)
261 {
262   mpfr_ptr x, y;
263 
264   reset_stack ();
265   org = (long *) (void *) stack;
266 
267   x = new_mpfr (p);
268   y = new_mpfr (p);
269   mpfr_set_ui (x, 42, MPFR_RNDN);
270   mpfr_set_ui (y, 17, MPFR_RNDN);
271   mpfr_add (y, x, y, MPFR_RNDN);
272   y = return_mpfr (y, (char *) org);
273   if ((long *) y != org || mpfr_cmp_ui (y, 59) != 0)
274     {
275       printf ("Compact (1) failed!\n");
276       exit (1);
277     }
278 
279   x = new_mpfr (p);
280   y = new_mpfr (p);
281   mpfr_set_ui (x, 4217, MPFR_RNDN);
282   mpfr_set_ui (y, 1742, MPFR_RNDN);
283   mpfr_add (y, x, y, MPFR_RNDN);
284   y = return_mpfr_func (y, (char *) org);
285   if ((long *) y != org || mpfr_cmp_ui (y, 5959) != 0)
286     {
287       printf ("Compact (5) failed!\n");
288       exit (1);
289     }
290 
291   reset_stack ();
292 }
293 
294 static void
test_nan_inf_zero(void)295 test_nan_inf_zero (void)
296 {
297   mpfr_ptr val;
298   mpfr_srcptr sval;  /* for compilation error checking */
299   int sign;
300   int kind;
301 
302   reset_stack ();
303 
304   val = new_mpfr (MPFR_PREC_MIN);
305   sval = val;
306   mpfr_set_nan (val);
307   kind = (mpfr_custom_get_kind) (sval);
308   if (kind != MPFR_NAN_KIND)
309     {
310       printf ("mpfr_custom_get_kind error: ");
311       mpfr_dump (val);
312       printf (" is kind %d instead of %d\n", kind, (int) MPFR_NAN_KIND);
313       exit (1);
314     }
315 
316   val = new_nan1 (MPFR_PREC_MIN);
317   if (!mpfr_nan_p(val))
318     {
319       printf ("Error: mpfr_custom_init_set doesn't set NAN mpfr (1).\n");
320       exit (1);
321     }
322 
323   val = new_nan2 (MPFR_PREC_MIN);
324   if (!mpfr_nan_p(val))
325     {
326       printf ("Error: mpfr_custom_init_set doesn't set NAN mpfr (2).\n");
327       exit (1);
328     }
329 
330   val = new_inf (MPFR_PREC_MIN);
331   if (!mpfr_inf_p(val) || mpfr_sgn(val) >= 0)
332     {
333       printf ("Error: mpfr_custom_init_set doesn't set -INF mpfr.\n");
334       exit (1);
335     }
336 
337   sign = 1;
338   mpfr_set_inf (val, sign);
339   kind = (mpfr_custom_get_kind) (val);
340   if ((ABS (kind) != MPFR_INF_KIND) || (VSIGN (kind) != VSIGN (sign)))
341     {
342       printf ("mpfr_custom_get_kind error: ");
343       mpfr_dump (val);
344       printf (" is kind %d instead of %d\n", kind, (int) MPFR_INF_KIND);
345       printf (" have sign %d instead of %d\n", VSIGN (kind), VSIGN (sign));
346       exit (1);
347     }
348 
349   sign = -1;
350   mpfr_set_zero (val, sign);
351   kind = (mpfr_custom_get_kind) (val);
352   if ((ABS (kind) != MPFR_ZERO_KIND) || (VSIGN (kind) != VSIGN (sign)))
353     {
354       printf ("mpfr_custom_get_kind error: ");
355       mpfr_dump (val);
356       printf (" is kind %d instead of %d\n", kind, (int) MPFR_ZERO_KIND);
357       printf (" have sign %d instead of %d\n", VSIGN (kind), VSIGN (sign));
358       exit (1);
359     }
360 
361   reset_stack ();
362 }
363 
364 /*************************************************************************/
365 
366 /* We build the MPFR variable each time it is needed */
367 /* a[0] is the kind, a[1] is the exponent, &a[2] is the mantissa */
368 static long *
dummy_new(void)369 dummy_new (void)
370 {
371   long *r;
372 
373   r = (long *) new_st (ALIGNED (2 * sizeof (long)) +
374                        ALIGNED (mpfr_custom_get_size (p)));
375   (mpfr_custom_init) (&r[2], p);
376   r[0] = (int) MPFR_NAN_KIND;
377   r[1] = 0;
378   return r;
379 }
380 
381 static long *
dummy_set_si(long si)382 dummy_set_si (long si)
383 {
384   mpfr_t x;
385   mpfr_srcptr px;  /* for compilation error checking */
386   long *r = dummy_new ();
387   int i1, i2, i3, i4, i5;
388 
389   /* Check that the type "void *" can be used, like with the function.
390      Also check side effects. */
391   i1 = i2 = i3 = i4 = i5 = 0;
392 #ifdef IGNORE_CPP_COMPAT
393 #pragma GCC diagnostic push
394 #pragma GCC diagnostic ignored "-Wc++-compat"
395 #endif
396   mpfr_custom_init_set ((i1++, VOIDP_CAST(x)),
397                         (i2++, MPFR_REGULAR_KIND),
398                         (i3++, 0),
399                         (i4++, p),
400                         (i5++, &r[2]));
401 #ifdef IGNORE_CPP_COMPAT
402 #pragma GCC diagnostic pop
403 #endif
404   MPFR_ASSERTN (i1 == 1);
405   MPFR_ASSERTN (i2 == 1);
406   MPFR_ASSERTN (i3 == 1);
407   MPFR_ASSERTN (i4 == 1);
408   MPFR_ASSERTN (i5 == 1);
409 
410   mpfr_set_si (x, si, MPFR_RNDN);
411   px = x;
412   r[0] = mpfr_custom_get_kind (px);
413 
414   /* Check that the type "void *" can be used in C, like with the function
415      (forbidden in C++). Also check side effects. */
416   i1 = 0;
417 #ifdef IGNORE_CPP_COMPAT
418 #pragma GCC diagnostic push
419 #pragma GCC diagnostic ignored "-Wc++-compat"
420 #endif
421   MPFR_ASSERTN (mpfr_custom_get_kind ((i1++, VOIDP_CAST(x))) == r[0]);
422 #ifdef IGNORE_CPP_COMPAT
423 #pragma GCC diagnostic pop
424 #endif
425   MPFR_ASSERTN (i1 == 1);
426 
427   r[1] = mpfr_custom_get_exp (x);
428 
429   /* Check that the type "void *" can be used in C, like with the function
430      (forbidden in C++). Also check side effects. */
431   i1 = 0;
432 #ifdef IGNORE_CPP_COMPAT
433 #pragma GCC diagnostic push
434 #pragma GCC diagnostic ignored "-Wc++-compat"
435 #endif
436   MPFR_ASSERTN (mpfr_custom_get_exp ((i1++, VOIDP_CAST(x))) == r[1]);
437 #ifdef IGNORE_CPP_COMPAT
438 #pragma GCC diagnostic pop
439 #endif
440   MPFR_ASSERTN (i1 == 1);
441 
442   return r;
443 }
444 
445 static long *
dummy_add(long * a,long * b)446 dummy_add (long *a, long *b)
447 {
448   mpfr_t x, y, z;
449   long *r = dummy_new ();
450 
451   mpfr_custom_init_set (x, 0 + MPFR_REGULAR_KIND, 0, p, &r[2]);
452   (mpfr_custom_init_set) (y, a[0], a[1], p, &a[2]);
453   mpfr_custom_init_set (z, 0 + b[0], b[1], p, &b[2]);
454   mpfr_add (x, y, z, MPFR_RNDN);
455   r[0] = (mpfr_custom_get_kind) (x);
456   r[1] = (mpfr_custom_get_exp) (x);
457   return r;
458 }
459 
460 static long *
dummy_compact(long * r,long * org_stack)461 dummy_compact (long *r, long *org_stack)
462 {
463   memmove (org_stack, r,
464            ALIGNED (2*sizeof (long)) + ALIGNED ((mpfr_custom_get_size) (p)));
465   return org_stack;
466 }
467 
468 /*************************************************************************/
469 
470 static void
test2(void)471 test2 (void)
472 {
473   mpfr_t x;
474   long *a, *b, *c;
475 
476   reset_stack ();
477   org = (long *) (void *) stack;
478 
479   a = dummy_set_si (42);
480   b = dummy_set_si (17);
481   c = dummy_add (a, b);
482   c = dummy_compact (c, org);
483   (mpfr_custom_init_set) (x, c[0], c[1], p, &c[2]);
484   if (c != org || mpfr_cmp_ui (x, 59) != 0)
485     {
486       printf ("Compact (2) failed! c=%p a=%p\n", (void *) c, (void *) a);
487       mpfr_dump (x);
488       exit (1);
489     }
490 
491   a = dummy_set_si (42);
492   b = dummy_set_si (-17);
493   c = dummy_add (a, b);
494   c = dummy_compact (c, org);
495   (mpfr_custom_init_set) (x, c[0], c[1], p, &c[2]);
496   if (c != org || mpfr_cmp_ui (x, 25) != 0)
497     {
498       printf ("Compact (6) failed! c=%p a=%p\n", (void *) c, (void *) a);
499       mpfr_dump (x);
500       exit (1);
501     }
502 
503   reset_stack ();
504 }
505 
506 
507 int
main(void)508 main (void)
509 {
510   tests_start_mpfr ();
511   test_get_size ();
512   /* We test iff long = mp_limb_t */
513   if (sizeof (long) == sizeof (mp_limb_t))
514     {
515       test1 ();
516       test2 ();
517       test_nan_inf_zero ();
518     }
519   tests_end_mpfr ();
520   return 0;
521 }
522