amath  1.8.5
Simple command line calculator
fmod.c
Go to the documentation of this file.
1 /*-
2  * Copyright (c) 2014-2018 Carsten Sonne Larsen <cs@innolan.net>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  *
25  * Project homepage:
26  * https://amath.innolan.net
27  *
28  * The original source code can be obtained from:
29  * http://www.netlib.org/fdlibm/e_fmod.c
30  *
31  * =================================================================
32  * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
33  *
34  * Developed at SunSoft, a Sun Microsystems, Inc. business.
35  * Permission to use, copy, modify, and distribute this
36  * software is freely granted, provided that this notice
37  * is preserved.
38  * =================================================================
39  */
40 
41 /**
42  * @file fmod.c
43  * @brief Return x mod y in exact arithmetic
44  */
45 
46 #include "prim.h"
47 
48 static const double
49  one = 1.0,
50  Zero[] = {
51  0.0, -0.0,
52 };
53 
54 /**
55  * @brief Return x mod y in exact arithmetic
56  * @details Method: Shift and subtract
57  */
58 double fmod(double x, double y)
59 {
60  int32_t n, hx, hy, hz, ix, iy, sx, i;
61  uint32_t lx, ly, lz;
62 
63  EXTRACT_WORDS(hx, lx, x);
64  EXTRACT_WORDS(hy, ly, y);
65  sx = hx & 0x80000000; /* sign of x */
66  hx ^= sx; /* |x| */
67  hy &= 0x7fffffff; /* |y| */
68 
69  /* purge off exception values */
70  if ((hy | ly) == 0 || (hx >= 0x7ff00000) || /* y=0,or x not finite */
71  ((hy | ((ly | -ly) >> 31)) > 0x7ff00000)) /* or y is NaN */
72  return (x * y) / (x * y);
73  if (hx <= hy)
74  {
75  if ((hx < hy) || (lx < ly))
76  return x; /* |x|<|y| return x */
77  if (lx == ly)
78  return Zero[(uint32_t)sx >> 31]; /* |x|=|y| return x*0*/
79  }
80 
81  /* determine ix = ilogb(x) */
82  if (hx < 0x00100000)
83  { /* subnormal x */
84  if (hx == 0)
85  {
86  for (ix = -1043, i = lx; i > 0; i <<= 1)
87  ix -= 1;
88  }
89  else
90  {
91  for (ix = -1022, i = (hx << 11); i > 0; i <<= 1)
92  ix -= 1;
93  }
94  }
95  else
96  ix = (hx >> 20) - 1023;
97 
98  /* determine iy = ilogb(y) */
99  if (hy < 0x00100000)
100  { /* subnormal y */
101  if (hy == 0)
102  {
103  for (iy = -1043, i = ly; i > 0; i <<= 1)
104  iy -= 1;
105  }
106  else
107  {
108  for (iy = -1022, i = (hy << 11); i > 0; i <<= 1)
109  iy -= 1;
110  }
111  }
112  else
113  iy = (hy >> 20) - 1023;
114 
115  /* set up {hx,lx}, {hy,ly} and align y to x */
116  if (ix >= -1022)
117  hx = 0x00100000 | (0x000fffff & hx);
118  else
119  { /* subnormal x, shift x to normal */
120  n = -1022 - ix;
121  if (n <= 31)
122  {
123  hx = (hx << n) | (lx >> (32 - n));
124  lx <<= n;
125  }
126  else
127  {
128  hx = lx << (n - 32);
129  lx = 0;
130  }
131  }
132  if (iy >= -1022)
133  hy = 0x00100000 | (0x000fffff & hy);
134  else
135  { /* subnormal y, shift y to normal */
136  n = -1022 - iy;
137  if (n <= 31)
138  {
139  hy = (hy << n) | (ly >> (32 - n));
140  ly <<= n;
141  }
142  else
143  {
144  hy = ly << (n - 32);
145  ly = 0;
146  }
147  }
148 
149  /* fix point fmod */
150  n = ix - iy;
151  while (n--)
152  {
153  hz = hx - hy;
154  lz = lx - ly;
155  if (lx < ly)
156  hz -= 1;
157  if (hz < 0)
158  {
159  hx = hx + hx + (lx >> 31);
160  lx = lx + lx;
161  }
162  else
163  {
164  if ((hz | lz) == 0) /* return sign(x)*0 */
165  return Zero[(uint32_t)sx >> 31];
166  hx = hz + hz + (lz >> 31);
167  lx = lz + lz;
168  }
169  }
170  hz = hx - hy;
171  lz = lx - ly;
172  if (lx < ly)
173  hz -= 1;
174  if (hz >= 0)
175  {
176  hx = hz;
177  lx = lz;
178  }
179 
180  /* convert back to floating value and restore the sign */
181  if ((hx | lx) == 0) /* return sign(x)*0 */
182  return Zero[(unsigned)sx >> 31];
183  while (hx < 0x00100000)
184  { /* normalize x */
185  hx = hx + hx + (lx >> 31);
186  lx = lx + lx;
187  iy -= 1;
188  }
189  if (iy >= -1022)
190  { /* normalize output */
191  hx = ((hx - 0x00100000) | ((iy + 1023) << 20));
192  INSERT_WORDS(x, hx | sx, lx);
193  }
194  else
195  { /* subnormal output */
196  n = -1022 - iy;
197  if (n <= 20)
198  {
199  lx = (lx >> n) | ((uint32_t)hx << (32 - n));
200  hx >>= n;
201  }
202  else if (n <= 31)
203  {
204  lx = (hx << (32 - n)) | (lx >> n);
205  hx = sx;
206  }
207  else
208  {
209  lx = hx >> (n - 32);
210  hx = sx;
211  }
212  INSERT_WORDS(x, hx | sx, lx);
213  x *= one; /* create necessary signal */
214  }
215  return x; /* exact output */
216 }
#define INSERT_WORDS(d, ix0, ix1)
Set a double from two 32 bit ints.
Definition: prim.h:187
static const double Zero[]
Definition: fmod.c:50
#define EXTRACT_WORDS(ix0, ix1, d)
Get two 32 bit ints from a double.
Definition: prim.h:156
double fmod(double x, double y)
Return x mod y in exact arithmetic.
Definition: fmod.c:58
static const double one
Definition: fmod.c:49