xref: /netbsd-src/external/lgpl3/mpfr/dist/src/frexp.c (revision ec6772edaf0cdcb5f52a48f4aca5e33a8fb8ecfd)
1 /* mpfr_frexp -- convert to integral and fractional parts
2 
3 Copyright 2011-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 #include "mpfr-impl.h"
24 
25 int
mpfr_frexp(mpfr_exp_t * exp,mpfr_ptr y,mpfr_srcptr x,mpfr_rnd_t rnd)26 mpfr_frexp (mpfr_exp_t *exp, mpfr_ptr y, mpfr_srcptr x, mpfr_rnd_t rnd)
27 {
28   int inex;
29   mpfr_flags_t saved_flags = __gmpfr_flags;
30   MPFR_BLOCK_DECL (flags);
31 
32   MPFR_LOG_FUNC
33     (("x[%Pd]=%.*Rg rnd=%d", mpfr_get_prec (x), mpfr_log_prec, x, rnd),
34      ("y[%Pd]=%.*Rg exp=%" MPFR_EXP_FSPEC "d inex=%d", mpfr_get_prec (y),
35       mpfr_log_prec, y, (mpfr_eexp_t) *exp, inex));
36 
37   if (MPFR_UNLIKELY(MPFR_IS_SINGULAR(x)))
38     {
39       if (MPFR_IS_NAN(x))
40         {
41           MPFR_SET_NAN(y);
42           MPFR_RET_NAN; /* exp is unspecified */
43         }
44       else if (MPFR_IS_INF(x))
45         {
46           MPFR_SET_INF(y);
47           MPFR_SET_SAME_SIGN(y,x);
48           MPFR_RET(0); /* exp is unspecified */
49         }
50       else
51         {
52           MPFR_SET_ZERO(y);
53           MPFR_SET_SAME_SIGN(y,x);
54           *exp = 0;
55           MPFR_RET(0);
56         }
57     }
58 
59   MPFR_BLOCK (flags, inex = mpfr_set (y, x, rnd));
60   __gmpfr_flags = saved_flags;
61 
62   /* Possible overflow due to the rounding, no possible underflow. */
63 
64   if (MPFR_UNLIKELY (MPFR_OVERFLOW (flags)))
65     {
66       int inex2;
67 
68       /* An overflow here means that the exponent of y would be larger than
69          the one of x, thus x would be rounded to the next power of 2, and
70          the returned y should be 1/2 in absolute value, rounded (i.e. with
71          possible underflow or overflow). This also implies that x and y are
72          different objects, so that the exponent of x has not been lost. */
73       MPFR_LOG_MSG (("Internal overflow\n", 0));
74       MPFR_ASSERTD (x != y);
75       *exp = MPFR_GET_EXP (x) + 1;
76       inex2 = mpfr_set_si_2exp (y, MPFR_INT_SIGN (x), -1, rnd);
77       MPFR_LOG_MSG (("inex=%d inex2=%d\n", inex, inex2));
78       if (inex2 != 0)
79         inex = inex2;
80       MPFR_RET (inex);
81     }
82 
83   *exp = MPFR_GET_EXP (y);
84   /* Do not use MPFR_SET_EXP because the range has not been checked yet. */
85   MPFR_EXP (y) = 0;
86   return mpfr_check_range (y, inex, rnd);
87 }
88