1 /* Compute remainder and a congruent to the quotient.
2    Copyright (C) 1997-2018 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4    Contributed by Ulrich Drepper <drepper@cygnus.com>, 1997 and
5 		  Jakub Jelinek <jj@ultra.linux.cz>, 1999.
6 
7    The GNU C Library is free software; you can redistribute it and/or
8    modify it under the terms of the GNU Lesser General Public
9    License as published by the Free Software Foundation; either
10    version 2.1 of the License, or (at your option) any later version.
11 
12    The GNU C Library is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15    Lesser General Public License for more details.
16 
17    You should have received a copy of the GNU Lesser General Public
18    License along with the GNU C Library; if not, see
19    <http://www.gnu.org/licenses/>.  */
20 
21 #include "quadmath-imp.h"
22 
23 static const __float128 zero = 0.0;
24 
25 
26 __float128
remquoq(__float128 x,__float128 y,int * quo)27 remquoq (__float128 x, __float128 y, int *quo)
28 {
29   int64_t hx,hy;
30   uint64_t sx,lx,ly,qs;
31   int cquo;
32 
33   GET_FLT128_WORDS64 (hx, lx, x);
34   GET_FLT128_WORDS64 (hy, ly, y);
35   sx = hx & 0x8000000000000000ULL;
36   qs = sx ^ (hy & 0x8000000000000000ULL);
37   hy &= 0x7fffffffffffffffLL;
38   hx &= 0x7fffffffffffffffLL;
39 
40   /* Purge off exception values.  */
41   if ((hy | ly) == 0)
42     return (x * y) / (x * y); 			/* y = 0 */
43   if ((hx >= 0x7fff000000000000LL)		/* x not finite */
44       || ((hy >= 0x7fff000000000000LL)		/* y is NaN */
45 	  && (((hy - 0x7fff000000000000LL) | ly) != 0)))
46     return (x * y) / (x * y);
47 
48   if (hy <= 0x7ffbffffffffffffLL)
49     x = fmodq (x, 8 * y);              /* now x < 8y */
50 
51   if (((hx - hy) | (lx - ly)) == 0)
52     {
53       *quo = qs ? -1 : 1;
54       return zero * x;
55     }
56 
57   x  = fabsq (x);
58   y  = fabsq (y);
59   cquo = 0;
60 
61   if (hy <= 0x7ffcffffffffffffLL && x >= 4 * y)
62     {
63       x -= 4 * y;
64       cquo += 4;
65     }
66   if (hy <= 0x7ffdffffffffffffLL && x >= 2 * y)
67     {
68       x -= 2 * y;
69       cquo += 2;
70     }
71 
72   if (hy < 0x0002000000000000LL)
73     {
74       if (x + x > y)
75 	{
76 	  x -= y;
77 	  ++cquo;
78 	  if (x + x >= y)
79 	    {
80 	      x -= y;
81 	      ++cquo;
82 	    }
83 	}
84     }
85   else
86     {
87       __float128 y_half = 0.5Q * y;
88       if (x > y_half)
89 	{
90 	  x -= y;
91 	  ++cquo;
92 	  if (x >= y_half)
93 	    {
94 	      x -= y;
95 	      ++cquo;
96 	    }
97 	}
98     }
99 
100   *quo = qs ? -cquo : cquo;
101 
102   /* Ensure correct sign of zero result in round-downward mode.  */
103   if (x == 0)
104     x = 0;
105   if (sx)
106     x = -x;
107   return x;
108 }
109