1 /* Compute remainder and a congruent to the quotient.
2    Copyright (C) 1997-2022 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #include <math.h>
20 
21 #include <math_private.h>
22 #include <libm-alias-ldouble.h>
23 
24 
25 static const long double zero = 0.0;
26 
27 
28 long double
__remquol(long double x,long double p,int * quo)29 __remquol (long double x, long double p, int *quo)
30 {
31   int32_t ex,ep,hx,hp;
32   uint32_t sx,lx,lp;
33   int cquo,qs;
34 
35   GET_LDOUBLE_WORDS (ex, hx, lx, x);
36   GET_LDOUBLE_WORDS (ep, hp, lp, p);
37   sx = ex & 0x8000;
38   qs = (sx ^ (ep & 0x8000)) >> 15;
39   ep &= 0x7fff;
40   ex &= 0x7fff;
41 
42   /* Purge off exception values.  */
43   if ((ep | hp | lp) == 0)
44     return (x * p) / (x * p); 			/* p = 0 */
45   if ((ex == 0x7fff)				/* x not finite */
46       || ((ep == 0x7fff)			/* p is NaN */
47 	  && (((hp & 0x7fffffff) | lp) != 0)))
48     return (x * p) / (x * p);
49 
50   if (ep <= 0x7ffb)
51     x = __ieee754_fmodl (x, 8 * p);		/* now x < 8p */
52 
53   if (((ex - ep) | (hx - hp) | (lx - lp)) == 0)
54     {
55       *quo = qs ? -1 : 1;
56       return zero * x;
57     }
58 
59   x  = fabsl (x);
60   p  = fabsl (p);
61   cquo = 0;
62 
63   if (ep <= 0x7ffc && x >= 4 * p)
64     {
65       x -= 4 * p;
66       cquo += 4;
67     }
68   if (ep <= 0x7ffd && x >= 2 * p)
69     {
70       x -= 2 * p;
71       cquo += 2;
72     }
73 
74   if (ep < 0x0002)
75     {
76       if (x + x > p)
77 	{
78 	  x -= p;
79 	  ++cquo;
80 	  if (x + x >= p)
81 	    {
82 	      x -= p;
83 	      ++cquo;
84 	    }
85 	}
86     }
87   else
88     {
89       long double p_half = 0.5 * p;
90       if (x > p_half)
91 	{
92 	  x -= p;
93 	  ++cquo;
94 	  if (x >= p_half)
95 	    {
96 	      x -= p;
97 	      ++cquo;
98 	    }
99 	}
100     }
101 
102   *quo = qs ? -cquo : cquo;
103 
104   /* Ensure correct sign of zero result in round-downward mode.  */
105   if (x == 0.0L)
106     x = 0.0L;
107   if (sx)
108     x = -x;
109   return x;
110 }
111 libm_alias_ldouble (__remquo, remquo)
112