version 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; |
} |
} |