summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile.am2
-rw-r--r--ai.c48
-rw-r--r--ai2.c323
-rw-r--r--gammaonethird.c174
-rw-r--r--mpfr.h1
5 files changed, 518 insertions, 30 deletions
diff --git a/Makefile.am b/Makefile.am
index c85ae7cc6..dc8440bee 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -55,7 +55,7 @@ round_near_x.c constant.c abort_prec_max.c stack_interface.c lngamma.c \
zeta_ui.c set_d64.c get_d64.c jn.c yn.c rem1.c get_patches.c add_d.c \
sub_d.c d_sub.c mul_d.c div_d.c d_div.c li2.c rec_sqrt.c min_prec.c \
buildopt.c digamma.c bernoulli.c isregular.c set_flt.c get_flt.c \
-scale2.c set_z_exp.c ai.c
+scale2.c set_z_exp.c ai.c ai2.c gammaonethird.c
libmpfr_la_LIBADD = @LIBOBJS@
diff --git a/ai.c b/ai.c
index 6e053d23e..a26015771 100644
--- a/ai.c
+++ b/ai.c
@@ -23,7 +23,12 @@ http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
#define MPFR_NEED_LONGLONG_H
#include "mpfr-impl.h"
-#define MPFR_SMALL_PRECISION MPFR_PREC_MIN
+#define MPFR_SMALL_PRECISION 32
+
+/* These functions are provided by file gammaonethird.c */
+int mpfr_gamma_one_and_two_third (mpfr_ptr, mpfr_ptr, mp_prec_t);
+void mpfr_div_ui2 (mpfr_ptr, mpfr_srcptr, unsigned long int, unsigned long int, mpfr_rnd_t);
+
/* Reminder and notations:
-----------------------
@@ -66,7 +71,7 @@ mpfr_ai (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd)
mpfr_t x3; /* used to store x^3 */
mpfr_t tmp_sp, tmp2_sp; /* small precision variables */
unsigned long int x3u; /* used to store ceil(x^3) */
- mpfr_t temp;
+ mpfr_t temp1, temp2;
int test1, test2;
/* Logging */
@@ -142,7 +147,8 @@ mpfr_ai (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd)
mpfr_init (ti);
mpfr_init (tip1);
- mpfr_init (temp);
+ mpfr_init (temp1);
+ mpfr_init (temp2);
mpfr_init (x3);
mpfr_init (s);
@@ -152,7 +158,6 @@ mpfr_ai (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd)
MPFR_LOG_MSG (("Working precision: %d\n", wprec, 0));
mpfr_set_prec (ti, wprec);
mpfr_set_prec (tip1, wprec);
- mpfr_set_prec (temp, wprec+4);
mpfr_set_prec (x3, wprec);
mpfr_set_prec (s, wprec);
@@ -162,23 +167,17 @@ mpfr_ai (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd)
x3u = mpfr_get_ui (x3, MPFR_RNDU); /* x3u >= ceil(x^3) */
if (MPFR_IS_NEG (x)) MPFR_CHANGE_SIGN (x3);
-
+ mpfr_gamma_one_and_two_third (temp1, temp2, wprec);
mpfr_set_ui (ti, 9, MPFR_RNDN);
mpfr_cbrt (ti, ti, MPFR_RNDN);
- mpfr_set_ui (temp, 2, MPFR_RNDN);
- mpfr_div_ui (temp, temp, 3, MPFR_RNDN);
- mpfr_gamma (temp, temp, MPFR_RNDN);
- mpfr_mul (ti, ti, temp, MPFR_RNDN);
- mpfr_ui_div (ti, 1, ti , MPFR_RNDN); /* ti = 1 / ( Gamma(2/3)*9^(1/3) ) */
+ mpfr_mul (ti, ti, temp2, MPFR_RNDN);
+ mpfr_ui_div (ti, 1, ti , MPFR_RNDN); /* ti = 1 / ( Gamma (2/3)*9^(1/3) ) */
mpfr_set_ui (tip1, 3, MPFR_RNDN);
mpfr_cbrt (tip1, tip1, MPFR_RNDN);
- mpfr_set_ui (temp, 1, MPFR_RNDN);
- mpfr_div_ui (temp, temp, 3, MPFR_RNDN);
- mpfr_gamma (temp, temp, MPFR_RNDN);
- mpfr_mul (tip1, tip1, temp, MPFR_RNDN);
+ mpfr_mul (tip1, tip1, temp1, MPFR_RNDN);
mpfr_neg (tip1, tip1, MPFR_RNDN);
- mpfr_div (tip1, x, tip1, MPFR_RNDN); /* tip1 = -x/(Gamma(1/3)*3^(1/3)) */
+ mpfr_div (tip1, x, tip1, MPFR_RNDN); /* tip1 = -x/(Gamma (1/3)*3^(1/3)) */
mpfr_add (s, ti, tip1, MPFR_RNDN);
@@ -190,18 +189,8 @@ mpfr_ai (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd)
mpfr_mul (ti, ti, x3, MPFR_RNDN);
mpfr_mul (tip1, tip1, x3, MPFR_RNDN);
- if (k+2 <= ULONG_MAX/(k+1))
- {
- mpfr_div_ui (ti, ti, k*(k+1), MPFR_RNDN);
- mpfr_div_ui (tip1, tip1, (k+1)*(k+2), MPFR_RNDN);
- }
- else
- {
- mpfr_div_ui (ti, ti, k, MPFR_RNDN);
- mpfr_div_ui (ti, ti, k+1, MPFR_RNDN);
- mpfr_div_ui (tip1, tip1, k+1, MPFR_RNDN);
- mpfr_div_ui (tip1, tip1, k+2, MPFR_RNDN);
- }
+ mpfr_div_ui2 (ti, ti, k, (k+1), MPFR_RNDN);
+ mpfr_div_ui2 (tip1, tip1, (k+1), (k+2), MPFR_RNDN);
k += 3;
mpfr_add (s, s, ti, MPFR_RNDN);
@@ -249,7 +238,7 @@ mpfr_ai (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd)
{
if (correct_bits < prec)
{ /* The precision was badly chosen */
- MPFR_LOG_MSG (("Bad assumption on the exponent of Ai(x) (E=%d)\n",MPFR_EXP (s), 0));
+ MPFR_LOG_MSG (("Bad assumption on the exponent of Ai(x) (E=%d)\n", MPFR_EXP (s), 0));
wprec = prec + err + 1;
}
else
@@ -272,7 +261,8 @@ mpfr_ai (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd)
mpfr_clear (ti);
mpfr_clear (tip1);
- mpfr_clear (temp);
+ mpfr_clear (temp1);
+ mpfr_clear (temp2);
mpfr_clear (x3);
mpfr_clear (s);
mpfr_clear (tmp_sp);
diff --git a/ai2.c b/ai2.c
new file mode 100644
index 000000000..e9762956a
--- /dev/null
+++ b/ai2.c
@@ -0,0 +1,323 @@
+/* mpfr_ai2 -- implementation of Airy Ai function by Smith algorithm.
+
+Copyright 2010 Free Software Foundation, Inc.
+Contributed by the Arenaire and Cacao projects, INRIA.
+
+This file is part of the GNU MPFR Library.
+
+The GNU MPFR Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+The GNU MPFR Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see
+http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
+51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#define MPFR_NEED_LONGLONG_H
+#include <mpfr-impl.h>
+
+#define SMALL_PRECISION 32
+
+/* These functions are provided by file gammaonethird.c */
+int mpfr_gamma_one_and_two_third (mpfr_ptr, mpfr_ptr, mp_prec_t);
+void mpfr_div_ui2 (mpfr_ptr, mpfr_srcptr, unsigned long int, unsigned long int, mpfr_rnd_t);
+
+
+unsigned long isqrt (unsigned long n)
+{
+ mpz_t tmp;
+ unsigned int res;
+ mpz_init (tmp);
+ mpz_set_ui (tmp, n);
+ mpz_sqrt (tmp, tmp);
+ res = mpz_get_ui (tmp);
+ mpz_clear (tmp);
+ return res;
+}
+
+/* Reminder and notations:
+ -----------------------
+
+ Ai is the solution of:
+ / y'' - x*y = 0
+ { Ai (0) = 1/ ( 9^(1/3) * Gamma (2/3) )
+ \ Ai' (0) = -1/ ( 3^(1/3) * Gamma (1/3) )
+
+ Series development:
+ Ai (x) = sum (a_i*x^i)
+ = sum (t_i)
+
+ Recurrences:
+ a_(i+3) = a_i / ((i+2)*(i+3))
+ t_(i+3) = t_i * x^3 / ((i+2)*(i+3))
+
+ Values:
+ a_0 = Ai (0) ~ 0.355
+ a_1 = Ai' (0) ~ -0.259
+*/
+
+
+/* Airy function Ai evaluated by Smith algorithm */
+int
+mpfr_ai2 (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd)
+{
+ MPFR_ZIV_DECL (loop);
+ MPFR_SAVE_EXPO_DECL (expo);
+ mpfr_prec_t wprec; /* working precision */
+ mpfr_prec_t prec; /* target precision */
+ mpfr_prec_t err; /* used to estimate the evaluation error */
+ mpfr_prec_t correctBits; /* estimates the number of correct bits*/
+ unsigned long int i, j, k, L, t;
+ unsigned long int cond; /* condition number of the series */
+ unsigned assumedExp; /* used as a lowerbound of |EXP (Ai (x))| */
+ int r; /* returned ternary value */
+ mpfr_t s; /* used to store the partial sum */
+ mpfr_t u0, u1;
+ mpfr_t *z; /* used to store the (x^3j) */
+ mpfr_t result;
+ mpfr_t tmp_sp, tmp2_sp; /* small precision variables */
+ unsigned long int x3u; /* used to store ceil (x^3) */
+ mpfr_t temp1, temp2;
+ int test0, test1;
+
+ /* Logging */
+ MPFR_LOG_FUNC ( ("x[%#R]=%R rnd=%d", x, x, rnd), ("y[%#R]=%R", y, y) );
+
+ /* Special cases */
+ if (MPFR_UNLIKELY (MPFR_IS_NAN (x))) { MPFR_SET_NAN (y); MPFR_RET_NAN; }
+ if (MPFR_UNLIKELY (MPFR_IS_INF (x))) { return mpfr_set_ui (y, 0, rnd); }
+
+ /* Save current exponents range */
+ MPFR_SAVE_EXPO_MARK (expo);
+
+ /* FIXME: underflow for large values of |x| */
+
+
+ /* Set initial precision */
+ /* See the analysis for the naive evaluation */
+
+ /* We begin with 11 guard bits */
+ prec = MPFR_PREC (y) + 11;
+ MPFR_ZIV_INIT (loop, prec);
+
+ mpfr_init2 (tmp_sp, SMALL_PRECISION);
+ mpfr_init2 (tmp2_sp, SMALL_PRECISION);
+ mpfr_abs (tmp_sp, x, MPFR_RNDU);
+ mpfr_pow_ui (tmp_sp, tmp_sp, 3, MPFR_RNDU);
+ mpfr_sqrt (tmp_sp, tmp_sp, MPFR_RNDU); /* tmp_sp ~ x^3/2 */
+
+ /* 0.96179669392597567 >~ 2/3 * log2(e). See algorithms.tex */
+ mpfr_mul_d (tmp2_sp, tmp_sp, 0.96179669392597567, MPFR_RNDU);
+
+ /* cond represents the number of lost bits in the evaluation of the sum */
+ if (MPFR_EXP (x) <= 0 ) cond = 0;
+ else cond = mpfr_get_ui (tmp2_sp, MPFR_RNDU) - (MPFR_EXP (x) - 1)/4 - 1;
+
+ /* This variable is used to store the maximal assumed exponent of */
+ /* Ai (x). More precisely, we assume that |Ai (x)| will be greater than */
+ /* 2^{-assumedExp}. */
+ if (MPFR_IS_POS (x))
+ {
+ if (MPFR_EXP (x) <= 0) assumedExp = 3;
+ else assumedExp = 2 + (MPFR_EXP (x)/4 + 1) + mpfr_get_ui (tmp2_sp, MPFR_RNDU);
+ }
+ /* We do not know Ai (x) yet */
+ /* We cover the case when EXP (Ai (x))>=-10 */
+ else assumedExp = 10;
+
+ wprec = prec + MPFR_INT_CEIL_LOG2 (prec) + 6 + cond + assumedExp;
+
+ /* We assume that the truncation rank will be ~ prec */
+ L = isqrt (prec);
+ MPFR_LOG_MSG (("size of blocks L = %d\n", L, 0));
+
+ z = (mpfr_t *) (*__gmp_allocate_func) ( (L + 1) * sizeof (mpfr_t) );
+ MPFR_ASSERTN (z != NULL);
+ for (j=0; j<=L; j++) mpfr_init (z[j]);
+
+ mpfr_init (s);
+ mpfr_init (u0); mpfr_init (u1);
+ mpfr_init (result);
+ mpfr_init (temp1);
+ mpfr_init (temp2);
+
+ /* ZIV loop */
+ for (;;)
+ {
+ MPFR_LOG_MSG (("working precision: %d\n", wprec, 0));
+
+ for (j=0; j<=L; j++) mpfr_set_prec (z[j], wprec);
+ mpfr_set_prec (s, wprec);
+ mpfr_set_prec (u0, wprec); mpfr_set_prec (u1, wprec);
+ mpfr_set_prec (result, wprec);
+
+ mpfr_set_ui (u0, 1, MPFR_RNDN);
+ mpfr_set (u1, x, MPFR_RNDN);
+
+ mpfr_set_ui (z[0], 1, MPFR_RNDU);
+ mpfr_sqr (z[1], u1, MPFR_RNDU);
+ mpfr_mul (z[1], z[1], x, (MPFR_IS_POS (x) ? MPFR_RNDU : MPFR_RNDD) );
+
+ if (MPFR_IS_NEG (x)) MPFR_CHANGE_SIGN (z[1]);
+ x3u = mpfr_get_ui (z[1], MPFR_RNDU); /* x3u >= ceil (x^3) */
+ if (MPFR_IS_NEG (x)) MPFR_CHANGE_SIGN (z[1]);
+
+ for (j=2; j<=L ;j++)
+ {
+ if (j%2 == 0) mpfr_sqr (z[j], z[j/2], MPFR_RNDN);
+ else mpfr_mul (z[j], z[j-1], z[1], MPFR_RNDN);
+ }
+
+ mpfr_gamma_one_and_two_third (temp1, temp2, wprec);
+ mpfr_set_ui (u0, 9, MPFR_RNDN);
+ mpfr_cbrt (u0, u0, MPFR_RNDN);
+ mpfr_mul (u0, u0, temp2, MPFR_RNDN);
+ mpfr_ui_div (u0, 1, u0 , MPFR_RNDN); /* u0 = 1 / ( Gamma (2/3)*9^(1/3) ) */
+
+ mpfr_set_ui (u1, 3, MPFR_RNDN);
+ mpfr_cbrt (u1, u1, MPFR_RNDN);
+ mpfr_mul (u1, u1, temp1, MPFR_RNDN);
+ mpfr_neg (u1, u1, MPFR_RNDN);
+ mpfr_div (u1, x, u1, MPFR_RNDN); /* u1 = -x/(Gamma (1/3)*3^(1/3)) */
+
+ mpfr_set_ui (result, 0, MPFR_RNDN);
+ t = 0;
+
+ /* Evaluation of the series by Smith' method */
+ for (i=0; ; i++)
+ {
+ t += 3 * L;
+
+ /* k = 0 */
+ t -= 3;
+ mpfr_set (s, z[L-1], MPFR_RNDN);
+ for (j=L-2; ; j--)
+ {
+ t -= 3;
+ mpfr_div_ui2 (s, s, (t+2), (t+3), MPFR_RNDN);
+ mpfr_add (s, s, z[j], MPFR_RNDN);
+ if (j==0) break;
+ }
+ mpfr_mul (s, s, u0, MPFR_RNDN);
+ mpfr_add (result, result, s, MPFR_RNDN);
+
+ mpfr_mul (u0, u0, z[L], MPFR_RNDN);
+ for (j=0; j<=L-1; j++)
+ {
+ mpfr_div_ui2 (u0, u0, (t + 2), (t + 3), MPFR_RNDN);
+ t += 3;
+ }
+
+ t++;
+
+ /* k = 1 */
+ t -= 3;
+ mpfr_set (s, z[L-1], MPFR_RNDN);
+ for (j=L-2; ; j--)
+ {
+ t -= 3;
+ mpfr_div_ui2 (s, s, (t + 2), (t + 3), MPFR_RNDN);
+ mpfr_add (s, s, z[j], MPFR_RNDN);
+ if (j==0) break;
+ }
+ mpfr_mul (s, s, u1, MPFR_RNDN);
+ mpfr_add (result, result, s, MPFR_RNDN);
+
+ mpfr_mul (u1, u1, z[L], MPFR_RNDN);
+ for (j=0; j<=L-1; j++)
+ {
+ mpfr_div_ui2 (u1, u1, (t + 2), (t + 3), MPFR_RNDN);
+ t += 3;
+ }
+
+ t++;
+
+ /* k = 2 */
+ t++;
+
+ /* End of the loop over k */
+ t -= 3;
+
+ test0 = MPFR_IS_ZERO (u0) ||
+ (MPFR_EXP (u0) + (mp_exp_t)prec + 4 <= MPFR_EXP (result));
+ test1 = MPFR_IS_ZERO (u1) ||
+ (MPFR_EXP (u1) + (mp_exp_t)prec + 4 <= MPFR_EXP (result));
+
+ if ( test0 && test1 && (x3u <= (t + 2) * (t + 3) / 2) ) break;
+ }
+
+ MPFR_LOG_MSG (("Truncation rank: %d\n", t, 0));
+
+ err = 5 + MPFR_INT_CEIL_LOG2 (L+1) + MPFR_INT_CEIL_LOG2 (i+1) + cond - MPFR_EXP (result);
+
+ /* err is the number of bits lost due to the evaluation error */
+ /* wprec-(prec+1): the number of bits lost due to the approximation error */
+ MPFR_LOG_MSG (("Roundoff error: %d\n", err, 0));
+ MPFR_LOG_MSG (("Approxim error: %d\n", wprec - prec - 1, 0));
+
+ if (wprec < err+1) correctBits = 0;
+ else
+ {
+ if (wprec < err+prec+1) correctBits = (unsigned) ( (signed)wprec - (signed)err - 1);
+ else correctBits = prec;
+ }
+
+ if (MPFR_LIKELY (MPFR_CAN_ROUND (result, correctBits, MPFR_PREC (y), rnd))) break;
+
+ for (j=0; j<=L; j++) mpfr_clear (z[j]);
+ (*__gmp_free_func) (z, (L + 1) * sizeof (mpfr_t));
+ L = isqrt (t);
+ MPFR_LOG_MSG (("size of blocks L = %d\n", L, 0));
+ z = (mpfr_t *) (*__gmp_allocate_func) ( (L + 1) * sizeof (mpfr_t));
+ MPFR_ASSERTN (z != NULL);
+ for (j=0; j<=L; j++) mpfr_init (z[j]);
+
+ if (correctBits == 0)
+ {
+ assumedExp *= 2;
+ MPFR_LOG_MSG (("Not a single bit correct (assumedExp=%d)\n", 0));
+ wprec = prec + 6 + MPFR_INT_CEIL_LOG2 (t) + cond + assumedExp;
+ }
+ else
+ {
+ if (correctBits < prec)
+ { /* The precision was badly chosen */
+ MPFR_LOG_MSG (("Bad assumption on the exponent of Ai (x) (E=%d)\n", MPFR_EXP (result), 0));
+ wprec = prec + err + 1;
+ }
+ else
+ { /* We are really in a bad case of the TMD */
+ MPFR_ZIV_NEXT (loop, prec);
+
+ /* We update wprec */
+ /* We assume that t will not be multiplied by more than 4 */
+ wprec = prec + (MPFR_INT_CEIL_LOG2 (t) + 2) + 6 + cond - MPFR_EXP (result);
+ }
+ }
+ } /* End of ZIV loop */
+
+ MPFR_ZIV_FREE (loop);
+ MPFR_SAVE_EXPO_FREE (expo);
+
+ r = mpfr_set (y, result, rnd);
+
+ mpfr_clear (tmp_sp);
+ mpfr_clear (tmp2_sp);
+ for (j=0; j<=L; j++) mpfr_clear (z[j]);
+ (*__gmp_free_func) (z, (L + 1) * sizeof (mpfr_t));
+
+ mpfr_clear (s);
+ mpfr_clear (u0); mpfr_clear (u1);
+ mpfr_clear (result);
+ mpfr_clear (temp1);
+ mpfr_clear (temp2);
+
+ return r;
+}
diff --git a/gammaonethird.c b/gammaonethird.c
new file mode 100644
index 000000000..628471e71
--- /dev/null
+++ b/gammaonethird.c
@@ -0,0 +1,174 @@
+/* Functions for evaluating Gamma(1/3) and Gamma(2/3). Used by mpfr_ai.
+
+Copyright 2010 Free Software Foundation, Inc.
+Contributed by the Arenaire and Cacao projects, INRIA.
+
+This file is part of the GNU MPFR Library.
+
+The GNU MPFR Library is free software; you can redistribute it and/or modify
+it under the terms of the GNU Lesser General Public License as published by
+the Free Software Foundation; either version 3 of the License, or (at your
+option) any later version.
+
+The GNU MPFR Library is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
+License for more details.
+
+You should have received a copy of the GNU Lesser General Public License
+along with the GNU MPFR Library; see the file COPYING.LESSER. If not, see
+http://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
+51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#define MPFR_NEED_LONGLONG_H
+#include <mpfr-impl.h>
+
+#define MPFR_ACC_OR_MUL(v) \
+ if (v <= ULONG_MAX / acc) acc *= v; \
+ else { mpfr_mul_ui (y, y, acc, mode); acc = v; }
+
+#define MPFR_ACC_OR_DIV(v) \
+ if (v <= ULONG_MAX / acc) acc *= v; \
+ else { mpfr_div_ui (y, y, acc, mode); acc = v; }
+
+void
+mpfr_mul_ui5 (mpfr_ptr y, mpfr_srcptr x,
+ unsigned long int v1, unsigned long int v2,
+ unsigned long int v3, unsigned long int v4,
+ unsigned long int v5, mpfr_rnd_t mode)
+{
+ unsigned long int acc = v1;
+ mpfr_set (y, x, mode);
+ MPFR_ACC_OR_MUL (v2);
+ MPFR_ACC_OR_MUL (v3);
+ MPFR_ACC_OR_MUL (v4);
+ MPFR_ACC_OR_MUL (v5);
+ mpfr_mul_ui (y, y, acc, mode);
+}
+
+void
+mpfr_div_ui2 (mpfr_ptr y, mpfr_srcptr x,
+ unsigned long int v1, unsigned long int v2, mpfr_rnd_t mode)
+{
+ unsigned long int acc = v1;
+ mpfr_set (y, x, mode);
+ MPFR_ACC_OR_DIV (v2);
+ mpfr_div_ui (y, y, acc, mode);
+}
+
+void
+mpfr_div_ui8 (mpfr_ptr y, mpfr_srcptr x,
+ unsigned long int v1, unsigned long int v2,
+ unsigned long int v3, unsigned long int v4,
+ unsigned long int v5, unsigned long int v6,
+ unsigned long int v7, unsigned long int v8, mpfr_rnd_t mode)
+{
+ unsigned long int acc = v1;
+ mpfr_set (y, x, mode);
+ MPFR_ACC_OR_DIV (v2);
+ MPFR_ACC_OR_DIV (v3);
+ MPFR_ACC_OR_DIV (v4);
+ MPFR_ACC_OR_DIV (v5);
+ MPFR_ACC_OR_DIV (v6);
+ MPFR_ACC_OR_DIV (v7);
+ MPFR_ACC_OR_DIV (v8);
+ mpfr_div_ui (y, y, acc, mode);
+}
+
+
+/* Gives an approximation of omega = Gamma(1/3)^6 * sqrt(10) / (12pi^4) */
+/* using C. H. Brown's formula. */
+/* The computed value s satisfies |s-omega| <= 2^{1-prec}*omega */
+/* As usual, the variable s is supposed to be initialized. */
+mpfr_Browns_const (mpfr_ptr s, mp_prec_t prec)
+{
+ mpfr_t uk;
+ unsigned long int k;
+
+ mp_prec_t working_prec = prec + 10 + MPFR_INT_CEIL_LOG2 (2 + prec / 10);
+
+ mpfr_init2 (uk, working_prec);
+ mpfr_set_prec (s, working_prec);
+
+ mpfr_set_ui (uk, 1, MPFR_RNDN);
+ mpfr_set (s, uk, MPFR_RNDN);
+ k = 1;
+
+ /* Invariants: uk ~ u(k-1) and s ~ sum(i=0..k-1, u(i)) */
+ for (;;)
+ {
+ mpfr_mul_ui5 (uk, uk, 6 * k - 5, 6 * k - 4, 6 * k - 3, 6 * k - 2,
+ 6 * k - 1, MPFR_RNDN);
+ mpfr_div_ui8 (uk, uk, k, k, 3 * k - 2, 3 * k - 1, 3 * k, 80, 160, 160,
+ MPFR_RNDN);
+ MPFR_CHANGE_SIGN (uk);
+
+ mpfr_add (s, s, uk, MPFR_RNDN);
+ k++;
+ if (MPFR_EXP (uk) + (signed) prec <= MPFR_EXP (s) + 7)
+ break;
+ }
+
+ mpfr_clear (uk);
+ return;
+}
+
+/* Returns y such that |Gamma(1/3)-y| <= 2^{1-prec}*Gamma(1/3) */
+int
+mpfr_gamma_one_third (mpfr_ptr y, mp_prec_t prec)
+{
+ mpfr_t tmp, tmp2, tmp3;
+
+ mpfr_init2 (tmp, prec + 9);
+ mpfr_init2 (tmp2, prec + 9);
+ mpfr_init2 (tmp3, prec + 4);
+ mpfr_set_prec (y, prec + 2);
+
+ mpfr_const_pi (tmp, MPFR_RNDN);
+ mpfr_sqr (tmp, tmp, MPFR_RNDN);
+ mpfr_sqr (tmp, tmp, MPFR_RNDN);
+ mpfr_mul_ui (tmp, tmp, 12, MPFR_RNDN);
+
+ mpfr_Browns_const (tmp2, prec + 9);
+ mpfr_mul (tmp, tmp, tmp2, MPFR_RNDN);
+
+ mpfr_set_ui (tmp2, 10, MPFR_RNDN);
+ mpfr_sqrt (tmp2, tmp2, MPFR_RNDN);
+ mpfr_div (tmp, tmp, tmp2, MPFR_RNDN);
+
+ mpfr_sqrt (tmp3, tmp, MPFR_RNDN);
+ mpfr_cbrt (y, tmp3, MPFR_RNDN);
+
+ mpfr_clear (tmp);
+ mpfr_clear (tmp2);
+ mpfr_clear (tmp3);
+ return;
+}
+
+/* Computes y1 and y2 such that: */
+/* |y1-Gamma(1/3)| <= 2^{1-prec}Gamma(1/3) */
+/* and |y2-Gamma(2/3)| <= 2^{1-prec}Gamma(2/3) */
+/* */
+/* Uses the formula Gamma(z)Gamma(1-z) = pi / sin(pi*z) */
+/* to compute Gamma(2/3) from Gamma(1/3). */
+int
+mpfr_gamma_one_and_two_third (mpfr_ptr y1, mpfr_ptr y2, mp_prec_t prec)
+{
+ mpfr_t temp;
+
+ mpfr_init2 (temp, prec + 4);
+ mpfr_set_prec (y2, prec + 4);
+
+ mpfr_gamma_one_third (y1, prec + 4);
+
+ mpfr_set_ui (temp, 3, MPFR_RNDN);
+ mpfr_sqrt (temp, temp, MPFR_RNDN);
+ mpfr_mul (temp, y1, temp, MPFR_RNDN);
+
+ mpfr_const_pi (y2, MPFR_RNDN);
+ mpfr_mul_2ui (y2, y2, 1, MPFR_RNDN);
+
+ mpfr_div (y2, y2, temp, MPFR_RNDN);
+
+ mpfr_clear (temp);
+}
diff --git a/mpfr.h b/mpfr.h
index c66f78776..bc7b575d8 100644
--- a/mpfr.h
+++ b/mpfr.h
@@ -659,6 +659,7 @@ __MPFR_DECLSPEC int mpfr_yn _MPFR_PROTO ((mpfr_ptr, long, mpfr_srcptr,
mpfr_rnd_t));
__MPFR_DECLSPEC int mpfr_ai _MPFR_PROTO ((mpfr_ptr, mpfr_srcptr, mpfr_rnd_t));
+__MPFR_DECLSPEC int mpfr_ai2 _MPFR_PROTO ((mpfr_ptr, mpfr_srcptr, mpfr_rnd_t));
__MPFR_DECLSPEC int mpfr_min _MPFR_PROTO ((mpfr_ptr, mpfr_srcptr, mpfr_srcptr,
mpfr_rnd_t));