diff options
Diffstat (limited to 'libm/s_scalbn.c')
-rw-r--r-- | libm/s_scalbn.c | 72 |
1 files changed, 47 insertions, 25 deletions
diff --git a/libm/s_scalbn.c b/libm/s_scalbn.c index c98ea9d1c..bb14802d8 100644 --- a/libm/s_scalbn.c +++ b/libm/s_scalbn.c @@ -11,7 +11,7 @@ /* * scalbn (double x, int n) - * scalbn(x,n) returns x* 2**n computed by exponent + * scalbn(x,n) returns x* 2**n computed by exponent * manipulation rather than by actually performing an * exponentiation or a multiplication. */ @@ -20,35 +20,57 @@ #include "math_private.h" static const double -two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */ -twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */ +two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */ +twom54 = 5.55111512312578270212e-17, /* 0x3C900000, 0x00000000 */ huge = 1.0e+300, tiny = 1.0e-300; double scalbn(double x, int n) { - int32_t k,hx,lx; - EXTRACT_WORDS(hx,lx,x); - k = (hx&0x7ff00000)>>20; /* extract exponent */ - if (k==0) { /* 0 or subnormal x */ - if ((lx|(hx&0x7fffffff))==0) return x; /* +-0 */ - x *= two54; - GET_HIGH_WORD(hx,x); - k = ((hx&0x7ff00000)>>20) - 54; - if (n< -50000) return tiny*x; /*underflow*/ - } - if (k==0x7ff) return x+x; /* NaN or Inf */ - k = k+n; - if (k > 0x7fe) return huge*copysign(huge,x); /* overflow */ - if (k > 0) /* normal result */ - {SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20)); return x;} - if (k <= -54) { - if (n > 50000) /* in case integer overflow in n+k */ - return huge*copysign(huge,x); /*overflow*/ - else return tiny*copysign(tiny,x); /*underflow*/ + int32_t k, hx, lx; + + EXTRACT_WORDS(hx, lx, x); + k = (hx & 0x7ff00000) >> 20; /* extract exponent */ + if (k == 0) { /* 0 or subnormal x */ + if ((lx | (hx & 0x7fffffff)) == 0) + return x; /* +-0 */ + x *= two54; + GET_HIGH_WORD(hx, x); + k = ((hx & 0x7ff00000) >> 20) - 54; + } + if (k == 0x7ff) + return x + x; /* NaN or Inf */ + k = k + n; + if (k > 0x7fe) + return huge * copysign(huge, x); /* overflow */ + if (n < -50000) + return tiny * copysign(tiny, x); /* underflow */ + if (k > 0) { /* normal result */ + SET_HIGH_WORD(x, (hx & 0x800fffff) | (k << 20)); + return x; } - k += 54; /* subnormal result */ - SET_HIGH_WORD(x,(hx&0x800fffff)|(k<<20)); - return x*twom54; + if (k <= -54) { + if (n > 50000) /* in case integer overflow in n+k */ + return huge * copysign(huge, x); /* overflow */ + return tiny * copysign(tiny, x); /* underflow */ + } + k += 54; /* subnormal result */ + SET_HIGH_WORD(x, (hx & 0x800fffff) | (k << 20)); + return x * twom54; } libm_hidden_def(scalbn) + +#if LONG_MAX == INT_MAX +/* strong_alias(scalbn, scalbln) - "error: conflicting types for 'scalbln'" + * because it tries to declare "typeof(scalbn) scalbln;" + * which tries to give "int" parameter to scalbln. + * Doing it by hand: + */ +__typeof(scalbln) scalbln __attribute__((alias("scalbn"))); +#else +double scalbln(double x, long n) +{ + return scalbn(x, n); +} +#endif +libm_hidden_def(scalbln) |