122 lines
2.3 KiB
C
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);
|
|
}
|