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 /* s_expm1f.c -- float version of s_expm1.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 #ifdef POK_NEEDS_LIBMATH 00033 00034 #include <libm.h> 00035 #include "math_private.h" 00036 00037 static const float huge = 1.0e+30, tiny = 1.0e-30; 00038 00039 static const float 00040 one = 1.0, 00041 o_threshold = 8.8721679688e+01,/* 0x42b17180 */ 00042 ln2_hi = 6.9313812256e-01,/* 0x3f317180 */ 00043 ln2_lo = 9.0580006145e-06,/* 0x3717f7d1 */ 00044 invln2 = 1.4426950216e+00,/* 0x3fb8aa3b */ 00045 /* scaled coefficients related to expm1 */ 00046 Q1 = -3.3333335072e-02, /* 0xbd088889 */ 00047 Q2 = 1.5873016091e-03, /* 0x3ad00d01 */ 00048 Q3 = -7.9365076090e-05, /* 0xb8a670cd */ 00049 Q4 = 4.0082177293e-06, /* 0x36867e54 */ 00050 Q5 = -2.0109921195e-07; /* 0xb457edbb */ 00051 00052 float 00053 expm1f(float x) 00054 { 00055 float y,hi,lo,c,t,e,hxs,hfx,r1; 00056 int32_t k,xsb; 00057 uint32_t hx; 00058 00059 c = 0; 00060 GET_FLOAT_WORD(hx,x); 00061 xsb = hx&0x80000000; /* sign bit of x */ 00062 if(xsb==0) y=x; else y= -x; /* y = |x| */ 00063 hx &= 0x7fffffff; /* high word of |x| */ 00064 00065 /* filter out huge and non-finite argument */ 00066 if(hx >= 0x4195b844) { /* if |x|>=27*ln2 */ 00067 if(hx >= 0x42b17218) { /* if |x|>=88.721... */ 00068 if(hx>0x7f800000) 00069 return x+x; /* NaN */ 00070 if(hx==0x7f800000) 00071 return (xsb==0)? x:-1.0;/* exp(+-inf)={inf,-1} */ 00072 if(x > o_threshold) return huge*huge; /* overflow */ 00073 } 00074 if(xsb!=0) { /* x < -27*ln2, return -1.0 with inexact */ 00075 if(x+tiny<(float)0.0) /* raise inexact */ 00076 return tiny-one; /* return -1 */ 00077 } 00078 } 00079 00080 /* argument reduction */ 00081 if(hx > 0x3eb17218) { /* if |x| > 0.5 ln2 */ 00082 if(hx < 0x3F851592) { /* and |x| < 1.5 ln2 */ 00083 if(xsb==0) 00084 {hi = x - ln2_hi; lo = ln2_lo; k = 1;} 00085 else 00086 {hi = x + ln2_hi; lo = -ln2_lo; k = -1;} 00087 } else { 00088 k = invln2*x+((xsb==0)?(float)0.5:(float)-0.5); 00089 t = k; 00090 hi = x - t*ln2_hi; /* t*ln2_hi is exact here */ 00091 lo = t*ln2_lo; 00092 } 00093 x = hi - lo; 00094 c = (hi-x)-lo; 00095 } 00096 else if(hx < 0x33000000) { /* when |x|<2**-25, return x */ 00097 t = huge+x; /* return x with inexact flags when x!=0 */ 00098 return x - (t-(huge+x)); 00099 } 00100 else k = 0; 00101 00102 /* x is now in primary range */ 00103 hfx = (float)0.5*x; 00104 hxs = x*hfx; 00105 r1 = one+hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5)))); 00106 t = (float)3.0-r1*hfx; 00107 e = hxs*((r1-t)/((float)6.0 - x*t)); 00108 if(k==0) return x - (x*e-hxs); /* c is 0 */ 00109 else { 00110 e = (x*(e-c)-c); 00111 e -= hxs; 00112 if(k== -1) return (float)0.5*(x-e)-(float)0.5; 00113 if(k==1) { 00114 if(x < (float)-0.25) return -(float)2.0*(e-(x+(float)0.5)); 00115 else return one+(float)2.0*(x-e); 00116 } 00117 if (k <= -2 || k>56) { /* suffice to return exp(x)-1 */ 00118 int32_t i; 00119 y = one-(e-x); 00120 GET_FLOAT_WORD(i,y); 00121 SET_FLOAT_WORD(y,i+(k<<23)); /* add k to y's exponent */ 00122 return y-one; 00123 } 00124 t = one; 00125 if(k<23) { 00126 int32_t i; 00127 SET_FLOAT_WORD(t,0x3f800000 - (0x1000000>>k)); /* t=1-2^-k */ 00128 y = t-(e-x); 00129 GET_FLOAT_WORD(i,y); 00130 SET_FLOAT_WORD(y,i+(k<<23)); /* add k to y's exponent */ 00131 } else { 00132 int32_t i; 00133 SET_FLOAT_WORD(t,((0x7f-k)<<23)); /* 2^-k */ 00134 y = x-(e+t); 00135 y += one; 00136 GET_FLOAT_WORD(i,y); 00137 SET_FLOAT_WORD(y,i+(k<<23)); /* add k to y's exponent */ 00138 } 00139 } 00140 return y; 00141 } 00142 00143 #endif 00144