Add default Smack manifest for mpfr.spec
[toolchains/mpfr.git] / ai.c
1 /* mpfr_ai -- Airy function Ai
2
3 Copyright 2010 Free Software Foundation, Inc.
4 Contributed by the Arenaire and Cacao 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 http://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 #define MPFR_NEED_LONGLONG_H
24 #include "mpfr-impl.h"
25
26 #define MPFR_SMALL_PRECISION 32
27
28
29 /* Reminder and notations:
30    -----------------------
31
32    Ai is the solution of:
33         / y'' - x*y = 0
34        {    Ai(0)   = 1/ ( 9^(1/3)*Gamma(2/3) )
35         \  Ai'(0)   = -1/ ( 3^(1/3)*Gamma(1/3) )
36
37    Series development:
38        Ai(x) = sum (a_i*x^i)
39              = sum (t_i)
40
41    Recurrences:
42        a_(i+3) = a_i / ((i+2)*(i+3))
43        t_(i+3) = t_i * x^3 / ((i+2)*(i+3))
44
45    Values:
46        a_0 = Ai(0)  ~  0.355
47        a_1 = Ai'(0) ~ -0.259
48 */
49
50
51 /* Airy function Ai evaluated by the most naive algorithm */
52 int
53 mpfr_ai (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd)
54 {
55   MPFR_ZIV_DECL (loop);
56   MPFR_SAVE_EXPO_DECL (expo);
57   mpfr_prec_t wprec;             /* working precision */
58   mpfr_prec_t prec;              /* target precision */
59   mpfr_prec_t err;               /* used to estimate the evaluation error */
60   mpfr_prec_t correct_bits;      /* estimates the number of correct bits*/
61   unsigned long int k;
62   unsigned long int cond;        /* condition number of the series */
63   unsigned long int assumed_exponent; /* used as a lowerbound of |EXP(Ai(x))| */
64   int r;
65   mpfr_t s;                      /* used to store the partial sum */
66   mpfr_t ti, tip1;   /* used to store successive values of t_i */
67   mpfr_t x3;                     /* used to store x^3 */
68   mpfr_t tmp_sp, tmp2_sp;        /* small precision variables */
69   unsigned long int x3u;         /* used to store ceil(x^3) */
70   mpfr_t temp1, temp2;
71   int test1, test2;
72
73   /* Logging */
74   MPFR_LOG_FUNC ( ("x[%#R]=%R rnd=%d", x, x, rnd), ("y[%#R]=%R", y, y) );
75
76   /* Special cases */
77   if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x)))
78     {
79       if (MPFR_IS_NAN (x))
80         {
81           MPFR_SET_NAN (y);
82           MPFR_RET_NAN;
83         }
84       else if (MPFR_IS_INF (x))
85         return mpfr_set_ui (y, 0, rnd);
86     }
87
88   /* FIXME: handle the case x == 0 (and in a consistent way for +0 and -0) */
89
90   /* Save current exponents range */
91   MPFR_SAVE_EXPO_MARK (expo);
92
93   /* FIXME: underflow for large values of |x| ? */
94
95
96   /* Set initial precision */
97   /* If we compute sum(i=0, N-1, t_i), the relative error is bounded by  */
98   /*       2*(4N)*2^(1-wprec)*C(|x|)/Ai(x)                               */
99   /* where C(|x|) = 1 if 0<=x<=1                                         */
100   /*   and C(|x|) = (1/2)*x^(-1/4)*exp(2/3 x^(3/2))  if x >= 1           */
101
102   /* A priori, we do not know N, so we estimate it to ~ prec             */
103   /* If 0<=x<=1, we estimate Ai(x) ~ 1/8                                 */
104   /* if 1<=x,    we estimate Ai(x) ~ (1/4)*x^(-1/4)*exp(-2/3 * x^(3/2))  */
105   /* if x<=0,    ?????                                                   */
106
107   /* We begin with 11 guard bits */
108   prec = MPFR_PREC (y)+11;
109   MPFR_ZIV_INIT (loop, prec);
110
111   /* The working precision is heuristically chosen in order to obtain  */
112   /* approximately prec correct bits in the sum. To sum up: the sum    */
113   /* is stopped when the *exact* sum gives ~ prec correct bit. And     */
114   /* when it is stopped, the accuracy of the computed sum, with respect*/
115   /* to the exact one should be ~prec bits.                            */
116   mpfr_init2 (tmp_sp, MPFR_SMALL_PRECISION);
117   mpfr_init2 (tmp2_sp, MPFR_SMALL_PRECISION);
118   mpfr_abs (tmp_sp, x, MPFR_RNDU);
119   mpfr_pow_ui (tmp_sp, tmp_sp, 3, MPFR_RNDU);
120   mpfr_sqrt (tmp_sp, tmp_sp, MPFR_RNDU); /* tmp_sp ~ x^3/2 */
121
122   /* 0.96179669392597567 >~ 2/3 * log2(e). See algorithms.tex */
123   mpfr_set_str(tmp2_sp, "0.96179669392597567", 10, MPFR_RNDU);
124   mpfr_mul (tmp2_sp, tmp_sp, tmp2_sp, MPFR_RNDU);
125
126   /* cond represents the number of lost bits in the evaluation of the sum */
127   if ( (MPFR_IS_ZERO(x)) || (MPFR_GET_EXP (x) <= 0) )
128     cond = 0;
129   else
130     cond = mpfr_get_ui (tmp2_sp, MPFR_RNDU) - (MPFR_GET_EXP (x)-1)/4 - 1;
131
132   /* The variable assumed_exponent is used to store the maximal assumed */
133   /* exponent of Ai(x). More precisely, we assume that |Ai(x)| will be  */
134   /* greater than 2^{-assumed_exponent}.                                */
135   if (MPFR_IS_ZERO(x))
136     assumed_exponent = 2;
137   else
138     {
139       if (MPFR_IS_POS (x))
140         {
141           if (MPFR_GET_EXP (x) <= 0)
142             assumed_exponent = 3;
143           else
144             assumed_exponent = (2 + (MPFR_GET_EXP (x)/4 + 1)
145                                 + mpfr_get_ui (tmp2_sp, MPFR_RNDU));
146         }
147       /* We do not know Ai (x) yet */
148       /* We cover the case when EXP (Ai (x))>=-10 */
149       else
150         assumed_exponent = 10;
151     }
152
153   wprec = prec + MPFR_INT_CEIL_LOG2 (prec) + 5 + cond + assumed_exponent;
154
155   mpfr_init (ti);
156   mpfr_init (tip1);
157   mpfr_init (temp1);
158   mpfr_init (temp2);
159   mpfr_init (x3);
160   mpfr_init (s);
161
162   /* ZIV loop */
163   for (;;)
164     {
165       MPFR_LOG_MSG (("Working precision: %Pu\n", wprec));
166       mpfr_set_prec (ti, wprec);
167       mpfr_set_prec (tip1, wprec);
168       mpfr_set_prec (x3, wprec);
169       mpfr_set_prec (s, wprec);
170
171       mpfr_sqr (x3, x, MPFR_RNDU);
172       mpfr_mul (x3, x3, x, (MPFR_IS_POS (x)?MPFR_RNDU:MPFR_RNDD));  /* x3=x^3 */
173       if (MPFR_IS_NEG (x))
174         MPFR_CHANGE_SIGN (x3);
175       x3u = mpfr_get_ui (x3, MPFR_RNDU);   /* x3u >= ceil(x^3) */
176       if (MPFR_IS_NEG (x))
177         MPFR_CHANGE_SIGN (x3);
178
179       mpfr_gamma_one_and_two_third (temp1, temp2, wprec);
180       mpfr_set_ui (ti, 9, MPFR_RNDN);
181       mpfr_cbrt (ti, ti, MPFR_RNDN);
182       mpfr_mul (ti, ti, temp2, MPFR_RNDN);
183       mpfr_ui_div (ti, 1, ti , MPFR_RNDN); /* ti = 1/( Gamma (2/3)*9^(1/3) ) */
184
185       mpfr_set_ui (tip1, 3, MPFR_RNDN);
186       mpfr_cbrt (tip1, tip1, MPFR_RNDN);
187       mpfr_mul (tip1, tip1, temp1, MPFR_RNDN);
188       mpfr_neg (tip1, tip1, MPFR_RNDN);
189       mpfr_div (tip1, x, tip1, MPFR_RNDN); /* tip1 = -x/(Gamma (1/3)*3^(1/3)) */
190
191       mpfr_add (s, ti, tip1, MPFR_RNDN);
192
193
194       /* Evaluation of the series */
195       k = 2;
196       for (;;)
197         {
198           mpfr_mul (ti, ti, x3, MPFR_RNDN);
199           mpfr_mul (tip1, tip1, x3, MPFR_RNDN);
200
201           mpfr_div_ui2 (ti, ti, k, (k+1), MPFR_RNDN);
202           mpfr_div_ui2 (tip1, tip1, (k+1), (k+2), MPFR_RNDN);
203
204           k += 3;
205           mpfr_add (s, s, ti, MPFR_RNDN);
206           mpfr_add (s, s, tip1, MPFR_RNDN);
207
208           /* FIXME: if s==0 */
209           test1 = MPFR_IS_ZERO (ti)
210             || (MPFR_GET_EXP (ti) + (mpfr_exp_t)prec + 3 <= MPFR_GET_EXP (s));
211           test2 = MPFR_IS_ZERO (tip1)
212             || (MPFR_GET_EXP (tip1) + (mpfr_exp_t)prec + 3 <= MPFR_GET_EXP (s));
213
214           if ( test1 && test2 && (x3u <= k*(k+1)/2) )
215             break; /* FIXME: if k*(k+1) overflows */
216         }
217
218       MPFR_LOG_MSG (("Truncation rank: %lu\n", k));
219
220       err = 4 + MPFR_INT_CEIL_LOG2 (k) + cond - MPFR_GET_EXP (s);
221
222       /* err is the number of bits lost due to the evaluation error */
223       /* wprec-(prec+1): number of bits lost due to the approximation error */
224       MPFR_LOG_MSG (("Roundoff error: %Pu\n", err));
225       MPFR_LOG_MSG (("Approxim error: %Pu\n", wprec-prec-1));
226
227       if (wprec < err+1)
228         correct_bits=0;
229       else
230         {
231           if (wprec < err+prec+1)
232             correct_bits =  wprec - err - 1;
233           else
234             correct_bits = prec;
235         }
236
237       if (MPFR_LIKELY (MPFR_CAN_ROUND (s, correct_bits, MPFR_PREC (y), rnd)))
238         break;
239
240       if (correct_bits == 0)
241         {
242           assumed_exponent *= 2;
243           MPFR_LOG_MSG (("Not a single bit correct (assumed_exponent=%lu)\n",
244                          assumed_exponent));
245           wprec = prec + 5 + MPFR_INT_CEIL_LOG2 (k) + cond + assumed_exponent;
246         }
247       else
248         {
249           if (correct_bits < prec)
250             { /* The precision was badly chosen */
251               MPFR_LOG_MSG (("Bad assumption on the exponent of Ai(x)", 0));
252               MPFR_LOG_MSG ((" (E=%ld)\n", (long) MPFR_GET_EXP (s)));
253               wprec = prec + err + 1;
254             }
255           else
256             { /* We are really in a bad case of the TMD */
257               MPFR_ZIV_NEXT (loop, prec);
258
259               /* We update wprec */
260               /* We assume that K will not be multiplied by more than 4 */
261               wprec = prec + (MPFR_INT_CEIL_LOG2 (k)+2) + 5 + cond
262                 - MPFR_GET_EXP (s);
263             }
264         }
265
266     } /* End of ZIV loop */
267
268   MPFR_ZIV_FREE (loop);
269
270   r = mpfr_set (y, s, rnd);
271
272   mpfr_clear (ti);
273   mpfr_clear (tip1);
274   mpfr_clear (temp1);
275   mpfr_clear (temp2);
276   mpfr_clear (x3);
277   mpfr_clear (s);
278   mpfr_clear (tmp_sp);
279   mpfr_clear (tmp2_sp);
280
281   MPFR_SAVE_EXPO_FREE (expo);
282   return mpfr_check_range (y, r, rnd);
283 }