| version 1.1.1.1, 2000/09/09 14:12:19 |
version 1.1.1.2, 2003/08/25 16:06:08 |
|
|
| /* mpfr_log2 -- compute natural logarithm of 2 |
/* mpfr_log2 -- log base 2 |
| |
|
| Copyright (C) 1999 PolKA project, Inria Lorraine and Loria |
Copyright 2001, 2002 Free Software Foundation, Inc. |
| |
|
| This file is part of the MPFR Library. |
This file is part of the MPFR Library. |
| |
|
| The MPFR Library is free software; you can redistribute it and/or modify |
The MPFR Library is free software; you can redistribute it and/or modify |
| it under the terms of the GNU Library General Public License as published by |
it under the terms of the GNU Lesser General Public License as published by |
| the Free Software Foundation; either version 2 of the License, or (at your |
the Free Software Foundation; either version 2.1 of the License, or (at your |
| option) any later version. |
option) any later version. |
| |
|
| The MPFR Library is distributed in the hope that it will be useful, but |
The MPFR Library is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public |
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
| License for more details. |
License for more details. |
| |
|
| You should have received a copy of the GNU Library General Public License |
You should have received a copy of the GNU Lesser General Public License |
| along with the MPFR Library; see the file COPYING.LIB. If not, write to |
along with the MPFR Library; see the file COPYING.LIB. If not, write to |
| the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, |
| MA 02111-1307, USA. */ |
MA 02111-1307, USA. */ |
| |
|
| #include <stdio.h> |
#include <stdio.h> |
| #include <math.h> |
|
| #include "gmp.h" |
#include "gmp.h" |
| #include "gmp-impl.h" |
#include "gmp-impl.h" |
| #include "longlong.h" |
|
| #include "mpfr.h" |
#include "mpfr.h" |
| |
#include "mpfr-impl.h" |
| |
|
| mpfr_t __mpfr_log2; /* stored value of log(2) with rnd_mode=GMP_RNDZ */ |
/* The computation of r=log2(a) |
| int __mpfr_log2_prec=0; /* precision of stored value */ |
|
| |
|
| /* set x to log(2) rounded to precision PREC(x) with direction rnd_mode |
r=log2(a)=log(a)/log(2) |
| |
*/ |
| |
|
| use formula log(2) = sum(1/k/2^k, k=1..infinity) |
int |
| |
mpfr_log2 (mpfr_ptr r, mpfr_srcptr a, mp_rnd_t rnd_mode) |
| |
{ |
| |
int inexact = 0; |
| |
|
| whence 2^N*log(2) = S(N) + R(N) |
/* If a is NaN, the result is NaN */ |
| |
if (MPFR_IS_NAN(a)) |
| |
{ |
| |
MPFR_SET_NAN(r); |
| |
MPFR_RET_NAN; |
| |
} |
| |
|
| where S(N) = sum(2^(N-k)/k, k=1..N-1) |
MPFR_CLEAR_NAN(r); |
| and R(N) = sum(1/k/2^(k-N), k=N..infinity) < 2/N |
|
| |
|
| Let S'(N) = sum(floor(2^(N-k)/k), k=1..N-1) |
/* check for infinity before zero */ |
| |
if (MPFR_IS_INF(a)) |
| |
{ |
| |
if (MPFR_SIGN(a) < 0) /* log(-Inf) = NaN */ |
| |
{ |
| |
MPFR_SET_NAN(r); |
| |
MPFR_RET_NAN; |
| |
} |
| |
else /* log(+Inf) = +Inf */ |
| |
{ |
| |
MPFR_SET_INF(r); |
| |
MPFR_SET_POS(r); |
| |
MPFR_RET(0); |
| |
} |
| |
} |
| |
|
| Then 2^N*log(2)-S'(N) <= N-1+2/N <= N for N>=2. |
/* Now we can clear the flags without damage even if r == a */ |
| */ |
MPFR_CLEAR_INF(r); |
| void |
|
| #if __STDC__ |
|
| mpfr_log2(mpfr_ptr x, unsigned char rnd_mode) |
|
| #else |
|
| mpfr_log2(x, rnd_mode) mpfr_ptr x; unsigned char rnd_mode; |
|
| #endif |
|
| { |
|
| int N, oldN, k, precx; mpz_t s, t, u; |
|
| |
|
| precx = PREC(x); |
if (MPFR_IS_ZERO(a)) |
| |
{ |
| |
MPFR_SET_INF(r); |
| |
MPFR_SET_NEG(r); |
| |
MPFR_RET(0); /* log2(0) is an exact -infinity */ |
| |
} |
| |
|
| /* has stored value enough precision ? */ |
/* If a is negative, the result is NaN */ |
| if (precx <= __mpfr_log2_prec) { |
if (MPFR_SIGN(a) < 0) |
| if (rnd_mode==GMP_RNDZ || rnd_mode==GMP_RNDD || |
{ |
| mpfr_can_round(__mpfr_log2, __mpfr_log2_prec, GMP_RNDZ, rnd_mode, precx)) |
MPFR_SET_NAN(r); |
| { |
MPFR_RET_NAN; |
| mpfr_set(x, __mpfr_log2, rnd_mode); return; |
} |
| } |
|
| } |
|
| |
|
| /* need to recompute */ |
/* If a is 1, the result is 0 */ |
| N=2; |
if (mpfr_cmp_ui(a, 1) == 0) |
| do { |
{ |
| oldN = N; |
MPFR_SET_ZERO(r); |
| N = precx + (int)ceil(log((double)N)/log(2.0)); |
MPFR_SET_POS(r); |
| } while (N != oldN); |
MPFR_RET(0); /* only "normal" case where the result is exact */ |
| mpz_init_set_ui(s,0); |
} |
| mpz_init(u); |
|
| mpz_init_set_ui(t,1); |
|
| #if 0 |
|
| /* use log(2) = sum(1/k/2^k, k=1..infinity) */ |
|
| mpz_mul_2exp(t, t, N); |
|
| for (k=1;k<N;k++) { |
|
| mpz_div_2exp(t, t, 1); |
|
| mpz_fdiv_q_ui(u, t, k); |
|
| mpz_add(s, s, u); |
|
| } |
|
| #else |
|
| /* use log(2) = sum((6*k-1)/(2*k^2-k)/2^(2*k+1), k=1..infinity) */ |
|
| mpz_mul_2exp(t, t, N-1); |
|
| for (k=1;k<N/2;k++) { |
|
| mpz_div_2exp(t, t, 2); |
|
| mpz_mul_ui(u, t, 6*k-1); |
|
| mpz_fdiv_q_ui(u, u, k*(2*k-1)); |
|
| mpz_add(s, s, u); |
|
| } |
|
| #endif |
|
| mpfr_set_z(x, s, rnd_mode); |
|
| EXP(x) -= N; |
|
| |
|
| /* stored computed value */ |
/* If a is integer, log2(a) is exact*/ |
| if (__mpfr_log2_prec==0) mpfr_init2(__mpfr_log2, precx); |
if (mpfr_cmp_ui_2exp(a,1,MPFR_EXP(a)-1) == 0) |
| else mpfr_set_prec(__mpfr_log2, precx); |
return mpfr_set_si(r,MPFR_EXP(a)-1,rnd_mode); |
| mpfr_set(__mpfr_log2, x, GMP_RNDZ); |
|
| __mpfr_log2_prec=precx; |
|
| |
|
| mpz_clear(s); mpz_clear(t); mpz_clear(u); |
|
| |
/* General case */ |
| |
{ |
| |
/* Declaration of the intermediary variable */ |
| |
mpfr_t t, tt; |
| |
|
| |
/* Declaration of the size variable */ |
| |
mp_prec_t Nx = MPFR_PREC(a); /* Precision of input variable */ |
| |
mp_prec_t Ny = MPFR_PREC(r); /* Precision of input variable */ |
| |
|
| |
mp_prec_t Nt; /* Precision of the intermediary variable */ |
| |
long int err; /* Precision of error */ |
| |
|
| |
|
| |
/* compute the precision of intermediary variable */ |
| |
Nt=MAX(Nx,Ny); |
| |
/* the optimal number of bits : see algorithms.ps */ |
| |
Nt=Nt+3+_mpfr_ceil_log2(Nt); |
| |
|
| |
/* initialise of intermediary variable */ |
| |
mpfr_init(t); |
| |
mpfr_init(tt); |
| |
|
| |
|
| |
/* First computation of log2 */ |
| |
do { |
| |
|
| |
/* reactualisation of the precision */ |
| |
mpfr_set_prec(t,Nt); |
| |
mpfr_set_prec(tt,Nt); |
| |
|
| |
/* compute log2 */ |
| |
mpfr_const_log2(t,GMP_RNDD); /* log(2) */ |
| |
mpfr_log(tt,a,GMP_RNDN); /* log(a) */ |
| |
mpfr_div(t,tt,t,GMP_RNDN); /* log(a)/log(2) */ |
| |
|
| |
|
| |
/* estimation of the error */ |
| |
err=Nt-3; |
| |
|
| |
/* actualisation of the precision */ |
| |
Nt += 10; |
| |
} while ((err<0) || !mpfr_can_round(t,err,GMP_RNDN,rnd_mode,Ny)); |
| |
|
| |
inexact = mpfr_set(r,t,rnd_mode); |
| |
|
| |
mpfr_clear(t); |
| |
mpfr_clear(tt); |
| |
} |
| |
return inexact; |
| } |
} |