tsum.c revision 1.1.1.3
1/* tsum -- test file for the list summation function
2
3Copyright 2004-2016 Free Software Foundation, Inc.
4Contributed by the AriC and Caramba projects, INRIA.
5
6This file is part of the GNU MPFR Library.
7
8The GNU MPFR Library is free software; you can redistribute it and/or modify
9it under the terms of the GNU Lesser General Public License as published by
10the Free Software Foundation; either version 3 of the License, or (at your
11option) any later version.
12
13The GNU MPFR Library is distributed in the hope that it will be useful, but
14WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16License for more details.
17
18You should have received a copy of the GNU Lesser General Public License
19along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
20http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
2151 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
22
23#include <stdlib.h>
24#include <stdio.h>
25#include "mpfr-test.h"
26
27static int
28check_is_sorted (unsigned long n, mpfr_srcptr *perm)
29{
30  unsigned long i;
31
32  for (i = 0; i < n - 1; i++)
33    if (MPFR_GET_EXP(perm[i]) < MPFR_GET_EXP(perm[i+1]))
34      return 0;
35  return 1;
36}
37
38static int
39sum_tab (mpfr_ptr ret, mpfr_t *tab, unsigned long n, mpfr_rnd_t rnd)
40{
41  mpfr_ptr *tabtmp;
42  unsigned long i;
43  int inexact;
44  MPFR_TMP_DECL(marker);
45
46  MPFR_TMP_MARK(marker);
47  tabtmp = (mpfr_ptr *) MPFR_TMP_ALLOC(n * sizeof(mpfr_srcptr));
48  for (i = 0; i < n; i++)
49    tabtmp[i] = tab[i];
50
51  inexact = mpfr_sum (ret, tabtmp, n, rnd);
52  MPFR_TMP_FREE(marker);
53  return inexact;
54}
55
56
57static mpfr_prec_t
58get_prec_max (mpfr_t *tab, unsigned long n, mpfr_prec_t f)
59{
60  mpfr_prec_t res;
61  mpfr_exp_t min, max;
62  unsigned long i;
63
64  i = 0;
65  while (MPFR_IS_ZERO (tab[i]))
66    {
67      i++;
68      if (i == n)
69        return MPFR_PREC_MIN;  /* all values are 0 */
70    }
71
72  if (! mpfr_check (tab[i]))
73    {
74      printf ("tab[%lu] is not valid.\n", i);
75      exit (1);
76    }
77  MPFR_ASSERTN (MPFR_IS_FP (tab[i]));
78  min = max = MPFR_GET_EXP(tab[i]);
79  for (i++; i < n; i++)
80    {
81      if (! mpfr_check (tab[i]))
82        {
83          printf ("tab[%lu] is not valid.\n", i);
84          exit (1);
85        }
86      MPFR_ASSERTN (MPFR_IS_FP (tab[i]));
87      if (! MPFR_IS_ZERO (tab[i]))
88        {
89          if (MPFR_GET_EXP(tab[i]) > max)
90            max = MPFR_GET_EXP(tab[i]);
91          if (MPFR_GET_EXP(tab[i]) < min)
92            min = MPFR_GET_EXP(tab[i]);
93        }
94    }
95  res = max - min;
96  res += f;
97  res += __gmpfr_ceil_log2 (n) + 1;
98  return res;
99}
100
101
102static void
103algo_exact (mpfr_t somme, mpfr_t *tab, unsigned long n, mpfr_prec_t f)
104{
105  unsigned long i;
106  mpfr_prec_t prec_max;
107
108  prec_max = get_prec_max(tab, n, f);
109  mpfr_set_prec (somme, prec_max);
110  mpfr_set_ui (somme, 0, MPFR_RNDN);
111  for (i = 0; i < n; i++)
112    {
113      if (mpfr_add(somme, somme, tab[i], MPFR_RNDN))
114        {
115          printf ("FIXME: algo_exact is buggy.\n");
116          exit (1);
117        }
118    }
119}
120
121/* Test the sorting function */
122static void
123test_sort (mpfr_prec_t f, unsigned long n)
124{
125  mpfr_t *tab;
126  mpfr_ptr *tabtmp;
127  mpfr_srcptr *perm;
128  unsigned long i;
129  mpfr_prec_t prec = MPFR_PREC_MIN;
130
131  /* Init stuff */
132  tab = (mpfr_t *) tests_allocate (n * sizeof (mpfr_t));
133  for (i = 0; i < n; i++)
134    mpfr_init2 (tab[i], f);
135  tabtmp = (mpfr_ptr *) tests_allocate (n * sizeof(mpfr_ptr));
136  perm = (mpfr_srcptr *) tests_allocate (n * sizeof(mpfr_srcptr));
137
138  for (i = 0; i < n; i++)
139    {
140      mpfr_urandomb (tab[i], RANDS);
141      tabtmp[i] = tab[i];
142    }
143
144  mpfr_sum_sort ((mpfr_srcptr *)tabtmp, n, perm, &prec);
145
146  if (check_is_sorted (n, perm) == 0)
147    {
148      printf ("mpfr_sum_sort incorrect.\n");
149      for (i = 0; i < n; i++)
150        mpfr_dump (perm[i]);
151      exit (1);
152    }
153
154  /* Clear stuff */
155  for (i = 0; i < n; i++)
156    mpfr_clear (tab[i]);
157  tests_free (tab, n * sizeof (mpfr_t));
158  tests_free (tabtmp, n * sizeof(mpfr_ptr));
159  tests_free (perm, n * sizeof(mpfr_srcptr));
160}
161
162static void
163test_sum (mpfr_prec_t f, unsigned long n)
164{
165  mpfr_t sum, real_sum, real_non_rounded;
166  mpfr_t *tab;
167  unsigned long i;
168  int rnd_mode;
169
170  /* Init */
171  tab = (mpfr_t *) tests_allocate (n * sizeof(mpfr_t));
172  for (i = 0; i < n; i++)
173    mpfr_init2 (tab[i], f);
174  mpfr_inits2 (f, sum, real_sum, real_non_rounded, (mpfr_ptr) 0);
175
176  /* First Uniform */
177  for (i = 0; i < n; i++)
178    mpfr_urandomb (tab[i], RANDS);
179  algo_exact (real_non_rounded, tab, n, f);
180  for (rnd_mode = 0; rnd_mode < MPFR_RND_MAX; rnd_mode++)
181    {
182      sum_tab (sum, tab, n, (mpfr_rnd_t) rnd_mode);
183      mpfr_set (real_sum, real_non_rounded, (mpfr_rnd_t) rnd_mode);
184      if (mpfr_cmp (real_sum, sum) != 0)
185        {
186          printf ("mpfr_sum incorrect.\n");
187          mpfr_dump (real_sum);
188          mpfr_dump (sum);
189          exit (1);
190        }
191    }
192
193  /* Then non uniform */
194  for (i = 0; i < n; i++)
195    {
196      mpfr_urandomb (tab[i], RANDS);
197      if (! mpfr_zero_p (tab[i]))
198        mpfr_set_exp (tab[i], randlimb () % 1000);
199    }
200  algo_exact (real_non_rounded, tab, n, f);
201  for (rnd_mode = 0; rnd_mode < MPFR_RND_MAX; rnd_mode++)
202    {
203      sum_tab (sum, tab, n, (mpfr_rnd_t) rnd_mode);
204      mpfr_set (real_sum, real_non_rounded, (mpfr_rnd_t) rnd_mode);
205      if (mpfr_cmp (real_sum, sum) != 0)
206        {
207          printf ("mpfr_sum incorrect.\n");
208          mpfr_dump (real_sum);
209          mpfr_dump (sum);
210          exit (1);
211        }
212    }
213
214  /* Clear stuff */
215  for (i = 0; i < n; i++)
216    mpfr_clear (tab[i]);
217  mpfr_clears (sum, real_sum, real_non_rounded, (mpfr_ptr) 0);
218  tests_free (tab, n * sizeof(mpfr_t));
219}
220
221static
222void check_special (void)
223{
224  mpfr_t tab[3], r;
225  mpfr_ptr tabp[3];
226  int i;
227
228  mpfr_inits (tab[0], tab[1], tab[2], r, (mpfr_ptr) 0);
229  tabp[0] = tab[0];
230  tabp[1] = tab[1];
231  tabp[2] = tab[2];
232
233  i = mpfr_sum (r, tabp, 0, MPFR_RNDN);
234  if (!MPFR_IS_ZERO (r) || !MPFR_IS_POS (r) || i != 0)
235    {
236      printf ("Special case n==0 failed!\n");
237      exit (1);
238    }
239
240  mpfr_set_ui (tab[0], 42, MPFR_RNDN);
241  i = mpfr_sum (r, tabp, 1, MPFR_RNDN);
242  if (mpfr_cmp_ui (r, 42) || i != 0)
243    {
244      printf ("Special case n==1 failed!\n");
245      exit (1);
246    }
247
248  mpfr_set_ui (tab[1], 17, MPFR_RNDN);
249  MPFR_SET_NAN (tab[2]);
250  i = mpfr_sum (r, tabp, 3, MPFR_RNDN);
251  if (!MPFR_IS_NAN (r) || i != 0)
252    {
253      printf ("Special case NAN failed!\n");
254      exit (1);
255    }
256
257  MPFR_SET_INF (tab[2]);
258  MPFR_SET_POS (tab[2]);
259  i = mpfr_sum (r, tabp, 3, MPFR_RNDN);
260  if (!MPFR_IS_INF (r) || !MPFR_IS_POS (r) || i != 0)
261    {
262      printf ("Special case +INF failed!\n");
263      exit (1);
264    }
265
266  MPFR_SET_INF (tab[2]);
267  MPFR_SET_NEG (tab[2]);
268  i = mpfr_sum (r, tabp, 3, MPFR_RNDN);
269  if (!MPFR_IS_INF (r) || !MPFR_IS_NEG (r) || i != 0)
270    {
271      printf ("Special case -INF failed!\n");
272      exit (1);
273    }
274
275  MPFR_SET_ZERO (tab[1]);
276  i = mpfr_sum (r, tabp, 2, MPFR_RNDN);
277  if (mpfr_cmp_ui (r, 42) || i != 0)
278    {
279      printf ("Special case 42+0 failed!\n");
280      exit (1);
281    }
282
283  MPFR_SET_NAN (tab[0]);
284  i = mpfr_sum (r, tabp, 3, MPFR_RNDN);
285  if (!MPFR_IS_NAN (r) || i != 0)
286    {
287      printf ("Special case NAN+0+-INF failed!\n");
288      exit (1);
289    }
290
291  mpfr_set_inf (tab[0], 1);
292  mpfr_set_ui  (tab[1], 59, MPFR_RNDN);
293  mpfr_set_inf (tab[2], -1);
294  i = mpfr_sum (r, tabp, 3, MPFR_RNDN);
295  if (!MPFR_IS_NAN (r) || i != 0)
296    {
297      printf ("Special case +INF + 59 +-INF failed!\n");
298      exit (1);
299    }
300
301  mpfr_clears (tab[0], tab[1], tab[2], r, (mpfr_ptr) 0);
302}
303
304/* bug reported by Joseph S. Myers on 2013-10-27
305   https://sympa.inria.fr/sympa/arc/mpfr/2013-10/msg00015.html */
306static void
307bug20131027 (void)
308{
309  mpfr_t r, t[4];
310  mpfr_ptr p[4];
311  char *s[4] = {
312    "0x1p1000",
313    "-0x0.fffffffffffff80000000000000001p1000",
314    "-0x1p947",
315    "0x1p880"
316  };
317  int i;
318
319  mpfr_init2 (r, 53);
320  for (i = 0; i < 4; i++)
321    {
322      mpfr_init2 (t[i], i == 0 ? 53 : 1000);
323      mpfr_set_str (t[i], s[i], 0, MPFR_RNDN);
324      p[i] = t[i];
325    }
326  mpfr_sum (r, p, 4, MPFR_RNDN);
327
328  if (MPFR_NOTZERO (r))
329    {
330      printf ("mpfr_sum incorrect in bug20131027: expected 0, got\n");
331      mpfr_dump (r);
332      exit (1);
333    }
334
335  for (i = 0; i < 4; i++)
336    mpfr_clear (t[i]);
337  mpfr_clear (r);
338}
339
340int
341main (void)
342{
343  mpfr_prec_t p;
344  unsigned long n;
345
346  tests_start_mpfr ();
347
348  check_special ();
349  bug20131027 ();
350  test_sort (1764, 1026);
351  for (p = 2 ; p < 444 ; p += 17)
352    for (n = 2 ; n < 1026 ; n += 42 + p)
353      test_sum (p, n);
354
355  tests_end_mpfr ();
356  return 0;
357}
358