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 }