annotate lib/fmod.c @ 40231:9b3c79fdfe0b

strtod: fix clash with strtold Problem reported for RHEL 5 by Jesse Caldwell (Bug#34817). * lib/strtod.c (compute_minus_zero, minus_zero): Simplify by remving the macro / external variable, and having just a function. User changed. This avoids the need for an external variable that might clash.
author Paul Eggert <eggert@cs.ucla.edu>
date Mon, 11 Mar 2019 16:40:29 -0700
parents b06060465f09
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
16486
8b3ead70232c fmod-ieee: Work around test failures on OSF/1, mingw.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
1 /* Remainder.
40057
b06060465f09 maint: Run 'make update-copyright'
Paul Eggert <eggert@cs.ucla.edu>
parents: 19484
diff changeset
2 Copyright (C) 2011-2019 Free Software Foundation, Inc.
16486
8b3ead70232c fmod-ieee: Work around test failures on OSF/1, mingw.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
3
8b3ead70232c fmod-ieee: Work around test failures on OSF/1, mingw.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
4 This program is free software: you can redistribute it and/or modify
8b3ead70232c fmod-ieee: Work around test failures on OSF/1, mingw.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
5 it under the terms of the GNU General Public License as published by
8b3ead70232c fmod-ieee: Work around test failures on OSF/1, mingw.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
6 the Free Software Foundation; either version 3 of the License, or
8b3ead70232c fmod-ieee: Work around test failures on OSF/1, mingw.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
7 (at your option) any later version.
8b3ead70232c fmod-ieee: Work around test failures on OSF/1, mingw.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
8
8b3ead70232c fmod-ieee: Work around test failures on OSF/1, mingw.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
9 This program is distributed in the hope that it will be useful,
8b3ead70232c fmod-ieee: Work around test failures on OSF/1, mingw.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
8b3ead70232c fmod-ieee: Work around test failures on OSF/1, mingw.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
8b3ead70232c fmod-ieee: Work around test failures on OSF/1, mingw.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
12 GNU General Public License for more details.
8b3ead70232c fmod-ieee: Work around test failures on OSF/1, mingw.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
13
8b3ead70232c fmod-ieee: Work around test failures on OSF/1, mingw.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
14 You should have received a copy of the GNU General Public License
19190
9759915b2aca all: prefer https: URLs
Paul Eggert <eggert@cs.ucla.edu>
parents: 18626
diff changeset
15 along with this program. If not, see <https://www.gnu.org/licenses/>. */
16486
8b3ead70232c fmod-ieee: Work around test failures on OSF/1, mingw.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
16
16565
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
17 #if ! defined USE_LONG_DOUBLE
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
18 # include <config.h>
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
19 #endif
16486
8b3ead70232c fmod-ieee: Work around test failures on OSF/1, mingw.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
20
8b3ead70232c fmod-ieee: Work around test failures on OSF/1, mingw.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
21 /* Specification. */
8b3ead70232c fmod-ieee: Work around test failures on OSF/1, mingw.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
22 #include <math.h>
8b3ead70232c fmod-ieee: Work around test failures on OSF/1, mingw.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
23
16565
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
24 #include <float.h>
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
25 #include <stdlib.h>
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
26
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
27 #ifdef USE_LONG_DOUBLE
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
28 # define FMOD fmodl
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
29 # define DOUBLE long double
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
30 # define MANT_DIG LDBL_MANT_DIG
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
31 # define L_(literal) literal##L
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
32 # define FREXP frexpl
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
33 # define LDEXP ldexpl
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
34 # define FABS fabsl
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
35 # define TRUNC truncl
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
36 # define ISNAN isnanl
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
37 #else
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
38 # define FMOD fmod
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
39 # define DOUBLE double
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
40 # define MANT_DIG DBL_MANT_DIG
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
41 # define L_(literal) literal
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
42 # define FREXP frexp
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
43 # define LDEXP ldexp
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
44 # define FABS fabs
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
45 # define TRUNC trunc
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
46 # define ISNAN isnand
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
47 #endif
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
48
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
49 /* MSVC with option -fp:strict refuses to compile constant initializers that
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
50 contain floating-point operations. Pacify this compiler. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
51 #ifdef _MSC_VER
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
52 # pragma fenv_access (off)
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
53 #endif
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
54
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
55 #undef NAN
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
56 #if defined _MSC_VER
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
57 static DOUBLE zero;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
58 # define NAN (zero / zero)
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
59 #else
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
60 # define NAN (L_(0.0) / L_(0.0))
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
61 #endif
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
62
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
63 /* To avoid rounding errors during the computation of x - q * y,
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
64 there are three possibilities:
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
65 - Use fma (- q, y, x).
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
66 - Have q be a single bit at a time, and compute x - q * y
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
67 through a subtraction.
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
68 - Have q be at most MANT_DIG/2 bits at a time, and compute
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
69 x - q * y by splitting y into two halves:
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
70 y = y1 * 2^(MANT_DIG/2) + y0
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
71 x - q * y = (x - q * y1 * 2^MANT_DIG/2) - q * y0.
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
72 The latter is probably the most efficient. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
73
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
74 /* Number of bits in a limb. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
75 #define LIMB_BITS (MANT_DIG / 2)
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
76
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
77 /* 2^LIMB_BITS. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
78 static const DOUBLE TWO_LIMB_BITS =
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
79 /* Assume LIMB_BITS <= 3 * 31.
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
80 Use the identity
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
81 n = floor(n/3) + floor((n+1)/3) + floor((n+2)/3). */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
82 (DOUBLE) (1U << (LIMB_BITS / 3))
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
83 * (DOUBLE) (1U << ((LIMB_BITS + 1) / 3))
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
84 * (DOUBLE) (1U << ((LIMB_BITS + 2) / 3));
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
85
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
86 /* 2^-LIMB_BITS. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
87 static const DOUBLE TWO_LIMB_BITS_INVERSE =
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
88 /* Assume LIMB_BITS <= 3 * 31.
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
89 Use the identity
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
90 n = floor(n/3) + floor((n+1)/3) + floor((n+2)/3). */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
91 L_(1.0) / ((DOUBLE) (1U << (LIMB_BITS / 3))
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
92 * (DOUBLE) (1U << ((LIMB_BITS + 1) / 3))
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
93 * (DOUBLE) (1U << ((LIMB_BITS + 2) / 3)));
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
94
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
95 DOUBLE
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
96 FMOD (DOUBLE x, DOUBLE y)
16486
8b3ead70232c fmod-ieee: Work around test failures on OSF/1, mingw.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
97 {
16565
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
98 if (isfinite (x) && isfinite (y) && y != L_(0.0))
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
99 {
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
100 if (x == L_(0.0))
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
101 /* Return x, regardless of the sign of y. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
102 return x;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
103
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
104 {
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
105 int negate = ((!signbit (x)) ^ (!signbit (y)));
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
106
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
107 /* Take the absolute value of x and y. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
108 x = FABS (x);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
109 y = FABS (y);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
110
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
111 /* Trivial case that requires no computation. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
112 if (x < y)
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
113 return (negate ? - x : x);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
114
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
115 {
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
116 int yexp;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
117 DOUBLE ym;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
118 DOUBLE y1;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
119 DOUBLE y0;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
120 int k;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
121 DOUBLE x2;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
122 DOUBLE x1;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
123 DOUBLE x0;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
124
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
125 /* Write y = 2^yexp * (y1 * 2^-LIMB_BITS + y0 * 2^-(2*LIMB_BITS))
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
126 where y1 is an integer, 2^(LIMB_BITS-1) <= y1 < 2^LIMB_BITS,
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
127 y1 has at most LIMB_BITS bits,
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
128 0 <= y0 < 2^LIMB_BITS,
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
129 y0 has at most (MANT_DIG + 1) / 2 bits. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
130 ym = FREXP (y, &yexp);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
131 ym = ym * TWO_LIMB_BITS;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
132 y1 = TRUNC (ym);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
133 y0 = (ym - y1) * TWO_LIMB_BITS;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
134
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
135 /* Write
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
136 x = 2^(yexp+(k-3)*LIMB_BITS)
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
137 * (x2 * 2^(2*LIMB_BITS) + x1 * 2^LIMB_BITS + x0)
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
138 where x2, x1, x0 are each integers >= 0, < 2^LIMB_BITS. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
139 {
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
140 int xexp;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
141 DOUBLE xm = FREXP (x, &xexp);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
142 /* Since we know x >= y, we know xexp >= yexp. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
143 xexp -= yexp;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
144 /* Compute k = ceil(xexp / LIMB_BITS). */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
145 k = (xexp + LIMB_BITS - 1) / LIMB_BITS;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
146 /* Note: (k - 1) * LIMB_BITS + 1 <= xexp <= k * LIMB_BITS. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
147 /* Note: 0.5 <= xm < 1.0. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
148 xm = LDEXP (xm, xexp - (k - 1) * LIMB_BITS);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
149 /* Note: Now xm < 2^(xexp - (k - 1) * LIMB_BITS) <= 2^LIMB_BITS
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
150 and xm >= 0.5 * 2^(xexp - (k - 1) * LIMB_BITS) >= 1.0
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
151 and xm has at most MANT_DIG <= 2*LIMB_BITS+1 bits. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
152 x2 = TRUNC (xm);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
153 x1 = (xm - x2) * TWO_LIMB_BITS;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
154 /* Split off x0 from x1 later. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
155 }
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
156
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
157 /* Test whether [x2,x1,0] >= 2^LIMB_BITS * [y1,y0]. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
158 if (x2 > y1 || (x2 == y1 && x1 >= y0))
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
159 {
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
160 /* Subtract 2^LIMB_BITS * [y1,y0] from [x2,x1,0]. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
161 x2 -= y1;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
162 x1 -= y0;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
163 if (x1 < L_(0.0))
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
164 {
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
165 if (!(x2 >= L_(1.0)))
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
166 abort ();
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
167 x2 -= L_(1.0);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
168 x1 += TWO_LIMB_BITS;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
169 }
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
170 }
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
171
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
172 /* Split off x0 from x1. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
173 {
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
174 DOUBLE x1int = TRUNC (x1);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
175 x0 = TRUNC ((x1 - x1int) * TWO_LIMB_BITS);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
176 x1 = x1int;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
177 }
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
178
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
179 for (; k > 0; k--)
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
180 {
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
181 /* Multiprecision division of the limb sequence [x2,x1,x0]
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
182 by [y1,y0]. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
183 /* Here [x2,x1,x0] < 2^LIMB_BITS * [y1,y0]. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
184 /* The first guess takes into account only [x2,x1] and [y1].
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
185
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
186 By Knuth's theorem, we know that
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
187 q* = min (floor ([x2,x1] / [y1]), 2^LIMB_BITS - 1)
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
188 and
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
189 q = floor ([x2,x1,x0] / [y1,y0])
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
190 are not far away:
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
191 q* - 2 <= q <= q* + 1.
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
192
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
193 Proof:
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
194 a) q* * y1 <= floor ([x2,x1] / [y1]) * y1 <= [x2,x1].
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
195 Hence
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
196 [x2,x1,x0] - q* * [y1,y0]
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
197 = 2^LIMB_BITS * ([x2,x1] - q* * [y1]) + x0 - q* * y0
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
198 >= x0 - q* * y0
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
199 >= - q* * y0
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
200 > - 2^(2*LIMB_BITS)
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
201 >= - 2 * [y1,y0]
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
202 So
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
203 [x2,x1,x0] > (q* - 2) * [y1,y0].
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
204 b) If q* = floor ([x2,x1] / [y1]), then
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
205 [x2,x1] < (q* + 1) * y1
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
206 Hence
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
207 [x2,x1,x0] - q* * [y1,y0]
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
208 = 2^LIMB_BITS * ([x2,x1] - q* * [y1]) + x0 - q* * y0
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
209 <= 2^LIMB_BITS * (y1 - 1) + x0 - q* * y0
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
210 <= 2^LIMB_BITS * (2^LIMB_BITS-2) + (2^LIMB_BITS-1) - 0
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
211 < 2^(2*LIMB_BITS)
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
212 <= 2 * [y1,y0]
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
213 So
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
214 [x2,x1,x0] < (q* + 2) * [y1,y0].
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
215 and so
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
216 q < q* + 2
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
217 which implies
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
218 q <= q* + 1.
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
219 In the other case, q* = 2^LIMB_BITS - 1. Then trivially
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
220 q < 2^LIMB_BITS = q* + 1.
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
221
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
222 We know that floor ([x2,x1] / [y1]) >= 2^LIMB_BITS if and
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
223 only if x2 >= y1. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
224 DOUBLE q =
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
225 (x2 >= y1
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
226 ? TWO_LIMB_BITS - L_(1.0)
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
227 : TRUNC ((x2 * TWO_LIMB_BITS + x1) / y1));
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
228 if (q > L_(0.0))
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
229 {
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
230 /* Compute
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
231 [x2,x1,x0] - q* * [y1,y0]
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
232 = 2^LIMB_BITS * ([x2,x1] - q* * [y1]) + x0 - q* * y0. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
233 DOUBLE q_y1 = q * y1; /* exact, at most 2*LIMB_BITS bits */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
234 DOUBLE q_y1_1 = TRUNC (q_y1 * TWO_LIMB_BITS_INVERSE);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
235 DOUBLE q_y1_0 = q_y1 - q_y1_1 * TWO_LIMB_BITS;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
236 DOUBLE q_y0 = q * y0; /* exact, at most MANT_DIG bits */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
237 DOUBLE q_y0_1 = TRUNC (q_y0 * TWO_LIMB_BITS_INVERSE);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
238 DOUBLE q_y0_0 = q_y0 - q_y0_1 * TWO_LIMB_BITS;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
239 x2 -= q_y1_1;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
240 x1 -= q_y1_0;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
241 x1 -= q_y0_1;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
242 x0 -= q_y0_0;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
243 /* Move negative carry from x0 to x1 and from x1 to x2. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
244 if (x0 < L_(0.0))
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
245 {
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
246 x0 += TWO_LIMB_BITS;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
247 x1 -= L_(1.0);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
248 }
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
249 if (x1 < L_(0.0))
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
250 {
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
251 x1 += TWO_LIMB_BITS;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
252 x2 -= L_(1.0);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
253 if (x1 < L_(0.0)) /* not sure this can happen */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
254 {
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
255 x1 += TWO_LIMB_BITS;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
256 x2 -= L_(1.0);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
257 }
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
258 }
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
259 if (x2 < L_(0.0))
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
260 {
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
261 /* Reduce q by 1. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
262 x1 += y1;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
263 x0 += y0;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
264 /* Move overflow from x0 to x1 and from x1 to x0. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
265 if (x0 >= TWO_LIMB_BITS)
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
266 {
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
267 x0 -= TWO_LIMB_BITS;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
268 x1 += L_(1.0);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
269 }
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
270 if (x1 >= TWO_LIMB_BITS)
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
271 {
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
272 x1 -= TWO_LIMB_BITS;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
273 x2 += L_(1.0);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
274 }
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
275 if (x2 < L_(0.0))
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
276 {
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
277 /* Reduce q by 1 again. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
278 x1 += y1;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
279 x0 += y0;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
280 /* Move overflow from x0 to x1 and from x1 to x0. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
281 if (x0 >= TWO_LIMB_BITS)
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
282 {
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
283 x0 -= TWO_LIMB_BITS;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
284 x1 += L_(1.0);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
285 }
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
286 if (x1 >= TWO_LIMB_BITS)
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
287 {
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
288 x1 -= TWO_LIMB_BITS;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
289 x2 += L_(1.0);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
290 }
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
291 if (x2 < L_(0.0))
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
292 /* Shouldn't happen, because we proved that
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
293 q >= q* - 2. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
294 abort ();
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
295 }
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
296 }
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
297 }
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
298 if (x2 > L_(0.0)
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
299 || x1 > y1
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
300 || (x1 == y1 && x0 >= y0))
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
301 {
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
302 /* Increase q by 1. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
303 x1 -= y1;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
304 x0 -= y0;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
305 /* Move negative carry from x0 to x1 and from x1 to x2. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
306 if (x0 < L_(0.0))
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
307 {
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
308 x0 += TWO_LIMB_BITS;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
309 x1 -= L_(1.0);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
310 }
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
311 if (x1 < L_(0.0))
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
312 {
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
313 x1 += TWO_LIMB_BITS;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
314 x2 -= L_(1.0);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
315 }
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
316 if (x2 < L_(0.0))
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
317 abort ();
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
318 if (x2 > L_(0.0)
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
319 || x1 > y1
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
320 || (x1 == y1 && x0 >= y0))
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
321 /* Shouldn't happen, because we proved that
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
322 q <= q* + 1. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
323 abort ();
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
324 }
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
325 /* Here [x2,x1,x0] < [y1,y0]. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
326 /* Next round. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
327 x2 = x1;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
328 #if (MANT_DIG + 1) / 2 > LIMB_BITS /* y0 can have a fractional bit */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
329 x1 = TRUNC (x0);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
330 x0 = (x0 - x1) * TWO_LIMB_BITS;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
331 #else
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
332 x1 = x0;
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
333 x0 = L_(0.0);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
334 #endif
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
335 /* Here [x2,x1,x0] < 2^LIMB_BITS * [y1,y0]. */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
336 }
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
337 /* Here k = 0.
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
338 The result is
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
339 2^(yexp-3*LIMB_BITS)
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
340 * (x2 * 2^(2*LIMB_BITS) + x1 * 2^LIMB_BITS + x0). */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
341 {
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
342 DOUBLE r =
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
343 LDEXP ((x2 * TWO_LIMB_BITS + x1) * TWO_LIMB_BITS + x0,
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
344 yexp - 3 * LIMB_BITS);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
345 return (negate ? - r : r);
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
346 }
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
347 }
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
348 }
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
349 }
16486
8b3ead70232c fmod-ieee: Work around test failures on OSF/1, mingw.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
350 else
8b3ead70232c fmod-ieee: Work around test failures on OSF/1, mingw.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
351 {
16565
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
352 if (ISNAN (x) || ISNAN (y))
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
353 return x + y; /* NaN */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
354 else if (isinf (y))
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
355 return x;
16486
8b3ead70232c fmod-ieee: Work around test failures on OSF/1, mingw.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
356 else
16565
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
357 /* x infinite or y zero */
0badbd4d62e4 fmod, fmodl: Fix computation for large quotients x / y.
Bruno Haible <bruno@clisp.org>
parents: 16486
diff changeset
358 return NAN;
16486
8b3ead70232c fmod-ieee: Work around test failures on OSF/1, mingw.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
359 }
8b3ead70232c fmod-ieee: Work around test failures on OSF/1, mingw.
Bruno Haible <bruno@clisp.org>
parents:
diff changeset
360 }