Files
vlibc/src/math/scalbn.c
T

122 lines
2.3 KiB
C

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <math.h>
#ifdef HAVE_CONFIG_H
#include <errno.h>
#endif
#include <limits.h>
#include "math_impl.h"
/*
* x * FLT_RADIX^n with FLT_RADIX 2 (C23 7.12.6.6), all three precisions
* and both exponent-argument types. scalbn takes an int n, scalbln a long
* n; otherwise the two families are semantically identical to ldexp (they
* share the exact same scale cores and overflow-to-+-Inf-with-ERANGE
* behavior, and subnormal inputs are handled exactly like subnormal
* outputs). The scalbln functions clamp the long exponent to +-20000
* first: any magnitude beyond that saturates every result to +-Inf or +-0
* in all three formats, and clamping keeps the arithmetic inside int range
* with no shift by a huge count.
*/
/*
* As ldexp (see ldexp.c) for a double x and an int n.
*/
double
scalbn(double x, int n)
{
int overflowed = 0;
double r = vl_scale2_d(x, n, &overflowed);
#ifdef HAVE_CONFIG_H
if (overflowed)
{
errno = ERANGE;
}
#endif
return r;
}
float
scalbnf(float x, int n)
{
int overflowed = 0;
float r = vl_scale2_f(x, n, &overflowed);
#ifdef HAVE_CONFIG_H
if (overflowed)
{
errno = ERANGE;
}
#endif
return r;
}
long double
scalbnl(long double x, int n)
{
int overflowed = 0;
long double r = vl_scale2_ld(x, n, &overflowed);
#ifdef HAVE_CONFIG_H
if (overflowed)
{
errno = ERANGE;
}
#endif
return r;
}
/*
* The scalbln family: as scalbn with the exponent given as a long.
* n is first clamped into [-20000, 20000]; anything beyond saturates every
* precision's range (the largest meaningful long-double exponent is below
* 16446 in magnitude), so no precision is lost by the clamp.
*/
double
scalbln(double x, long n)
{
if (n > 20000)
{
n = 20000;
}
else if (n < -20000)
{
n = -20000;
}
return scalbn(x, (int)n);
}
float
scalblnf(float x, long n)
{
if (n > 20000)
{
n = 20000;
}
else if (n < -20000)
{
n = -20000;
}
return scalbnf(x, (int)n);
}
long double
scalblnl(long double x, long n)
{
if (n > 20000)
{
n = 20000;
}
else if (n < -20000)
{
n = -20000;
}
return scalbnl(x, (int)n);
}