xref: /netbsd-src/external/lgpl3/mpfr/dist/src/log2p1.c (revision ec6772edaf0cdcb5f52a48f4aca5e33a8fb8ecfd)
1 /* mpfr_log2p1 -- Compute log2(1+x)
2 
3 Copyright 2001-2023 Free Software Foundation, Inc.
4 Contributed by the AriC and Caramba 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 https://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 /* needed for MPFR_INT_CEIL_LOG2 */
24 #include "mpfr-impl.h"
25 
26 #define ULSIZE (sizeof (unsigned long) * CHAR_BIT)
27 
28 /* return non-zero if log2(1+x) is exactly representable in infinite precision,
29    and in such case the returned value is k such that 1+x = 2^k (the case k=0
30    cannot happen since we assume x<>0) */
31 static mpfr_exp_t
mpfr_log2p1_isexact(mpfr_srcptr x)32 mpfr_log2p1_isexact (mpfr_srcptr x)
33 {
34   /* log2(1+x) is exactly representable when 1+x is a power of two,
35      we thus simply compute 1+x with 1-bit precision and check whether
36      the addition is exact. This routine is called with extended exponent
37      range, thus no need to extend it. */
38   mpfr_t t;
39   int inex;
40   mpfr_exp_t e;
41 
42   mpfr_init2 (t, 1);
43   inex = mpfr_add_ui (t, x, 1, MPFR_RNDZ);
44   e = MPFR_GET_EXP (t);
45   mpfr_clear (t);
46   return inex == 0 ? e - 1 : 0;
47 }
48 
49 /* in case x=2^k and we can decide of the correct rounding,
50    put the correctly-rounded value in y and return the corresponding
51    ternary value (which is necessarily non-zero),
52    otherwise return 0 */
53 static int
mpfr_log2p1_special(mpfr_ptr y,mpfr_srcptr x,mpfr_rnd_t rnd_mode)54 mpfr_log2p1_special (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode)
55 {
56   mpfr_exp_t expx = MPFR_GET_EXP(x);
57   mpfr_exp_t k = expx - 1, expk;
58   mpfr_prec_t prec;
59   mpfr_t t;
60   int inex;
61 
62   if (k <= 0 || mpfr_cmp_si_2exp (x, 1, k) != 0)
63     return 0;
64   /* k < log2(1+x) < k + 1/x/log(2) < k + 2/x */
65   expk = MPFR_INT_CEIL_LOG2(k); /* exponent of k */
66   /* 2/x < 2^(2-EXP(x)) thus if 2-EXP(x) < expk - PREC(y) - 1,
67      we have 2/x < 1/4*ulp(k) and we can decide the correct rounding */
68   if (2 - expx >= expk - MPFR_PREC(y) - 1)
69     return 0;
70   prec = (MPFR_PREC(y) + 2 <= ULSIZE) ? ULSIZE : MPFR_PREC(y) + 2;
71   mpfr_init2 (t, prec);
72   mpfr_set_ui (t, k, MPFR_RNDZ); /* exact since prec >= ULSIZE */
73   mpfr_nextabove (t);
74   /* now k < t < k + 2/x and round(t) = round(log2(1+x)) */
75   inex = mpfr_set (y, t, rnd_mode);
76   mpfr_clear (t);
77   /* Warning: for RNDF, the mpfr_set calls above might return 0 */
78   return (rnd_mode == MPFR_RNDF) ? 1 : inex;
79 }
80 
81 /* The computation of log2p1 is done by log2p1(x) = log1p(x)/log(2) */
82 int
mpfr_log2p1(mpfr_ptr y,mpfr_srcptr x,mpfr_rnd_t rnd_mode)83 mpfr_log2p1 (mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd_mode)
84 {
85   int comp, inexact, nloop;
86   mpfr_t t, lg2;
87   mpfr_prec_t Ny = MPFR_PREC(y), prec;
88   MPFR_ZIV_DECL (loop);
89   MPFR_SAVE_EXPO_DECL (expo);
90 
91   MPFR_LOG_FUNC
92     (("x[%Pd]=%.*Rg rnd=%d", mpfr_get_prec (x), mpfr_log_prec, x, rnd_mode),
93      ("y[%Pd]=%.*Rg inexact=%d", mpfr_get_prec (y), mpfr_log_prec, y,
94       inexact));
95 
96   if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x)))
97     return mpfr_log1p (y, x, rnd_mode); /* same result for singular cases */
98 
99   comp = mpfr_cmp_si (x, -1);
100   /* log2p1(x) is undefined for x < -1 */
101   if (MPFR_UNLIKELY(comp <= 0))
102     {
103       if (comp == 0)
104         /* x=0: log2p1(-1)=-inf (divide-by-zero exception) */
105         {
106           MPFR_SET_INF (y);
107           MPFR_SET_NEG (y);
108           MPFR_SET_DIVBY0 ();
109           MPFR_RET (0);
110         }
111       MPFR_SET_NAN (y);
112       MPFR_RET_NAN;
113     }
114 
115   MPFR_SAVE_EXPO_MARK (expo);
116 
117   prec = Ny + MPFR_INT_CEIL_LOG2 (Ny) + 6;
118 
119   mpfr_init2 (t, prec);
120   mpfr_init2 (lg2, prec);
121 
122   MPFR_ZIV_INIT (loop, prec);
123   for (nloop = 0; ; nloop++)
124     {
125       mpfr_log1p (t, x, MPFR_RNDN);
126       mpfr_const_log2 (lg2, MPFR_RNDN);
127       mpfr_div (t, t, lg2, MPFR_RNDN);
128       /* t = log2(1+x) * (1 + theta)^3 where |theta| < 2^-prec,
129          for prec >= 2 we have |(1 + theta)^3 - 1| < 4*theta.
130          Note: contrary to log10p1, no underflow is possible in extended
131          exponent range, since for tiny x, |log2(1+x)| ~ |x|/log(2) >= |x|,
132          and x is representable, thus x/log(2) too. */
133       if (MPFR_LIKELY (MPFR_CAN_ROUND (t, prec - 2, Ny, rnd_mode)))
134         break;
135 
136       if (nloop == 0)
137         {
138           /* check for exact cases */
139           mpfr_exp_t k;
140 
141           MPFR_LOG_MSG (("check for exact cases\n", 0));
142           k = mpfr_log2p1_isexact (x);
143           if (k != 0) /* 1+x = 2^k */
144             {
145               inexact = mpfr_set_si (y, k, rnd_mode);
146               goto end;
147             }
148 
149           /* if x = 2^k with huge k, Ziv's loop will fail */
150           inexact = mpfr_log2p1_special (y, x, rnd_mode);
151           if (inexact != 0)
152             goto end;
153         }
154 
155       MPFR_ZIV_NEXT (loop, prec);
156       mpfr_set_prec (t, prec);
157       mpfr_set_prec (lg2, prec);
158     }
159   inexact = mpfr_set (y, t, rnd_mode);
160 
161  end:
162   MPFR_ZIV_FREE (loop);
163   mpfr_clear (t);
164   mpfr_clear (lg2);
165 
166   MPFR_SAVE_EXPO_FREE (expo);
167   return mpfr_check_range (y, inexact, rnd_mode);
168 }
169