1 /* mpfr_rem1 -- internal function
2    mpfr_fmod -- compute the floating-point remainder of x/y
3    mpfr_remquo and mpfr_remainder -- argument reduction functions
4 
5 Copyright 2007-2020 Free Software Foundation, Inc.
6 Contributed by the AriC and Caramba projects, INRIA.
7 
8 This file is part of the GNU MPFR Library.
9 
10 The GNU MPFR Library is free software; you can redistribute it and/or modify
11 it under the terms of the GNU Lesser General Public License as published by
12 the Free Software Foundation; either version 3 of the License, or (at your
13 option) any later version.
14 
15 The GNU MPFR Library is distributed in the hope that it will be useful, but
16 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
17 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
18 License for more details.
19 
20 You should have received a copy of the GNU Lesser General Public License
21 along with the GNU MPFR Library; see the file COPYING.LESSER.  If not, see
22 https://www.gnu.org/licenses/ or write to the Free Software Foundation, Inc.,
23 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */
24 
25 #include "mpfr-impl.h"
26 
27 /* we return as many bits as we can, keeping just one bit for the sign */
28 # define WANTED_BITS (sizeof(long) * CHAR_BIT - 1)
29 
30 /*
31   rem1 works as follows:
32   The first rounding mode rnd_q indicate if we are actually computing
33   a fmod (MPFR_RNDZ) or a remainder/remquo (MPFR_RNDN).
34 
35   Let q = x/y rounded to an integer in the direction rnd_q.
36   Put x - q*y in rem, rounded according to rnd.
37   If quo is not null, the value stored in *quo has the sign of q,
38   and agrees with q with the 2^n low order bits.
39   In other words, *quo = q (mod 2^n) and *quo q >= 0.
40   If rem is zero, then it has the sign of x.
41   The returned 'int' is the inexact flag giving the place of rem wrt x - q*y.
42 
43   If x or y is NaN: *quo is undefined, rem is NaN.
44   If x is Inf, whatever y: *quo is undefined, rem is NaN.
45   If y is Inf, x not NaN nor Inf: *quo is 0, rem is x.
46   If y is 0, whatever x: *quo is undefined, rem is NaN.
47   If x is 0, whatever y (not NaN nor 0): *quo is 0, rem is x.
48 
49   Otherwise if x and y are neither NaN, Inf nor 0, q is always defined,
50   thus *quo is.
51   Since |x - q*y| <= y/2, no overflow is possible.
52   Only an underflow is possible when y is very small.
53  */
54 
55 static int
mpfr_rem1(mpfr_ptr rem,long * quo,mpfr_rnd_t rnd_q,mpfr_srcptr x,mpfr_srcptr y,mpfr_rnd_t rnd)56 mpfr_rem1 (mpfr_ptr rem, long *quo, mpfr_rnd_t rnd_q,
57            mpfr_srcptr x, mpfr_srcptr y, mpfr_rnd_t rnd)
58 {
59   mpfr_exp_t ex, ey;
60   int compare, inex, q_is_odd, sign, signx = MPFR_SIGN (x);
61   mpz_t mx, my, r;
62   int tiny = 0;
63 
64   MPFR_ASSERTD (rnd_q == MPFR_RNDN || rnd_q == MPFR_RNDZ);
65 
66   if (MPFR_UNLIKELY (MPFR_IS_SINGULAR (x) || MPFR_IS_SINGULAR (y)))
67     {
68       if (MPFR_IS_NAN (x) || MPFR_IS_NAN (y) || MPFR_IS_INF (x)
69           || MPFR_IS_ZERO (y))
70         {
71           /* for remquo, quo is undefined */
72           MPFR_SET_NAN (rem);
73           MPFR_RET_NAN;
74         }
75       else                      /* either y is Inf and x is 0 or non-special,
76                                    or x is 0 and y is non-special,
77                                    in both cases the quotient is zero. */
78         {
79           if (quo)
80             *quo = 0;
81           return mpfr_set (rem, x, rnd);
82         }
83     }
84 
85   /* now neither x nor y is NaN, Inf or zero */
86 
87   mpz_init (mx);
88   mpz_init (my);
89   mpz_init (r);
90 
91   ex = mpfr_get_z_2exp (mx, x);  /* x = mx*2^ex */
92   ey = mpfr_get_z_2exp (my, y);  /* y = my*2^ey */
93 
94   /* to get rid of sign problems, we compute it separately:
95      quo(-x,-y) = quo(x,y), rem(-x,-y) = -rem(x,y)
96      quo(-x,y) = -quo(x,y), rem(-x,y)  = -rem(x,y)
97      thus quo = sign(x/y)*quo(|x|,|y|), rem = sign(x)*rem(|x|,|y|) */
98   sign = (signx == MPFR_SIGN (y)) ? 1 : -1;
99   mpz_abs (mx, mx);
100   mpz_abs (my, my);
101   q_is_odd = 0;
102 
103   /* Divide my by 2^k if possible to make operations mod my easier.
104      Since my comes from a regular MPFR number, due to the constraints on the
105      exponent and the precision, there can be no integer overflow below. */
106   {
107     mpfr_exp_t k = mpz_scan1 (my, 0);
108     ey += k;
109     mpz_fdiv_q_2exp (my, my, k);
110   }
111 
112   if (ex <= ey)
113     {
114       /* q = x/y = mx/(my*2^(ey-ex)) */
115 
116       /* First detect cases where q=0, to avoid creating a huge number
117          my*2^(ey-ex): if sx = mpz_sizeinbase (mx, 2) and sy =
118          mpz_sizeinbase (my, 2), we have x < 2^(ex + sx) and
119          y >= 2^(ey + sy - 1), thus if ex + sx <= ey + sy - 1
120          the quotient is 0 */
121       if (ex + (mpfr_exp_t) mpz_sizeinbase (mx, 2) <
122           ey + (mpfr_exp_t) mpz_sizeinbase (my, 2))
123         {
124           tiny = 1;
125           mpz_set (r, mx);
126           mpz_set_ui (mx, 0);
127         }
128       else
129         {
130           mpz_mul_2exp (my, my, ey - ex);   /* divide mx by my*2^(ey-ex) */
131 
132           /* since mx > 0 and my > 0, we can use mpz_tdiv_qr in all cases */
133           mpz_tdiv_qr (mx, r, mx, my);
134           /* 0 <= |r| <= |my|, r has the same sign as mx */
135         }
136 
137       if (rnd_q == MPFR_RNDN)
138         q_is_odd = mpz_tstbit (mx, 0);
139       if (quo)                  /* mx is the quotient */
140         {
141           mpz_tdiv_r_2exp (mx, mx, WANTED_BITS);
142           *quo = mpz_get_si (mx);
143         }
144     }
145   else                          /* ex > ey */
146     {
147       if (quo) /* remquo case */
148         /* for remquo, to get the low WANTED_BITS more bits of the quotient,
149            we first compute R =  X mod Y*2^WANTED_BITS, where X and Y are
150            defined below. Then the low WANTED_BITS of the quotient are
151            floor(R/Y). */
152         mpz_mul_2exp (my, my, WANTED_BITS);     /* 2^WANTED_BITS*Y */
153 
154       else if (rnd_q == MPFR_RNDN) /* remainder case */
155         /* Let X = mx*2^(ex-ey) and Y = my. Then both X and Y are integers.
156            Assume X = R mod Y, then x = X*2^ey = R*2^ey mod (Y*2^ey=y).
157            To be able to perform the rounding, we need the least significant
158            bit of the quotient, i.e., one more bit in the remainder,
159            which is obtained by dividing by 2Y. */
160         mpz_mul_2exp (my, my, 1);       /* 2Y */
161 
162       /* Warning: up to GMP 6.2.0, mpz_powm_ui is not optimized when BASE^EXP
163          has about the same size as MOD, in which case it should first compute
164          BASE^EXP exactly, then reduce it modulo MOD:
165          https://gmplib.org/list-archives/gmp-bugs/2020-February/004736.html
166          Thus when 2^(ex-ey) is less than my^3, we use this algorithm. */
167       if (ex - ey > 3 * mpz_sizeinbase (my, 2))
168         {
169           mpz_set_ui (r, 2);
170           mpz_powm_ui (r, r, ex - ey, my);  /* 2^(ex-ey) mod my */
171         }
172       else
173         mpz_ui_pow_ui (r, 2, ex - ey);
174       mpz_mul (r, r, mx);
175       mpz_mod (r, r, my);
176 
177       if (quo)                  /* now 0 <= r < 2^WANTED_BITS*Y */
178         {
179           mpz_fdiv_q_2exp (my, my, WANTED_BITS);   /* back to Y */
180           mpz_tdiv_qr (mx, r, r, my);
181           /* oldr = mx*my + newr */
182           *quo = mpz_get_si (mx);
183           q_is_odd = *quo & 1;
184         }
185       else if (rnd_q == MPFR_RNDN) /* now 0 <= r < 2Y in the remainder case */
186         {
187           mpz_fdiv_q_2exp (my, my, 1);     /* back to Y */
188           /* least significant bit of q */
189           q_is_odd = mpz_cmpabs (r, my) >= 0;
190           if (q_is_odd)
191             mpz_sub (r, r, my);
192         }
193       /* now 0 <= |r| < |my|, and if needed,
194          q_is_odd is the least significant bit of q */
195     }
196 
197   if (mpz_cmp_ui (r, 0) == 0)
198     {
199       inex = mpfr_set_ui (rem, 0, MPFR_RNDN);
200       /* take into account sign of x */
201       if (signx < 0)
202         mpfr_neg (rem, rem, MPFR_RNDN);
203     }
204   else
205     {
206       if (rnd_q == MPFR_RNDN)
207         {
208           /* FIXME: the comparison 2*r < my could be done more efficiently
209              at the mpn level */
210           mpz_mul_2exp (r, r, 1);
211           /* if tiny=1, we should compare r with my*2^(ey-ex) */
212           if (tiny)
213             {
214               if (ex + (mpfr_exp_t) mpz_sizeinbase (r, 2) <
215                   ey + (mpfr_exp_t) mpz_sizeinbase (my, 2))
216                 compare = 0; /* r*2^ex < my*2^ey */
217               else
218                 {
219                   mpz_mul_2exp (my, my, ey - ex);
220                   compare = mpz_cmpabs (r, my);
221                 }
222             }
223           else
224             compare = mpz_cmpabs (r, my);
225           mpz_fdiv_q_2exp (r, r, 1);
226           compare = ((compare > 0) ||
227                      ((rnd_q == MPFR_RNDN) && (compare == 0) && q_is_odd));
228           /* if compare != 0, we need to subtract my to r, and add 1 to quo */
229           if (compare)
230             {
231               mpz_sub (r, r, my);
232               if (quo && (rnd_q == MPFR_RNDN))
233                 *quo += 1;
234             }
235         }
236       /* take into account sign of x */
237       if (signx < 0)
238         mpz_neg (r, r);
239       inex = mpfr_set_z_2exp (rem, r, ex > ey ? ey : ex, rnd);
240     }
241 
242   if (quo)
243     *quo *= sign;
244 
245   mpz_clear (mx);
246   mpz_clear (my);
247   mpz_clear (r);
248 
249   return inex;
250 }
251 
252 int
mpfr_remainder(mpfr_ptr rem,mpfr_srcptr x,mpfr_srcptr y,mpfr_rnd_t rnd)253 mpfr_remainder (mpfr_ptr rem, mpfr_srcptr x, mpfr_srcptr y, mpfr_rnd_t rnd)
254 {
255   return mpfr_rem1 (rem, (long *) 0, MPFR_RNDN, x, y, rnd);
256 }
257 
258 int
mpfr_remquo(mpfr_ptr rem,long * quo,mpfr_srcptr x,mpfr_srcptr y,mpfr_rnd_t rnd)259 mpfr_remquo (mpfr_ptr rem, long *quo,
260              mpfr_srcptr x, mpfr_srcptr y, mpfr_rnd_t rnd)
261 {
262   return mpfr_rem1 (rem, quo, MPFR_RNDN, x, y, rnd);
263 }
264 
265 int
mpfr_fmod(mpfr_ptr rem,mpfr_srcptr x,mpfr_srcptr y,mpfr_rnd_t rnd)266 mpfr_fmod (mpfr_ptr rem, mpfr_srcptr x, mpfr_srcptr y, mpfr_rnd_t rnd)
267 {
268   return mpfr_rem1 (rem, (long *) 0, MPFR_RNDZ, x, y, rnd);
269 }
270 
271 int
mpfr_fmodquo(mpfr_ptr rem,long * quo,mpfr_srcptr x,mpfr_srcptr y,mpfr_rnd_t rnd)272 mpfr_fmodquo (mpfr_ptr rem, long *quo, mpfr_srcptr x, mpfr_srcptr y,
273               mpfr_rnd_t rnd)
274 {
275   return mpfr_rem1 (rem, quo, MPFR_RNDZ, x, y, rnd);
276 }
277