xref: /netbsd-src/external/lgpl3/mpfr/dist/src/log2.c (revision ec6772edaf0cdcb5f52a48f4aca5e33a8fb8ecfd)
1d59437c0Smrg /* mpfr_log2 -- log base 2
2d59437c0Smrg 
3ba125506Smrg Copyright 2001-2023 Free Software Foundation, Inc.
4efdec83bSmrg Contributed by the AriC and Caramba projects, INRIA.
5d59437c0Smrg 
6d59437c0Smrg This file is part of the GNU MPFR Library.
7d59437c0Smrg 
8d59437c0Smrg The GNU MPFR Library is free software; you can redistribute it and/or modify
9d59437c0Smrg it under the terms of the GNU Lesser General Public License as published by
10d59437c0Smrg the Free Software Foundation; either version 3 of the License, or (at your
11d59437c0Smrg option) any later version.
12d59437c0Smrg 
13d59437c0Smrg The GNU MPFR Library is distributed in the hope that it will be useful, but
14d59437c0Smrg WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15d59437c0Smrg or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16d59437c0Smrg License for more details.
17d59437c0Smrg 
18d59437c0Smrg You should have received a copy of the GNU Lesser General Public License
19d59437c0Smrg along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
202ba2404bSmrg https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
21d59437c0Smrg 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
22d59437c0Smrg 
23d59437c0Smrg #define MPFR_NEED_LONGLONG_H
24d59437c0Smrg #include "mpfr-impl.h"
25d59437c0Smrg 
26d59437c0Smrg  /* The computation of r=log2(a)
27d59437c0Smrg       r=log2(a)=log(a)/log(2)      */
28d59437c0Smrg 
29d59437c0Smrg int
mpfr_log2(mpfr_ptr r,mpfr_srcptr a,mpfr_rnd_t rnd_mode)30d59437c0Smrg mpfr_log2 (mpfr_ptr r, mpfr_srcptr a, mpfr_rnd_t rnd_mode)
31d59437c0Smrg {
32d59437c0Smrg   int inexact;
33d59437c0Smrg   MPFR_SAVE_EXPO_DECL (expo);
34d59437c0Smrg 
35d59437c0Smrg   MPFR_LOG_FUNC
36*ec6772edSmrg     (("a[%Pd]=%.*Rg rnd=%d", mpfr_get_prec (a), mpfr_log_prec, a, rnd_mode),
37*ec6772edSmrg      ("r[%Pd]=%.*Rg inexact=%d", mpfr_get_prec (r), mpfr_log_prec, r,
38d59437c0Smrg       inexact));
39d59437c0Smrg 
40d59437c0Smrg   if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (a)))
41d59437c0Smrg     {
42d59437c0Smrg       /* If a is NaN, the result is NaN */
43d59437c0Smrg       if (MPFR_IS_NAN (a))
44d59437c0Smrg         {
45d59437c0Smrg           MPFR_SET_NAN (r);
46d59437c0Smrg           MPFR_RET_NAN;
47d59437c0Smrg         }
48d59437c0Smrg       /* check for infinity before zero */
49d59437c0Smrg       else if (MPFR_IS_INF (a))
50d59437c0Smrg         {
51d59437c0Smrg           if (MPFR_IS_NEG (a))
52d59437c0Smrg             /* log(-Inf) = NaN */
53d59437c0Smrg             {
54d59437c0Smrg               MPFR_SET_NAN (r);
55d59437c0Smrg               MPFR_RET_NAN;
56d59437c0Smrg             }
57d59437c0Smrg           else /* log(+Inf) = +Inf */
58d59437c0Smrg             {
59d59437c0Smrg               MPFR_SET_INF (r);
60d59437c0Smrg               MPFR_SET_POS (r);
61d59437c0Smrg               MPFR_RET (0);
62d59437c0Smrg             }
63d59437c0Smrg         }
64d59437c0Smrg       else /* a is zero */
65d59437c0Smrg         {
66d59437c0Smrg           MPFR_ASSERTD (MPFR_IS_ZERO (a));
67d59437c0Smrg           MPFR_SET_INF (r);
68d59437c0Smrg           MPFR_SET_NEG (r);
69299c6f0cSmrg           MPFR_SET_DIVBY0 ();
70d59437c0Smrg           MPFR_RET (0); /* log2(0) is an exact -infinity */
71d59437c0Smrg         }
72d59437c0Smrg     }
73d59437c0Smrg 
74d59437c0Smrg   /* If a is negative, the result is NaN */
75d59437c0Smrg   if (MPFR_UNLIKELY (MPFR_IS_NEG (a)))
76d59437c0Smrg     {
77d59437c0Smrg       MPFR_SET_NAN (r);
78d59437c0Smrg       MPFR_RET_NAN;
79d59437c0Smrg     }
80d59437c0Smrg 
81d59437c0Smrg   /* If a is 1, the result is 0 */
82d59437c0Smrg   if (MPFR_UNLIKELY (mpfr_cmp_ui (a, 1) == 0))
83d59437c0Smrg     {
84d59437c0Smrg       MPFR_SET_ZERO (r);
85d59437c0Smrg       MPFR_SET_POS (r);
86d59437c0Smrg       MPFR_RET (0); /* only "normal" case where the result is exact */
87d59437c0Smrg     }
88d59437c0Smrg 
89d59437c0Smrg   /* If a is 2^N, log2(a) is exact*/
90d59437c0Smrg   if (MPFR_UNLIKELY (mpfr_cmp_ui_2exp (a, 1, MPFR_GET_EXP (a) - 1) == 0))
91d59437c0Smrg     return mpfr_set_si(r, MPFR_GET_EXP (a) - 1, rnd_mode);
92d59437c0Smrg 
93d59437c0Smrg   MPFR_SAVE_EXPO_MARK (expo);
94d59437c0Smrg 
95d59437c0Smrg   /* General case */
96d59437c0Smrg   {
97d59437c0Smrg     /* Declaration of the intermediary variable */
98d59437c0Smrg     mpfr_t t, tt;
99d59437c0Smrg     /* Declaration of the size variable */
100d59437c0Smrg     mpfr_prec_t Ny = MPFR_PREC(r);              /* target precision */
101d59437c0Smrg     mpfr_prec_t Nt;                             /* working precision */
102d59437c0Smrg     mpfr_exp_t err;                             /* error */
103d59437c0Smrg     MPFR_ZIV_DECL (loop);
104d59437c0Smrg 
105d59437c0Smrg     /* compute the precision of intermediary variable */
106d59437c0Smrg     /* the optimal number of bits : see algorithms.tex */
107d59437c0Smrg     Nt = Ny + 3 + MPFR_INT_CEIL_LOG2 (Ny);
108d59437c0Smrg 
109299c6f0cSmrg     /* initialize of intermediary       variable */
110d59437c0Smrg     mpfr_init2 (t, Nt);
111d59437c0Smrg     mpfr_init2 (tt, Nt);
112d59437c0Smrg 
113d59437c0Smrg     /* First computation of log2 */
114d59437c0Smrg     MPFR_ZIV_INIT (loop, Nt);
115d59437c0Smrg     for (;;)
116d59437c0Smrg       {
117d59437c0Smrg         /* compute log2 */
118d59437c0Smrg         mpfr_const_log2(t,MPFR_RNDD); /* log(2) */
119d59437c0Smrg         mpfr_log(tt,a,MPFR_RNDN);     /* log(a) */
120d59437c0Smrg         mpfr_div(t,tt,t,MPFR_RNDN); /* log(a)/log(2) */
121d59437c0Smrg 
122d59437c0Smrg         /* estimation of the error */
123d59437c0Smrg         err = Nt-3;
124d59437c0Smrg         if (MPFR_LIKELY (MPFR_CAN_ROUND (t, err, Ny, rnd_mode)))
125d59437c0Smrg           break;
126d59437c0Smrg 
127299c6f0cSmrg         /* actualization of the precision */
128d59437c0Smrg         MPFR_ZIV_NEXT (loop, Nt);
129d59437c0Smrg         mpfr_set_prec (t, Nt);
130d59437c0Smrg         mpfr_set_prec (tt, Nt);
131d59437c0Smrg       }
132d59437c0Smrg     MPFR_ZIV_FREE (loop);
133d59437c0Smrg 
134d59437c0Smrg     inexact = mpfr_set (r, t, rnd_mode);
135d59437c0Smrg 
136d59437c0Smrg     mpfr_clear (t);
137d59437c0Smrg     mpfr_clear (tt);
138d59437c0Smrg   }
139d59437c0Smrg 
140d59437c0Smrg   MPFR_SAVE_EXPO_FREE (expo);
141d59437c0Smrg   return mpfr_check_range (r, inexact, rnd_mode);
142d59437c0Smrg }
143