]> git.ipfire.org Git - thirdparty/glibc.git/blob - sysdeps/ieee754/ldbl-128ibm/s_remquol.c
8b946ab3997fd9b89bc0381b075035364749cd7e
[thirdparty/glibc.git] / sysdeps / ieee754 / ldbl-128ibm / s_remquol.c
1 /* Compute remainder and a congruent to the quotient.
2 Copyright (C) 1997-2019 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 <math.h>
22
23 #include <math_private.h>
24 #include <math_ldbl_opt.h>
25
26
27 static const long double zero = 0.0;
28
29
30 long double
31 __remquol (long double x, long double y, int *quo)
32 {
33 int64_t hx,hy;
34 uint64_t sx,lx,ly,qs;
35 int cquo;
36 double xhi, xlo, yhi, ylo;
37
38 ldbl_unpack (x, &xhi, &xlo);
39 EXTRACT_WORDS64 (hx, xhi);
40 EXTRACT_WORDS64 (lx, xlo);
41 ldbl_unpack (y, &yhi, &ylo);
42 EXTRACT_WORDS64 (hy, yhi);
43 EXTRACT_WORDS64 (ly, ylo);
44 sx = hx & 0x8000000000000000ULL;
45 qs = sx ^ (hy & 0x8000000000000000ULL);
46 ly ^= hy & 0x8000000000000000ULL;
47 hy &= 0x7fffffffffffffffLL;
48 lx ^= sx;
49 hx &= 0x7fffffffffffffffLL;
50
51 /* Purge off exception values. */
52 if (hy == 0)
53 return (x * y) / (x * y); /* y = 0 */
54 if ((hx >= 0x7ff0000000000000LL) /* x not finite */
55 || (hy > 0x7ff0000000000000LL)) /* y is NaN */
56 return (x * y) / (x * y);
57
58 if (hy <= 0x7fbfffffffffffffLL)
59 x = __ieee754_fmodl (x, 8 * y); /* now x < 8y */
60
61 if (((hx - hy) | (lx - ly)) == 0)
62 {
63 *quo = qs ? -1 : 1;
64 return zero * x;
65 }
66
67 x = fabsl (x);
68 y = fabsl (y);
69 cquo = 0;
70
71 if (hy <= 0x7fcfffffffffffffLL && x >= 4 * y)
72 {
73 x -= 4 * y;
74 cquo += 4;
75 }
76 if (hy <= 0x7fdfffffffffffffLL && x >= 2 * y)
77 {
78 x -= 2 * y;
79 cquo += 2;
80 }
81
82 if (hy < 0x0020000000000000LL)
83 {
84 if (x + x > y)
85 {
86 x -= y;
87 ++cquo;
88 if (x + x >= y)
89 {
90 x -= y;
91 ++cquo;
92 }
93 }
94 }
95 else
96 {
97 long double y_half = 0.5L * y;
98 if (x > y_half)
99 {
100 x -= y;
101 ++cquo;
102 if (x >= y_half)
103 {
104 x -= y;
105 ++cquo;
106 }
107 }
108 }
109
110 *quo = qs ? -cquo : cquo;
111
112 /* Ensure correct sign of zero result in round-downward mode. */
113 if (x == 0.0L)
114 x = 0.0L;
115 if (sx)
116 x = -x;
117 return x;
118 }
119 long_double_symbol (libm, __remquol, remquol);