1 1.1 christos /* @(#)e_fmod.c 1.3 95/01/18 */ 2 1.1 christos /*- 3 1.1 christos * ==================================================== 4 1.1 christos * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. 5 1.1 christos * 6 1.1 christos * Developed at SunSoft, a Sun Microsystems, Inc. business. 7 1.1 christos * Permission to use, copy, modify, and distribute this 8 1.1 christos * software is freely granted, provided that this notice 9 1.1 christos * is preserved. 10 1.1 christos * ==================================================== 11 1.1 christos */ 12 1.1 christos 13 1.1 christos #include <sys/cdefs.h> 14 1.1 christos 15 1.2 mrg #include "namespace.h" 16 1.2 mrg 17 1.1 christos #include <float.h> 18 1.1 christos 19 1.1 christos #include "math.h" 20 1.1 christos #include "math_private.h" 21 1.1 christos 22 1.2 mrg #ifdef __weak_alias 23 1.2 mrg __weak_alias(remquo, _remquo) 24 1.2 mrg #endif 25 1.2 mrg 26 1.1 christos static const double Zero[] = {0.0, -0.0,}; 27 1.1 christos 28 1.1 christos /* 29 1.1 christos * Return the IEEE remainder and set *quo to the last n bits of the 30 1.1 christos * quotient, rounded to the nearest integer. We choose n=31 because 31 1.1 christos * we wind up computing all the integer bits of the quotient anyway as 32 1.1 christos * a side-effect of computing the remainder by the shift and subtract 33 1.1 christos * method. In practice, this is far more bits than are needed to use 34 1.1 christos * remquo in reduction algorithms. 35 1.1 christos */ 36 1.1 christos double 37 1.1 christos remquo(double x, double y, int *quo) 38 1.1 christos { 39 1.1 christos int32_t n,hx,hy,hz,ix,iy,sx,i; 40 1.1 christos u_int32_t lx,ly,lz,q,sxy; 41 1.1 christos 42 1.1 christos EXTRACT_WORDS(hx,lx,x); 43 1.1 christos EXTRACT_WORDS(hy,ly,y); 44 1.1 christos sxy = (hx ^ hy) & 0x80000000; 45 1.1 christos sx = hx&0x80000000; /* sign of x */ 46 1.1 christos hx ^=sx; /* |x| */ 47 1.1 christos hy &= 0x7fffffff; /* |y| */ 48 1.1 christos 49 1.1 christos /* purge off exception values */ 50 1.1 christos if((hy|ly)==0||(hx>=0x7ff00000)|| /* y=0,or x not finite */ 51 1.1 christos ((hy|((ly|-ly)>>31))>0x7ff00000)) /* or y is NaN */ 52 1.1 christos return (x*y)/(x*y); 53 1.1 christos if(hx<=hy) { 54 1.1 christos if((hx<hy)||(lx<ly)) { 55 1.1 christos q = 0; 56 1.1 christos goto fixup; /* |x|<|y| return x or x-y */ 57 1.1 christos } 58 1.1 christos if(lx==ly) { 59 1.3 gdt *quo = (sxy ? -1 : 1); 60 1.1 christos return Zero[(u_int32_t)sx>>31]; /* |x|=|y| return x*0*/ 61 1.1 christos } 62 1.1 christos } 63 1.1 christos 64 1.1 christos /* determine ix = ilogb(x) */ 65 1.1 christos if(hx<0x00100000) { /* subnormal x */ 66 1.1 christos if(hx==0) { 67 1.1 christos for (ix = -1043, i=lx; i>0; i<<=1) ix -=1; 68 1.1 christos } else { 69 1.1 christos for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1; 70 1.1 christos } 71 1.1 christos } else ix = (hx>>20)-1023; 72 1.1 christos 73 1.1 christos /* determine iy = ilogb(y) */ 74 1.1 christos if(hy<0x00100000) { /* subnormal y */ 75 1.1 christos if(hy==0) { 76 1.1 christos for (iy = -1043, i=ly; i>0; i<<=1) iy -=1; 77 1.1 christos } else { 78 1.1 christos for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1; 79 1.1 christos } 80 1.1 christos } else iy = (hy>>20)-1023; 81 1.1 christos 82 1.1 christos /* set up {hx,lx}, {hy,ly} and align y to x */ 83 1.1 christos if(ix >= -1022) 84 1.1 christos hx = 0x00100000|(0x000fffff&hx); 85 1.1 christos else { /* subnormal x, shift x to normal */ 86 1.1 christos n = -1022-ix; 87 1.1 christos if(n<=31) { 88 1.1 christos hx = (hx<<n)|(lx>>(32-n)); 89 1.1 christos lx <<= n; 90 1.1 christos } else { 91 1.1 christos hx = lx<<(n-32); 92 1.1 christos lx = 0; 93 1.1 christos } 94 1.1 christos } 95 1.1 christos if(iy >= -1022) 96 1.1 christos hy = 0x00100000|(0x000fffff&hy); 97 1.1 christos else { /* subnormal y, shift y to normal */ 98 1.1 christos n = -1022-iy; 99 1.1 christos if(n<=31) { 100 1.1 christos hy = (hy<<n)|(ly>>(32-n)); 101 1.1 christos ly <<= n; 102 1.1 christos } else { 103 1.1 christos hy = ly<<(n-32); 104 1.1 christos ly = 0; 105 1.1 christos } 106 1.1 christos } 107 1.1 christos 108 1.1 christos /* fix point fmod */ 109 1.1 christos n = ix - iy; 110 1.1 christos q = 0; 111 1.1 christos while(n--) { 112 1.1 christos hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1; 113 1.1 christos if(hz<0){hx = hx+hx+(lx>>31); lx = lx+lx;} 114 1.1 christos else {hx = hz+hz+(lz>>31); lx = lz+lz; q++;} 115 1.1 christos q <<= 1; 116 1.1 christos } 117 1.1 christos hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1; 118 1.1 christos if(hz>=0) {hx=hz;lx=lz;q++;} 119 1.1 christos 120 1.1 christos /* convert back to floating value and restore the sign */ 121 1.1 christos if((hx|lx)==0) { /* return sign(x)*0 */ 122 1.3 gdt q &= 0x7fffffff; 123 1.1 christos *quo = (sxy ? -q : q); 124 1.1 christos return Zero[(u_int32_t)sx>>31]; 125 1.1 christos } 126 1.1 christos while(hx<0x00100000) { /* normalize x */ 127 1.1 christos hx = hx+hx+(lx>>31); lx = lx+lx; 128 1.1 christos iy -= 1; 129 1.1 christos } 130 1.1 christos if(iy>= -1022) { /* normalize output */ 131 1.1 christos hx = ((hx-0x00100000)|((iy+1023)<<20)); 132 1.1 christos } else { /* subnormal output */ 133 1.1 christos n = -1022 - iy; 134 1.1 christos if(n<=20) { 135 1.1 christos lx = (lx>>n)|((u_int32_t)hx<<(32-n)); 136 1.1 christos hx >>= n; 137 1.1 christos } else if (n<=31) { 138 1.3 gdt lx = (hx<<(32-n))|(lx>>n); hx = 0; 139 1.1 christos } else { 140 1.3 gdt lx = hx>>(n-32); hx = 0; 141 1.1 christos } 142 1.1 christos } 143 1.1 christos fixup: 144 1.1 christos INSERT_WORDS(x,hx,lx); 145 1.1 christos y = fabs(y); 146 1.1 christos if (y < 0x1p-1021) { 147 1.1 christos if (x+x>y || (x+x==y && (q & 1))) { 148 1.1 christos q++; 149 1.1 christos x-=y; 150 1.1 christos } 151 1.1 christos } else if (x>0.5*y || (x==0.5*y && (q & 1))) { 152 1.1 christos q++; 153 1.1 christos x-=y; 154 1.1 christos } 155 1.1 christos GET_HIGH_WORD(hx,x); 156 1.1 christos SET_HIGH_WORD(x,hx^sx); 157 1.1 christos q &= 0x7fffffff; 158 1.1 christos *quo = (sxy ? -q : q); 159 1.4 gdt /* 160 1.4 gdt * If q is 0 and we need to return negative, we have to choose 161 1.4 gdt * the largest negative number (in 32 bits) because it is the 162 1.4 gdt * only value that is negative and congruent to 0 mod 2^31. 163 1.4 gdt */ 164 1.4 gdt if (q == 0 && sxy) 165 1.4 gdt *quo = 0x80000000; 166 1.1 christos return x; 167 1.1 christos } 168