1/* Test file for mpfr_cos.
2
3Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
4Contributed by the Arenaire and Cacao 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 <stdio.h>
24#include <stdlib.h>
25
26#include "mpfr-test.h"
27
28#ifdef CHECK_EXTERNAL
29static int
30test_cos (mpfr_ptr a, mpfr_srcptr b, mpfr_rnd_t rnd_mode)
31{
32  int res;
33  int ok = rnd_mode == MPFR_RNDN && mpfr_number_p (b) && mpfr_get_prec (a)>=53;
34  if (ok)
35    {
36      mpfr_print_raw (b);
37    }
38  res = mpfr_cos (a, b, rnd_mode);
39  if (ok)
40    {
41      printf (" ");
42      mpfr_print_raw (a);
43      printf ("\n");
44    }
45  return res;
46}
47#else
48#define test_cos mpfr_cos
49#endif
50
51static void
52check53 (const char *xs, const char *cos_xs, mpfr_rnd_t rnd_mode)
53{
54  mpfr_t xx, c;
55
56  mpfr_inits2 (53, xx, c, (mpfr_ptr) 0);
57  mpfr_set_str1 (xx, xs); /* should be exact */
58  test_cos (c, xx, rnd_mode);
59  if (mpfr_cmp_str1 (c, cos_xs))
60    {
61      printf ("mpfr_cos failed for x=%s, rnd=%s\n",
62              xs, mpfr_print_rnd_mode (rnd_mode));
63      printf ("mpfr_cos gives cos(x)=");
64      mpfr_out_str(stdout, 10, 0, c, MPFR_RNDN);
65      printf(", expected %s\n", cos_xs);
66      exit (1);
67    }
68  mpfr_clears (xx, c, (mpfr_ptr) 0);
69}
70
71#define TEST_FUNCTION test_cos
72#define REDUCE_EMAX 262143 /* otherwise arg. reduction is too expensive */
73#include "tgeneric.c"
74
75static void
76check_nans (void)
77{
78  mpfr_t  x, y;
79
80  mpfr_init2 (x, 123L);
81  mpfr_init2 (y, 123L);
82
83  mpfr_set_nan (x);
84  test_cos (y, x, MPFR_RNDN);
85  if (! mpfr_nan_p (y))
86    {
87      printf ("Error: cos(NaN) != NaN\n");
88      exit (1);
89    }
90
91  mpfr_set_inf (x, 1);
92  test_cos (y, x, MPFR_RNDN);
93  if (! mpfr_nan_p (y))
94    {
95      printf ("Error: cos(Inf) != NaN\n");
96      exit (1);
97    }
98
99  mpfr_set_inf (x, -1);
100  test_cos (y, x, MPFR_RNDN);
101  if (! mpfr_nan_p (y))
102    {
103      printf ("Error: cos(-Inf) != NaN\n");
104      exit (1);
105    }
106
107  /* cos(+/-0) = 1 */
108  mpfr_set_ui (x, 0, MPFR_RNDN);
109  test_cos (y, x, MPFR_RNDN);
110  if (mpfr_cmp_ui (y, 1))
111    {
112      printf ("Error: cos(+0) != 1\n");
113      exit (1);
114    }
115  mpfr_neg (x, x, MPFR_RNDN);
116  test_cos (y, x, MPFR_RNDN);
117  if (mpfr_cmp_ui (y, 1))
118    {
119      printf ("Error: cos(-0) != 1\n");
120      exit (1);
121    }
122
123  /* Compute ~Pi/2 to check */
124  /* FIXME: Too slow!
125  mpfr_set_prec (x, 20000);
126  mpfr_const_pi (x, MPFR_RNDD); mpfr_div_2ui (x, x, 1, MPFR_RNDN);
127  mpfr_set_prec (y, 24);
128  test_cos (y, x, MPFR_RNDN);
129  if (mpfr_cmp_str (y, "0.111001010110100011000001E-20000", 2, MPFR_RNDN))
130    {
131      printf("Error computing cos(~Pi/2)\n");
132      mpfr_dump (y);
133      exit (1);
134      } */
135
136  mpfr_clear (x);
137  mpfr_clear (y);
138}
139
140static void
141special_overflow (void)
142{
143  mpfr_t x, y;
144  mpfr_exp_t emin, emax;
145
146  emin = mpfr_get_emin ();
147  emax = mpfr_get_emax ();
148
149  mpfr_init2 (x, 24);
150  mpfr_init2 (y, 73);
151
152  /* Check special case: An overflow in const_pi could occurs! */
153  set_emin (-125);
154  set_emax (128);
155  mpfr_set_str_binary (x, "0.111101010110110011101101E6");
156  test_cos (y, x, MPFR_RNDZ);
157  set_emin (emin);
158  set_emax (emax);
159
160  mpfr_clear (x);
161  mpfr_clear (y);
162}
163
164static void
165overflowed_cos0 (void)
166{
167  mpfr_t x, y;
168  int emax, i, inex, rnd, err = 0;
169  mpfr_exp_t old_emax;
170
171  old_emax = mpfr_get_emax ();
172
173  mpfr_init2 (x, 8);
174  mpfr_init2 (y, 8);
175
176  for (emax = -1; emax <= 0; emax++)
177    {
178      mpfr_set_ui_2exp (y, 1, emax, MPFR_RNDN);
179      mpfr_nextbelow (y);
180      set_emax (emax);  /* 1 is not representable. */
181      /* and if emax < 0, 1 - eps is not representable either. */
182      for (i = -1; i <= 1; i++)
183        RND_LOOP (rnd)
184        {
185          mpfr_set_si_2exp (x, i, -512 * ABS (i), MPFR_RNDN);
186          mpfr_clear_flags ();
187          inex = mpfr_cos (x, x, (mpfr_rnd_t) rnd);
188          if ((i == 0 || emax < 0 || rnd == MPFR_RNDN || rnd == MPFR_RNDU) &&
189              ! mpfr_overflow_p ())
190            {
191              printf ("Error in overflowed_cos0 (i = %d, rnd = %s):\n"
192                      "  The overflow flag is not set.\n",
193                      i, mpfr_print_rnd_mode ((mpfr_rnd_t) rnd));
194              err = 1;
195            }
196          if (rnd == MPFR_RNDZ || rnd == MPFR_RNDD)
197            {
198              if (inex >= 0)
199                {
200                  printf ("Error in overflowed_cos0 (i = %d, rnd = %s):\n"
201                          "  The inexact value must be negative.\n",
202                          i, mpfr_print_rnd_mode ((mpfr_rnd_t) rnd));
203                  err = 1;
204                }
205              if (! mpfr_equal_p (x, y))
206                {
207                  printf ("Error in overflowed_cos0 (i = %d, rnd = %s):\n"
208                          "  Got ", i, mpfr_print_rnd_mode ((mpfr_rnd_t) rnd));
209                  mpfr_print_binary (x);
210                  printf (" instead of 0.11111111E%d.\n", emax);
211                  err = 1;
212                }
213            }
214          else
215            {
216              if (inex <= 0)
217                {
218                  printf ("Error in overflowed_cos0 (i = %d, rnd = %s):\n"
219                          "  The inexact value must be positive.\n",
220                          i, mpfr_print_rnd_mode ((mpfr_rnd_t) rnd));
221                  err = 1;
222                }
223              if (! (mpfr_inf_p (x) && MPFR_SIGN (x) > 0))
224                {
225                  printf ("Error in overflowed_cos0 (i = %d, rnd = %s):\n"
226                          "  Got ", i, mpfr_print_rnd_mode ((mpfr_rnd_t) rnd));
227                  mpfr_print_binary (x);
228                  printf (" instead of +Inf.\n");
229                  err = 1;
230                }
231            }
232        }
233      set_emax (old_emax);
234    }
235
236  if (err)
237    exit (1);
238  mpfr_clear (x);
239  mpfr_clear (y);
240}
241
242static void
243bug20091030 (void)
244{
245  mpfr_t x, y;
246
247  mpfr_init2 (x, 5);
248  mpfr_init2 (y, 2);
249  mpfr_set_str (x, "-0.11001E3", 2, MPFR_RNDN);
250  mpfr_cos (y, x, MPFR_RNDN);
251  mpfr_clear (x);
252  mpfr_clear (y);
253}
254
255int
256main (int argc, char *argv[])
257{
258  mpfr_t x, y;
259  int inex;
260
261  tests_start_mpfr ();
262
263  special_overflow ();
264  check_nans ();
265
266  mpfr_init (x);
267  mpfr_init (y);
268
269  mpfr_set_prec (x, 53);
270  mpfr_set_prec (y, 2);
271  mpfr_set_str (x, "9.81333845856942e-1", 10, MPFR_RNDN);
272  test_cos (y, x, MPFR_RNDN);
273
274  mpfr_set_prec (x, 30);
275  mpfr_set_prec (y, 30);
276  mpfr_set_str_binary (x, "1.00001010001101110010100010101e-1");
277  test_cos (y, x, MPFR_RNDU);
278  mpfr_set_str_binary (x, "1.10111100010101011110101010100e-1");
279  if (mpfr_cmp (y, x))
280    {
281      printf ("Error for prec=30, rnd=MPFR_RNDU\n");
282      printf ("expected "); mpfr_print_binary (x); puts ("");
283      printf ("     got "); mpfr_print_binary (y); puts ("");
284      exit (1);
285    }
286
287  mpfr_set_prec (x, 59);
288  mpfr_set_prec (y, 59);
289  mpfr_set_str_binary (x, "1.01101011101111010011111110111111111011011101100111100011e-3");
290  test_cos (y, x, MPFR_RNDU);
291  mpfr_set_str_binary (x, "1.1111011111110010001001001011100111101110100010000010010011e-1");
292  if (mpfr_cmp (y, x))
293    {
294      printf ("Error for prec=59, rnd=MPFR_RNDU\n");
295      printf ("expected "); mpfr_print_binary (x); puts ("");
296      printf ("     got "); mpfr_print_binary (y); puts ("");
297      exit (1);
298    }
299
300  mpfr_set_prec (x, 5);
301  mpfr_set_prec (y, 5);
302  mpfr_set_str_binary (x, "1.1100e-2");
303  test_cos (y, x, MPFR_RNDD);
304  mpfr_set_str_binary (x, "1.1100e-1");
305  if (mpfr_cmp (y, x))
306    {
307      printf ("Error for x=1.1100e-2, rnd=MPFR_RNDD\n");
308      printf ("expected 1.1100e-1, got "); mpfr_print_binary (y); puts ("");
309      exit (1);
310    }
311
312  mpfr_set_prec (x, 32);
313  mpfr_set_prec (y, 32);
314
315  mpfr_set_str_binary (x, "0.10001000001001011000100001E-6");
316  mpfr_set_str_binary (y, "0.1111111111111101101111001100001");
317  test_cos (x, x, MPFR_RNDN);
318  if (mpfr_cmp (x, y))
319    {
320      printf ("Error for prec=32 (1)\n");
321      exit (1);
322    }
323
324  mpfr_set_str_binary (x, "-0.1101011110111100111010011001011E-1");
325  mpfr_set_str_binary (y, "0.11101001100110111011011010100011");
326  test_cos (x, x, MPFR_RNDN);
327  if (mpfr_cmp (x, y))
328    {
329      printf ("Error for prec=32 (2)\n");
330      exit (1);
331    }
332
333  /* huge argument reduction */
334  mpfr_set_str_binary (x, "0.10000010000001101011101111001011E40");
335  mpfr_set_str_binary (y, "0.10011000001111010000101011001011E-1");
336  test_cos (x, x, MPFR_RNDN);
337  if (mpfr_cmp (x, y))
338    {
339      printf ("Error for prec=32 (3)\n");
340      exit (1);
341    }
342
343  mpfr_set_prec (x, 3);
344  mpfr_set_prec (y, 3);
345  mpfr_set_str_binary (x, "0.110E60");
346  inex = mpfr_cos (y, x, MPFR_RNDD);
347  MPFR_ASSERTN(inex < 0);
348
349  /* worst case from PhD thesis of Vincent Lefe`vre: x=8980155785351021/2^54 */
350  check53 ("4.984987858808754279e-1", "8.783012931285841817e-1", MPFR_RNDN);
351  check53 ("4.984987858808754279e-1", "8.783012931285840707e-1", MPFR_RNDD);
352  check53 ("4.984987858808754279e-1", "8.783012931285840707e-1", MPFR_RNDZ);
353  check53 ("4.984987858808754279e-1", "8.783012931285841817e-1", MPFR_RNDU);
354  check53 ("1.00031274099908640274",  "0.540039116973283217504", MPFR_RNDN);
355  check53 ("1.00229256850978698523",  "0.538371757797526551137", MPFR_RNDZ);
356  check53 ("1.00288304857059840103",  "0.537874062022526966409", MPFR_RNDZ);
357  check53 ("1.00591265847407274059",  "0.53531755997839769456",  MPFR_RNDN);
358
359  check53 ("1.00591265847407274059", "0.53531755997839769456",  MPFR_RNDN);
360
361  overflowed_cos0 ();
362  test_generic (2, 100, 15);
363
364  /* check inexact flag */
365  mpfr_set_prec (x, 3);
366  mpfr_set_prec (y, 13);
367  mpfr_set_str_binary (x, "-0.100E196");
368  inex = mpfr_cos (y, x, MPFR_RNDU);
369  mpfr_set_prec (x, 13);
370  mpfr_set_str_binary (x, "0.1111111100101");
371  MPFR_ASSERTN (inex > 0 && mpfr_equal_p (x, y));
372
373  mpfr_clear (x);
374  mpfr_clear (y);
375
376  bug20091030 ();
377
378  data_check ("data/cos", mpfr_cos, "mpfr_cos");
379  bad_cases (mpfr_cos, mpfr_acos, "mpfr_cos", 256, -40, 0, 4, 128, 800, 50);
380
381  tests_end_mpfr ();
382  return 0;
383}
384