1b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project 2b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project/* @(#)e_fmod.c 1.3 95/01/18 */ 3b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project/* 4b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project * ==================================================== 5b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. 6b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project * 7b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project * Developed at SunSoft, a Sun Microsystems, Inc. business. 8b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project * Permission to use, copy, modify, and distribute this 9b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project * software is freely granted, provided that this notice 10b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project * is preserved. 11b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project * ==================================================== 12b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project */ 13b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project 14b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project/* 15b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project * __ieee754_fmod(x,y) 16b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project * Return x mod y in exact arithmetic 17b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project * Method: shift and subtract 18b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project */ 19b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project 20b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project#include "fdlibm.h" 21b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project 22b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project#ifdef __STDC__ 23b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Projectstatic const double one = 1.0, Zero[] = {0.0, -0.0,}; 24b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project#else 25b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Projectstatic double one = 1.0, Zero[] = {0.0, -0.0,}; 26b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project#endif 27b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project 28b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project#ifdef __STDC__ 29b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project double __ieee754_fmod(double x, double y) 30b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project#else 31b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project double __ieee754_fmod(x,y) 32b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project double x,y ; 33b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project#endif 34b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project{ 35b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project int n,hx,hy,hz,ix,iy,sx,i; 36b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project unsigned lx,ly,lz; 37b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project 38b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project hx = __HI(x); /* high word of x */ 39b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project lx = __LO(x); /* low word of x */ 40b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project hy = __HI(y); /* high word of y */ 41b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project ly = __LO(y); /* low word of y */ 42b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project sx = hx&0x80000000; /* sign of x */ 43b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project hx ^=sx; /* |x| */ 44b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project hy &= 0x7fffffff; /* |y| */ 45b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project 46b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project /* purge off exception values */ 47b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project if((hy|ly)==0||(hx>=0x7ff00000)|| /* y=0,or x not finite */ 48b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project ((hy|((ly|-ly)>>31))>0x7ff00000)) /* or y is NaN */ 49b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project return (x*y)/(x*y); 50b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project if(hx<=hy) { 51b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project if((hx<hy)||(lx<ly)) return x; /* |x|<|y| return x */ 52b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project if(lx==ly) 53b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project return Zero[(unsigned)sx>>31]; /* |x|=|y| return x*0*/ 54b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project } 55b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project 56b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project /* determine ix = ieee_ilogb(x) */ 57b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project if(hx<0x00100000) { /* subnormal x */ 58b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project if(hx==0) { 59b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project for (ix = -1043, i=lx; i>0; i<<=1) ix -=1; 60b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project } else { 61b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project for (ix = -1022,i=(hx<<11); i>0; i<<=1) ix -=1; 62b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project } 63b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project } else ix = (hx>>20)-1023; 64b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project 65b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project /* determine iy = ieee_ilogb(y) */ 66b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project if(hy<0x00100000) { /* subnormal y */ 67b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project if(hy==0) { 68b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project for (iy = -1043, i=ly; i>0; i<<=1) iy -=1; 69b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project } else { 70b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project for (iy = -1022,i=(hy<<11); i>0; i<<=1) iy -=1; 71b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project } 72b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project } else iy = (hy>>20)-1023; 73b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project 74b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project /* set up {hx,lx}, {hy,ly} and align y to x */ 75b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project if(ix >= -1022) 76b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project hx = 0x00100000|(0x000fffff&hx); 77b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project else { /* subnormal x, shift x to normal */ 78b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project n = -1022-ix; 79b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project if(n<=31) { 80b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project hx = (hx<<n)|(lx>>(32-n)); 81b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project lx <<= n; 82b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project } else { 83b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project hx = lx<<(n-32); 84b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project lx = 0; 85b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project } 86b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project } 87b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project if(iy >= -1022) 88b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project hy = 0x00100000|(0x000fffff&hy); 89b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project else { /* subnormal y, shift y to normal */ 90b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project n = -1022-iy; 91b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project if(n<=31) { 92b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project hy = (hy<<n)|(ly>>(32-n)); 93b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project ly <<= n; 94b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project } else { 95b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project hy = ly<<(n-32); 96b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project ly = 0; 97b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project } 98b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project } 99b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project 100b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project /* fix point fmod */ 101b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project n = ix - iy; 102b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project while(n--) { 103b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1; 104b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project if(hz<0){hx = hx+hx+(lx>>31); lx = lx+lx;} 105b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project else { 106b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project if((hz|lz)==0) /* return sign(x)*0 */ 107b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project return Zero[(unsigned)sx>>31]; 108b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project hx = hz+hz+(lz>>31); lx = lz+lz; 109b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project } 110b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project } 111b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1; 112b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project if(hz>=0) {hx=hz;lx=lz;} 113b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project 114b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project /* convert back to floating value and restore the sign */ 115b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project if((hx|lx)==0) /* return sign(x)*0 */ 116b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project return Zero[(unsigned)sx>>31]; 117b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project while(hx<0x00100000) { /* normalize x */ 118b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project hx = hx+hx+(lx>>31); lx = lx+lx; 119b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project iy -= 1; 120b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project } 121b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project if(iy>= -1022) { /* normalize output */ 122b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project hx = ((hx-0x00100000)|((iy+1023)<<20)); 123b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project __HI(x) = hx|sx; 124b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project __LO(x) = lx; 125b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project } else { /* subnormal output */ 126b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project n = -1022 - iy; 127b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project if(n<=20) { 128b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project lx = (lx>>n)|((unsigned)hx<<(32-n)); 129b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project hx >>= n; 130b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project } else if (n<=31) { 131b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project lx = (hx<<(32-n))|(lx>>n); hx = sx; 132b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project } else { 133b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project lx = hx>>(n-32); hx = sx; 134b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project } 135b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project __HI(x) = hx|sx; 136b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project __LO(x) = lx; 137b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project x *= one; /* create necessary signal */ 138b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project } 139b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project return x; /* exact output */ 140b07e1d9fd8d9e4e03698e0bd9bf77154c5390326The Android Open Source Project} 141