12#define WRAPPER_FUNC(x) __wrap_ ## x
13#define WRAPPER_FUNC_NAME(x) __wrap_##x
19double fix642double(int64_t m,
int e);
22_Pragma(
"GCC diagnostic push")
23_Pragma("GCC diagnostic ignored \"-Wconversion\"")
24_Pragma("GCC diagnostic ignored \"-Wsign-conversion\"")
30#define PINF ( HUGE_VAL)
31#define MINF (-HUGE_VAL)
36#define PI 3.14159265358979323846
37#define LOG2 0.69314718055994530941
39#define LOG10 2.30258509299404568401
40#define LOG2E 1.44269504088896340737
41#define LOG10E 0.43429448190325182765
42#define ONETHIRD 0.33333333333333333333
44#define PIf 3.14159265358979323846f
45#define LOG2f 0.69314718055994530941f
46#define LOG2Ef 1.44269504088896340737f
47#define LOG10Ef 0.43429448190325182765f
48#define ONETHIRDf 0.33333333333333333333f
50#define DUNPACK(x,e,m) e=((x)>>52)&0x7ff,m=((x)&0x000fffffffffffffULL)|0x0010000000000000ULL
51#define DUNPACKS(x,s,e,m) s=((x)>>63),DUNPACK((x),(e),(m))
58static inline double ui642double(ui64 ix) {
64static inline ui64 double2ui64(
double d) {
70static inline bool disnan(
double x) {
71 ui64 ix= double2ui64(x);
73 return ((uint32_t)(ix >> 31)) > 0xffe00000u;
76#if PICO_DOUBLE_PROPAGATE_NANS
77#define check_nan_d1(x) if (disnan((x))) return (x)
78#define check_nan_d2(x,y) if (disnan((x))) return (x); else if (disnan((y))) return (y);
80#define check_nan_d1(x) ((void)0)
81#define check_nan_d2(x,y) ((void)0)
84static inline int dgetsignexp(
double x) {
85 ui64 ix=double2ui64(x);
86 return (ix>>52)&0xfff;
89static inline int dgetexp(
double x) {
90 ui64 ix=double2ui64(x);
91 return (ix>>52)&0x7ff;
94static inline double dldexp(
double x,
int de) {
95 ui64 ix=double2ui64(x),iy;
98 if(e==0||e==0x7ff)
return x;
100 if(e<=0) iy=ix&0x8000000000000000ULL;
101 else if(e>=0x7ff) iy=(ix&0x8000000000000000ULL)|0x7ff0000000000000ULL;
102 else iy=ix+((ui64)de<<52);
103 return ui642double(iy);
106double WRAPPER_FUNC(ldexp)(
double x,
int de) {
108 return dldexp(x, de);
112static inline double dcopysign(
double x,
double y) {
113 ui64 ix=double2ui64(x),iy=double2ui64(y);
114 ix=((ix&0x7fffffffffffffffULL)|(iy&0x8000000000000000ULL));
115 return ui642double(ix);
118double WRAPPER_FUNC(copysign)(
double x,
double y) {
120 return dcopysign(x, y);
122static inline int diszero(
double x) {
return dgetexp (x)==0; }
123static inline int dispzero(
double x) {
return dgetsignexp(x)==0; }
124static inline int dismzero(
double x) {
return dgetsignexp(x)==0x800; }
125static inline int disinf(
double x) {
return dgetexp (x)==0x7ff; }
126static inline int dispinf(
double x) {
return dgetsignexp(x)==0x7ff; }
127static inline int disminf(
double x) {
return dgetsignexp(x)==0xfff; }
129static inline int disint(
double x) {
130 ui64 ix=double2ui64(x),m;
142static inline int disoddint(
double x) {
143 ui64 ix=double2ui64(x),m;
155static inline int disstrictneg(
double x) {
156 ui64 ix=double2ui64(x);
157 if(diszero(x))
return 0;
161static inline int disneg(
double x) {
162 ui64 ix=double2ui64(x);
166static inline double dneg(
double x) {
167 ui64 ix=double2ui64(x);
168 ix^=0x8000000000000000ULL;
169 return ui642double(ix);
172static inline int dispo2(
double x) {
173 ui64 ix=double2ui64(x);
174 if(diszero(x))
return 0;
175 if(disinf(x))
return 0;
176 ix&=0x000fffffffffffffULL;
180static inline double dnan_or(
double x) {
181#if PICO_DOUBLE_PROPAGATE_NANS
188double WRAPPER_FUNC(trunc)(
double x) {
190 ui64 ix=double2ui64(x),m;
194 ix&=0x8000000000000000ULL;
195 return ui642double(ix);
201 return ui642double(ix);
204double WRAPPER_FUNC(round)(
double x) {
206 ui64 ix=double2ui64(x),m;
210 ix&=0x8000000000000000ULL;
211 return ui642double(ix);
214 ix&=0x8000000000000000ULL;
215 ix|=0x3ff0000000000000ULL;
216 return ui642double(ix);
224 return ui642double(ix);
227double WRAPPER_FUNC(floor)(
double x) {
229 ui64 ix=double2ui64(x),m;
232 ix&=0x8000000000000000ULL;
233 return ui642double(ix);
237 if(disneg(x))
return -1;
245 return ui642double(ix);
248double WRAPPER_FUNC(ceil)(
double x) {
250 ui64 ix=double2ui64(x),m;
253 ix&=0x8000000000000000ULL;
254 return ui642double(ix);
258 if(disneg(x))
return MZERO;
264 if(!disneg(x)) ix+=m;
266 return ui642double(ix);
269double WRAPPER_FUNC(asin)(
double x) {
273 if(disstrictneg(u))
return dnan_or(PINF);
274 return atan2(x,sqrt(u));
277double WRAPPER_FUNC(acos)(
double x) {
281 if(disstrictneg(u))
return dnan_or(PINF);
282 return atan2(sqrt(u),x);
285double WRAPPER_FUNC(atan)(
double x) {
287 if(dispinf(x))
return PI/2;
288 if(disminf(x))
return -PI/2;
292double WRAPPER_FUNC(sinh)(
double x) {
294 return dldexp((exp(x)-exp(dneg(x))),-1);
297double WRAPPER_FUNC(cosh)(
double x) {
299 return dldexp((exp(x)+exp(dneg(x))),-1);
302double WRAPPER_FUNC(tanh)(
double x) {
308 if(!disneg(x))
return 1;
315double WRAPPER_FUNC(asinh)(
double x) {
320 if(!disneg(x))
return log( x )+LOG2;
321 else return dneg(log(dneg(x))+LOG2);
323 if(x>0)
return log(sqrt(x*x+1)+x);
324 else return dneg(log(sqrt(x*x+1)-x));
327double WRAPPER_FUNC(acosh)(
double x) {
330 if(disneg(x)) x=dneg(x);
332 if(e>=32+0x3ff)
return log(x)+LOG2;
333 return log(sqrt((x-1)*(x+1))+x);
336double WRAPPER_FUNC(atanh)(
double x) {
338 return dldexp(log((1+x)/(1-x)),-1);
341double WRAPPER_FUNC(exp2)(
double x) {
345 if (disminf(x) || x<=-4096)
return 0;
346 else if (x>=4096)
return PINF;
349 return dldexp(exp(x*LOG2),e);
351double WRAPPER_FUNC(log2)(
double x) { check_nan_d1(x);
return log(x)*LOG2E; }
352double WRAPPER_FUNC(exp10)(
double x) { check_nan_d1(x);
return pow(10,x); }
353double WRAPPER_FUNC(log10)(
double x) { check_nan_d1(x);
return log(x)*LOG10E; }
356double WRAPPER_FUNC(expm1(
double x) { check_nan_d1(x);
return exp)(x)-1; }
357double WRAPPER_FUNC(log1p(
double x) { check_nan_d1(x);
return log)(1+x); }
358double WRAPPER_FUNC(fma)(
double x,
double y,
double z) { check_nan_d1(x);
return x*y+z; }
361static double dpow_1(
double x,
double y) {
363 double t,rt,u,v,v0,v1,w,ry;
365 u=log2(dldexp(x,-a));
367 if(a==0)
return exp2(u*y);
379 v0=dldexp(round(ldexp(v,26)),-26);
395 return dldexp(exp2(w),c);
398static double dpow_int2(
double x,
int y) {
408static inline double dpowint_1(
double x,
int y) {
410 return dpow_int2(x,y);
414static double dpowint_0(
double x,
int y) {
417 if(disoddint(y))
return dneg(dpowint_0(dneg(x),y));
418 else return dpowint_0(dneg(x),y);
428 if(y>=-32&&y<=32)
return dpowint_1(x,y);
432double WRAPPER_FUNC(powint)(
double x,
int y) {
433 _Pragma(
"GCC diagnostic push")
434 _Pragma("GCC diagnostic ignored \"-Wfloat-equal\"")
435 if(x==1.0||y==0) return 1;
436 _Pragma("GCC diagnostic pop")
443 if((y&1))
return dcopysign(PINF,x);
452 if((y&1))
return MINF;
455 if((y&1))
return MZERO;
458 return dpowint_0(x,y);
462static double dpow_0(
double x,
double y) {
465 if(disoddint(y))
return dneg(dpow_0(dneg(x),y));
466 else return dpow_0(dneg(x),y);
477 if(p>=-32&&p<=32)
return dpowint_1(x,p);
481double WRAPPER_FUNC(pow)(
double x,
double y) {
482 _Pragma(
"GCC diagnostic push")
483 _Pragma("GCC diagnostic ignored \"-Wfloat-equal\"")
485 if(x==1.0||diszero(y)) return 1;
487 if(x==-1.0&&disinf(y)) return 1;
488 _Pragma("GCC diagnostic pop")
492 if(disoddint(y))
return x;
495 if(disoddint(y))
return dcopysign(PINF,x);
499 if(disneg(y))
return 0;
504 if(disoddint(y))
return MINF;
507 if(disoddint(y))
return MZERO;
511 if(dgetexp(x)<0x3ff)
return PZERO;
515 if(dgetexp(x)<0x3ff)
return PINF;
518 if(disint(y))
return dpow_0(x,y);
519 if(disneg(x))
return PINF;
523double WRAPPER_FUNC(hypot)(
double x,
double y) {
526 ex=dgetexp(x); ey=dgetexp(y);
527 if(ex>=0x3ff+400||ey>=0x3ff+400) {
528 x=dldexp(x,-600),y=dldexp(y,-600);
529 return dldexp(sqrt(x*x+y*y), 600);
531 else if(ex<=0x3ff-400&&ey<=0x3ff-400) {
532 x=dldexp(x, 600),y=dldexp(y, 600);
533 return dldexp(sqrt(x*x+y*y),-600);
535 return sqrt(x*x+y*y);
538double WRAPPER_FUNC(cbrt)(
double x) {
541 if(disneg(x))
return dneg(cbrt(dneg(x)));
542 if(diszero(x))
return dcopysign(PZERO,x);
544 e=(e*0x5555+0x8000)>>16;
546 x=exp(log(x)*ONETHIRD);
552static i64 drem_0(i64 mx,i64 my,
int e,
int*pquo) {
555 r=0xffffffffU/(ui32)(my>>36);
560 q=((q>>(29-s))+1)>>1;
565 if(mx>=my) mx-=my,quo++;
566 if(mx>=my) mx-=my,quo++;
567 if(mx<0) mx+=my,quo--;
568 if(mx<0) mx+=my,quo--;
573double WRAPPER_FUNC(fmod)(
double x,
double y) {
575 ui64 ix=double2ui64(x),iy=double2ui64(y);
578 DUNPACKS(ix,sx,ex,mx);
580 if(ex==0x7ff)
return dnan_or(PINF);
581 if(ey==0)
return PINF;
583 if(!disneg(x))
return PZERO;
587 mx=drem_0(mx,my,ex-ey,0);
589 return fix642double(mx,0x3ff-ey+52);
592double WRAPPER_FUNC(remquo)(
double x,
double y,
int*quo) {
594 ui64 ix=double2ui64(x),iy=double2ui64(y);
597 DUNPACKS(ix,sx,ex,mx);
598 DUNPACKS(iy,sy,ey,my);
600 if(ex==0x7ff)
return PINF;
601 if(ey==0)
return PINF;
602 if(ex==0)
return PZERO;
603 if(ey==0x7ff)
return x;
604 if(ex<ey-1)
return x;
620 mx=drem_0(mx,my,ex-ey,&q);
621 if(mx+mx>my || (mx+mx==my&&(q&1)) ) {
628 return fix642double(mx,0x3ff-ey+52);
631double WRAPPER_FUNC(drem)(
double x,
double y) { check_nan_d2(x, y);
return remquo(x,y,0); }
633double WRAPPER_FUNC(remainder)(
double x,
double y) { check_nan_d2(x, y);
return remquo(x,y,0); }
635_Pragma(
"GCC diagnostic pop")