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 __fmodl = fmodl
  32 
  33 #include "libm.h"
  34 
  35 static const int is = -0x7fffffff - 1, im = 0x0000ffff, iu = 0x00010000;
  36 static const long double zero = 0.0L, one = 1.0L;
  37 
  38 #ifdef __LITTLE_ENDIAN
  39 #define __H0(x)         *(3 + (int *)&x)
  40 #define __H1(x)         *(2 + (int *)&x)
  41 #define __H2(x)         *(1 + (int *)&x)
  42 #define __H3(x)         *(0 + (int *)&x)
  43 #else
  44 #define __H0(x)         *(0 + (int *)&x)
  45 #define __H1(x)         *(1 + (int *)&x)
  46 #define __H2(x)         *(2 + (int *)&x)
  47 #define __H3(x)         *(3 + (int *)&x)
  48 #endif
  49 
  50 long double
  51 fmodl(long double x, long double y)
  52 {
  53         long double a, b;
  54         int n, ix, iy, k, sx;
  55         int hx;
  56         int x0, y0, z0, carry;
  57         unsigned x1, x2, x3, y1, y2, y3, z1, z2, z3;
  58 
  59         hx = __H0(x);
  60         x1 = __H1(x);
  61         x2 = __H2(x);
  62         x3 = __H3(x);
  63         y0 = __H0(y);
  64         y1 = __H1(y);
  65         y2 = __H2(y);
  66         y3 = __H3(y);
  67 
  68         sx = hx & 0x80000000;
  69         x0 = hx ^ sx;
  70         y0 &= 0x7fffffff;
  71 
  72         /* purge off exception values */
  73         if (x0 >= 0x7fff0000 ||              /* !finitel(x) */
  74             (y0 > 0x7fff0000) || (y0 == 0x7fff0000 && ((y1 | y2 | y3) != 0)) ||
  75             (y0 | y1 | y2 | y3) == 0)   /* isnanl(y) || y = 0 */
  76                 return ((x * y) / (x * y));
  77 
  78         a = fabsl(x);
  79         b = fabsl(y);
  80 
  81         if (a <= b) {
  82                 if (a < b)
  83                         return (x);
  84                 else
  85                         return (zero * x);
  86         }
  87 
  88         /* determine ix = ilogbl(x) */
  89         if (x0 < iu) {                       /* subnormal x */
  90                 ix = -16382;
  91 
  92                 while (x0 == 0) {
  93                         ix -= 16;
  94                         x0 = x1 >> 16;
  95                         x1 = (x1 << 16) | (x2 >> 16);
  96                         x2 = (x2 << 16) | (x3 >> 16);
  97                         x3 = (x3 << 16);
  98                 }
  99 
 100                 while (x0 < iu) {
 101                         ix -= 1;
 102                         x0 = (x0 << 1) | (x1 >> 31);
 103                         x1 = (x1 << 1) | (x2 >> 31);
 104                         x2 = (x2 << 1) | (x3 >> 31);
 105                         x3 <<= 1;
 106                 }
 107         } else {
 108                 ix = (x0 >> 16) - 16383;
 109                 x0 = iu | (x0 & im);
 110         }
 111 
 112         /* determine iy = ilogbl(y) */
 113         if (y0 < iu) {                       /* subnormal y */
 114                 iy = -16382;
 115 
 116                 while (y0 == 0) {
 117                         iy -= 16;
 118                         y0 = y1 >> 16;
 119                         y1 = (y1 << 16) | (y2 >> 16);
 120                         y2 = (y2 << 16) | (y3 >> 16);
 121                         y3 = (y3 << 16);
 122                 }
 123 
 124                 while (y0 < iu) {
 125                         iy -= 1;
 126                         y0 = (y0 << 1) | (y1 >> 31);
 127                         y1 = (y1 << 1) | (y2 >> 31);
 128                         y2 = (y2 << 1) | (y3 >> 31);
 129                         y3 <<= 1;
 130                 }
 131         } else {
 132                 iy = (y0 >> 16) - 16383;
 133                 y0 = iu | (y0 & im);
 134         }
 135 
 136         /* fix point fmod */
 137         n = ix - iy;
 138 
 139         while (n--) {
 140                 while (x0 == 0 && n >= 16) {
 141                         n -= 16;
 142                         x0 = x1 >> 16;
 143                         x1 = (x1 << 16) | (x2 >> 16);
 144                         x2 = (x2 << 16) | (x3 >> 16);
 145                         x3 = (x3 << 16);
 146                 }
 147 
 148                 while (x0 < iu && n >= 1) {
 149                         n -= 1;
 150                         x0 = (x0 << 1) | (x1 >> 31);
 151                         x1 = (x1 << 1) | (x2 >> 31);
 152                         x2 = (x2 << 1) | (x3 >> 31);
 153                         x3 = (x3 << 1);
 154                 }
 155 
 156                 carry = 0;
 157                 z3 = x3 - y3;
 158                 carry = (z3 > x3);
 159 
 160                 if (carry == 0) {
 161                         z2 = x2 - y2;
 162                         carry = (z2 > x2);
 163                 } else {
 164                         z2 = x2 - y2 - 1;
 165                         carry = (z2 >= x2);
 166                 }
 167 
 168                 if (carry == 0) {
 169                         z1 = x1 - y1;
 170                         carry = (z1 > x1);
 171                 } else {
 172                         z1 = x1 - y1 - 1;
 173                         carry = (z1 >= x1);
 174                 }
 175 
 176                 z0 = x0 - y0 - carry;
 177 
 178                 if (z0 < 0) {                /* double x */
 179                         x0 = x0 + x0 + ((x1 & is) != 0);
 180                         x1 = x1 + x1 + ((x2 & is) != 0);
 181                         x2 = x2 + x2 + ((x3 & is) != 0);
 182                         x3 = x3 + x3;
 183                 } else {
 184                         if (z0 == 0) {
 185                                 if ((z1 | z2 | z3) == 0) {      /* 0: done */
 186                                         __H0(a) = hx & is;
 187                                         __H1(a) = __H2(a) = __H3(a) = 0;
 188                                         return (a);
 189                                 }
 190                         }
 191 
 192                         /* x = z << 1 */
 193                         z0 = z0 + z0 + ((z1 & is) != 0);
 194                         z1 = z1 + z1 + ((z2 & is) != 0);
 195                         z2 = z2 + z2 + ((z3 & is) != 0);
 196                         z3 = z3 + z3;
 197                         x0 = z0;
 198                         x1 = z1;
 199                         x2 = z2;
 200                         x3 = z3;
 201                 }
 202         }
 203 
 204         carry = 0;
 205         z3 = x3 - y3;
 206         carry = (z3 > x3);
 207 
 208         if (carry == 0) {
 209                 z2 = x2 - y2;
 210                 carry = (z2 > x2);
 211         } else {
 212                 z2 = x2 - y2 - 1;
 213                 carry = (z2 >= x2);
 214         }
 215 
 216         if (carry == 0) {
 217                 z1 = x1 - y1;
 218                 carry = (z1 > x1);
 219         } else {
 220                 z1 = x1 - y1 - 1;
 221                 carry = (z1 >= x1);
 222         }
 223 
 224         z0 = x0 - y0 - carry;
 225 
 226         if (z0 >= 0) {
 227                 x0 = z0;
 228                 x1 = z1;
 229                 x2 = z2;
 230                 x3 = z3;
 231         }
 232 
 233         /* convert back to floating value and restore the sign */
 234         if ((x0 | x1 | x2 | x3) == 0) {
 235                 __H0(a) = hx & is;
 236                 __H1(a) = __H2(a) = __H3(a) = 0;
 237                 return (a);
 238         }
 239 
 240         while (x0 < iu) {
 241                 if (x0 == 0) {
 242                         iy -= 16;
 243                         x0 = x1 >> 16;
 244                         x1 = (x1 << 16) | (x2 >> 16);
 245                         x2 = (x2 << 16) | (x3 >> 16);
 246                         x3 = (x3 << 16);
 247                 } else {
 248                         x0 = x0 + x0 + ((x1 & is) != 0);
 249                         x1 = x1 + x1 + ((x2 & is) != 0);
 250                         x2 = x2 + x2 + ((x3 & is) != 0);
 251                         x3 = x3 + x3;
 252                         iy -= 1;
 253                 }
 254         }
 255 
 256         /* normalize output */
 257         if (iy >= -16382) {
 258                 __H0(a) = sx | (x0 - iu) | ((iy + 16383) << 16);
 259                 __H1(a) = x1;
 260                 __H2(a) = x2;
 261                 __H3(a) = x3;
 262         } else {                        /* subnormal output */
 263                 n = -16382 - iy;
 264                 k = n & 31;
 265 
 266                 if (k != 0) {
 267                         if (k <= 16) {
 268                                 x3 = (x2 << (32 - k)) | (x3 >> k);
 269                                 x2 = (x1 << (32 - k)) | (x2 >> k);
 270                                 x1 = (x0 << (32 - k)) | (x1 >> k);
 271                                 x0 >>= k;
 272                         } else {
 273                                 x3 = (x2 << (32 - k)) | (x3 >> k);
 274                                 x2 = (x1 << (32 - k)) | (x2 >> k);
 275                                 x1 = (x0 << (32 - k)) | (x1 >> k);
 276                                 x0 = 0;
 277                         }
 278                 }
 279 
 280                 while (n >= 32) {
 281                         n -= 32;
 282                         x3 = x2;
 283                         x2 = x1;
 284                         x1 = x0;
 285                         x0 = 0;
 286                 }
 287 
 288                 __H0(a) = x0 | sx;
 289                 __H1(a) = x1;
 290                 __H2(a) = x2;
 291                 __H3(a) = x3;
 292                 a *= one;
 293         }
 294 
 295         return (a);
 296 }