POK
|
00001 /* 00002 * POK header 00003 * 00004 * The following file is a part of the POK project. Any modification should 00005 * made according to the POK licence. You CANNOT use this file or a part of 00006 * this file is this part of a file for your own project 00007 * 00008 * For more information on the POK licence, please see our LICENCE FILE 00009 * 00010 * Please follow the coding guidelines described in doc/CODING_GUIDELINES 00011 * 00012 * Copyright (c) 2007-2009 POK team 00013 * 00014 * Created by julien on Fri Jan 30 14:41:34 2009 00015 */ 00016 00017 /* e_fmodf.c -- float version of e_fmod.c. 00018 * Conversion to float by Ian Lance Taylor, Cygnus Support, ian@cygnus.com. 00019 */ 00020 00021 /* 00022 * ==================================================== 00023 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. 00024 * 00025 * Developed at SunPro, a Sun Microsystems, Inc. business. 00026 * Permission to use, copy, modify, and distribute this 00027 * software is freely granted, provided that this notice 00028 * is preserved. 00029 * ==================================================== 00030 */ 00031 00032 /* 00033 * __ieee754_fmodf(x,y) 00034 * Return x mod y in exact arithmetic 00035 * Method: shift and subtract 00036 */ 00037 00038 #ifdef POK_NEEDS_LIBMATH 00039 00040 #include "math_private.h" 00041 00042 static const float one = 1.0, Zero[] = {0.0, -0.0,}; 00043 00044 float 00045 __ieee754_fmodf(float x, float y) 00046 { 00047 int32_t n,hx,hy,hz,ix,iy,sx,i; 00048 00049 GET_FLOAT_WORD(hx,x); 00050 GET_FLOAT_WORD(hy,y); 00051 sx = hx&0x80000000; /* sign of x */ 00052 hx ^=sx; /* |x| */ 00053 hy &= 0x7fffffff; /* |y| */ 00054 00055 /* purge off exception values */ 00056 if(hy==0||(hx>=0x7f800000)|| /* y=0,or x not finite */ 00057 (hy>0x7f800000)) /* or y is NaN */ 00058 return (x*y)/(x*y); 00059 if(hx<hy) return x; /* |x|<|y| return x */ 00060 if(hx==hy) 00061 return Zero[(uint32_t)sx>>31]; /* |x|=|y| return x*0*/ 00062 00063 /* determine ix = ilogb(x) */ 00064 if(hx<0x00800000) { /* subnormal x */ 00065 for (ix = -126,i=(hx<<8); i>0; i<<=1) ix -=1; 00066 } else ix = (hx>>23)-127; 00067 00068 /* determine iy = ilogb(y) */ 00069 if(hy<0x00800000) { /* subnormal y */ 00070 for (iy = -126,i=(hy<<8); i>=0; i<<=1) iy -=1; 00071 } else iy = (hy>>23)-127; 00072 00073 /* set up {hx,lx}, {hy,ly} and align y to x */ 00074 if(ix >= -126) 00075 hx = 0x00800000|(0x007fffff&hx); 00076 else { /* subnormal x, shift x to normal */ 00077 n = -126-ix; 00078 hx = hx<<n; 00079 } 00080 if(iy >= -126) 00081 hy = 0x00800000|(0x007fffff&hy); 00082 else { /* subnormal y, shift y to normal */ 00083 n = -126-iy; 00084 hy = hy<<n; 00085 } 00086 00087 /* fix point fmod */ 00088 n = ix - iy; 00089 while(n--) { 00090 hz=hx-hy; 00091 if(hz<0){hx = hx+hx;} 00092 else { 00093 if(hz==0) /* return sign(x)*0 */ 00094 return Zero[(uint32_t)sx>>31]; 00095 hx = hz+hz; 00096 } 00097 } 00098 hz=hx-hy; 00099 if(hz>=0) {hx=hz;} 00100 00101 /* convert back to floating value and restore the sign */ 00102 if(hx==0) /* return sign(x)*0 */ 00103 return Zero[(uint32_t)sx>>31]; 00104 while(hx<0x00800000) { /* normalize x */ 00105 hx = hx+hx; 00106 iy -= 1; 00107 } 00108 if(iy>= -126) { /* normalize output */ 00109 hx = ((hx-0x00800000)|((iy+127)<<23)); 00110 SET_FLOAT_WORD(x,hx|sx); 00111 } else { /* subnormal output */ 00112 n = -126 - iy; 00113 hx >>= n; 00114 SET_FLOAT_WORD(x,hx|sx); 00115 x *= one; /* create necessary signal */ 00116 } 00117 return x; /* exact output */ 00118 } 00119 00120 #endif 00121