1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 22 /* 23 * Copyright 2011 Nexenta Systems, Inc. All rights reserved. 24 */ 25 26 /* 27 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 28 * Use is subject to license terms. 29 */ 30 31 #pragma weak __remquo = remquo 32 33 34 /* 35 * double remquo(double x, double y, int *quo) return remainder(x,y) and an 36 * integer pointer quo such that *quo = N mod {2**31}, where N is the 37 * exact integral part of x/y rounded to nearest even. 38 * 39 * remquo call internal fmodquo 40 */ 41 42 #include "libm.h" 43 #include "libm_protos.h" 44 #include <math.h> /* fabs() */ 45 #include <sys/isa_defs.h> 46 47 #if defined(_BIG_ENDIAN) 48 #define HIWORD 0 49 #define LOWORD 1 50 #else 51 #define HIWORD 1 52 #define LOWORD 0 53 #endif 54 #define __HI(x) ((int *)&x)[HIWORD] 55 #define __LO(x) ((int *)&x)[LOWORD] 56 57 static const double one = 1.0, Zero[] = { 0.0, -0.0 }; 58 static double 59 fmodquo(double x, double y, int *quo) 60 { 61 int n, hx, hy, hz, ix, iy, sx, sq, i, m; 62 unsigned lx, ly, lz; 63 64 hx = __HI(x); /* high word of x */ 65 lx = __LO(x); /* low word of x */ 66 hy = __HI(y); /* high word of y */ 67 ly = __LO(y); /* low word of y */ 68 sx = hx & 0x80000000; /* sign of x */ 69 sq = (hx ^ hy) & 0x80000000; /* sign of x/y */ 70 hx ^= sx; /* |x| */ 71 hy &= 0x7fffffff; /* |y| */ 72 73 /* purge off exception values */ 74 *quo = 0; 75 76 if ((hy | ly) == 0 || hx >= 0x7ff00000 || /* y=0, or x !finite */ 77 (hy | ((ly | -ly) >> 31)) > 0x7ff00000) /* or y is NaN */ 78 return ((x * y) / (x * y)); 79 80 if (hx <= hy) { 81 if (hx < hy || lx < ly) 82 return (x); /* |x|<|y| return x */ 83 84 if (lx == ly) { 85 *quo = 1 + (sq >> 30); 86 /* |x|=|y| return x*0 */ 87 return (Zero[(unsigned)sx >> 31]); 88 } 89 } 90 91 /* determine ix = ilogb(x) */ 92 if (hx < 0x00100000) { /* subnormal x */ 93 if (hx == 0) { 94 for (ix = -1043, i = lx; i > 0; i <<= 1) 95 ix -= 1; 96 } else { 97 for (ix = -1022, i = (hx << 11); i > 0; i <<= 1) 98 ix -= 1; 99 } 100 } else { 101 ix = (hx >> 20) - 1023; 102 } 103 104 /* determine iy = ilogb(y) */ 105 if (hy < 0x00100000) { /* subnormal y */ 106 if (hy == 0) { 107 for (iy = -1043, i = ly; i > 0; i <<= 1) 108 iy -= 1; 109 } else { 110 for (iy = -1022, i = (hy << 11); i > 0; i <<= 1) 111 iy -= 1; 112 } 113 } else { 114 iy = (hy >> 20) - 1023; 115 } 116 117 /* set up {hx,lx}, {hy,ly} and align y to x */ 118 if (ix >= -1022) { 119 hx = 0x00100000 | (0x000fffff & hx); 120 } else { /* subnormal x, shift x to normal */ 121 n = -1022 - ix; 122 123 if (n <= 31) { 124 hx = (hx << n) | (lx >> (32 - n)); 125 lx <<= n; 126 } else { 127 hx = lx << (n - 32); 128 lx = 0; 129 } 130 } 131 132 if (iy >= -1022) { 133 hy = 0x00100000 | (0x000fffff & hy); 134 } else { /* subnormal y, shift y to normal */ 135 n = -1022 - iy; 136 137 if (n <= 31) { 138 hy = (hy << n) | (ly >> (32 - n)); 139 ly <<= n; 140 } else { 141 hy = ly << (n - 32); 142 ly = 0; 143 } 144 } 145 146 /* fix point fmod */ 147 n = ix - iy; 148 m = 0; 149 150 while (n--) { 151 hz = hx - hy; 152 lz = lx - ly; 153 154 if (lx < ly) 155 hz -= 1; 156 157 if (hz < 0) { 158 hx = hx + hx + (lx >> 31); 159 lx = lx + lx; 160 } else { 161 m += 1; 162 163 if ((hz | lz) == 0) { /* return sign(x)*0 */ 164 if (n < 31) 165 m <<= 1 + n; 166 else 167 m = 0; 168 169 m &= 0x7fffffff; 170 *quo = sq >= 0 ? m : -m; 171 return (Zero[(unsigned)sx >> 31]); 172 } 173 174 hx = hz + hz + (lz >> 31); 175 lx = lz + lz; 176 } 177 178 m += m; 179 } 180 181 hz = hx - hy; 182 lz = lx - ly; 183 184 if (lx < ly) 185 hz -= 1; 186 187 if (hz >= 0) { 188 hx = hz; 189 lx = lz; 190 m += 1; 191 } 192 193 m &= 0x7fffffff; 194 *quo = sq >= 0 ? m : -m; 195 196 /* convert back to floating value and restore the sign */ 197 if ((hx | lx) == 0) /* return sign(x)*0 */ 198 return (Zero[(unsigned)sx >> 31]); 199 200 while (hx < 0x00100000) { /* normalize x */ 201 hx = hx + hx + (lx >> 31); 202 lx = lx + lx; 203 iy -= 1; 204 } 205 206 if (iy >= -1022) { /* normalize output */ 207 hx = (hx - 0x00100000) | ((iy + 1023) << 20); 208 __HI(x) = hx | sx; 209 __LO(x) = lx; 210 } else { /* subnormal output */ 211 n = -1022 - iy; 212 213 if (n <= 20) { 214 lx = (lx >> n) | ((unsigned)hx << (32 - n)); 215 hx >>= n; 216 } else if (n <= 31) { 217 lx = (hx << (32 - n)) | (lx >> n); 218 hx = sx; 219 } else { 220 lx = hx >> (n - 32); 221 hx = sx; 222 } 223 224 __HI(x) = hx | sx; 225 __LO(x) = lx; 226 x *= one; /* create necessary signal */ 227 } 228 229 return (x); /* exact output */ 230 } 231 232 #define zero Zero[0] 233 234 double 235 remquo(double x, double y, int *quo) 236 { 237 int hx, hy, sx, sq; 238 double v; 239 unsigned ly; 240 241 hx = __HI(x); /* high word of x */ 242 hy = __HI(y); /* high word of y */ 243 ly = __LO(y); /* low word of y */ 244 sx = hx & 0x80000000; /* sign of x */ 245 sq = (hx ^ hy) & 0x80000000; /* sign of x/y */ 246 hx ^= sx; /* |x| */ 247 hy &= 0x7fffffff; /* |y| */ 248 249 /* purge off exception values */ 250 *quo = 0; 251 252 if ((hy | ly) == 0 || hx >= 0x7ff00000 || /* y=0, or x !finite */ 253 (hy | ((ly | -ly) >> 31)) > 0x7ff00000) /* or y is NaN */ 254 return ((x * y) / (x * y)); 255 256 y = fabs(y); 257 x = fabs(x); 258 259 if (hy <= 0x7fdfffff) { 260 x = fmodquo(x, y + y, quo); 261 *quo = ((*quo) & 0x3fffffff) << 1; 262 } 263 264 if (hy < 0x00200000) { 265 if (x + x > y) { 266 *quo += 1; 267 268 if (x == y) 269 x = zero; 270 else 271 x -= y; 272 273 if (x + x >= y) { 274 x -= y; 275 *quo += 1; 276 } 277 } 278 } else { 279 v = 0.5 * y; 280 281 if (x > v) { 282 *quo += 1; 283 284 if (x == y) 285 x = zero; 286 else 287 x -= y; 288 289 if (x >= v) { 290 x -= y; 291 *quo += 1; 292 } 293 } 294 } 295 296 if (sq != 0) 297 *quo = -(*quo); 298 299 return (sx == 0 ? x : -x); 300 }