feat(math): abs/round/trunc/frexp/ldexp/scalbn/copysign/fmin/fmax/fmod
This commit is contained in:
@@ -0,0 +1,121 @@
|
||||
#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);
|
||||
}
|
||||
Reference in New Issue
Block a user