1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-07-29 08:21:15 +03:00

MCOL-4479 Imported couple functions from boost::math to remove libquadmath dependency

This commit is contained in:
Roman Nozdrin
2020-12-30 10:34:50 +00:00
parent cf11e03d4b
commit aa5211f192
6 changed files with 482 additions and 30 deletions

View File

@ -855,8 +855,8 @@ TypeHandlerStr::formatPartitionInfoSmallCharVarchar(
const MinMaxInfo &pi) const
{
ostringstreamL output;
int64_t maxLimit = numeric_limits<int64_t>::max();
int64_t minLimit = numeric_limits<int64_t>::min();
int64_t maxLimit = std::numeric_limits<int64_t>::max();
int64_t minLimit = std::numeric_limits<int64_t>::min();
maxLimit = uint64ToStr(maxLimit);
minLimit = uint64ToStr(minLimit);
if (pi.min == maxLimit && pi.max == minLimit)

View File

@ -22,24 +22,6 @@
namespace datatypes
{
struct lldiv_t_128
{
int128_t quot;
int128_t rem;
lldiv_t_128() : quot(0), rem(0) {}
lldiv_t_128(const int128_t& a_quot, const int128_t& a_rem)
: quot(a_quot), rem(a_rem) {}
};
inline lldiv_t_128 lldiv128(const int128_t& dividend, const int128_t& divisor)
{
if (UNLIKELY(divisor == 0) || UNLIKELY(dividend == 0))
return lldiv_t_128();
return lldiv_t_128(dividend / divisor, dividend % divisor);
}
template<typename BinaryOperation,
typename OpOverflowCheck,
typename MultiplicationOverflowCheck>
@ -115,7 +97,6 @@ namespace datatypes
? r.s128Value : r.value;
opOverflowCheck(lValue, rValue);
if (result.scale >= l.scale - r.scale)
{
int128_t scaleMultiplier;

View File

@ -161,6 +161,23 @@ inline void getScaleDivisor(T& divisor, const int8_t scale)
}
}
struct lldiv_t_128
{
int128_t quot;
int128_t rem;
lldiv_t_128() : quot(0), rem(0) {}
lldiv_t_128(const int128_t& a_quot, const int128_t& a_rem)
: quot(a_quot), rem(a_rem) {}
};
inline lldiv_t_128 lldiv128(const int128_t& dividend, const int128_t& divisor)
{
if (UNLIKELY(divisor == 0) || UNLIKELY(dividend == 0))
return lldiv_t_128();
return lldiv_t_128(dividend / divisor, dividend % divisor);
}
// @brief The class for Decimal related operations
// The class contains Decimal related operations are scale and
// precision aware.

View File

@ -21,14 +21,138 @@
#include <cfloat>
#include <cstdint>
#include <cstring>
namespace datatypes
{
/* Main union type we use to manipulate the floating-point type. */
typedef union
{
__float128 value;
struct
{
unsigned mantissa3:32;
unsigned mantissa2:32;
unsigned mantissa1:32;
unsigned mantissa0:16;
unsigned exponent:15;
unsigned negative:1;
} ieee;
struct
{
uint64_t low;
uint64_t high;
} words64;
struct
{
uint32_t w3;
uint32_t w2;
uint32_t w1;
uint32_t w0;
} words32;
struct
{
unsigned mantissa3:32;
unsigned mantissa2:32;
unsigned mantissa1:32;
unsigned mantissa0:15;
unsigned quiet_nan:1;
unsigned exponent:15;
unsigned negative:1;
} ieee_nan;
} mcs_ieee854_float128;
/* Get two 64 bit ints from a long double. */
#define MCS_GET_FLT128_WORDS64(ix0,ix1,d) \
do { \
mcs_ieee854_float128 u; \
u.value = (d); \
(ix0) = u.words64.high; \
(ix1) = u.words64.low; \
} while (0)
/* Set a long double from two 64 bit ints. */
#define MCS_SET_FLT128_WORDS64(d,ix0,ix1) \
do { \
mcs_ieee854_float128 u; \
u.words64.high = (ix0); \
u.words64.low = (ix1); \
(d) = u.value; \
} while (0)
class TSInt128;
class TFloat128;
using int128_t = __int128;
static const __float128 mcs_fl_one = 1.0, mcs_fl_Zero[] = {0.0, -0.0,};
template<typename T>
class numeric_limits { };
// Copy from boost::multiprecision::float128
template<> class numeric_limits<__float128> {
public:
static constexpr bool is_specialized = true;
static constexpr __float128 max()
{
return mcs_ieee854_float128{ .ieee = {0xffffffff,
0xffffffff,
0xffffffff,
0xffff,
0x7ffe,
0x0}}.value;
}
static constexpr __float128 min()
{
return mcs_ieee854_float128{ .ieee = {0x0,
0x0,
0x0,
0x0,
0x1,
0x0}}.value;
}
static __float128 denorm_min()
{
return mcs_ieee854_float128{ .ieee = {0x1,
0x0,
0x0,
0x0,
0x0,
0x0}}.value;
}
static __float128 lowest() { return -max(); }
static constexpr int digits = 113;
static constexpr int digits10 = 33;
static constexpr int max_digits10 = 36;
static constexpr bool is_signed = true;
static constexpr bool is_integer = false;
static constexpr bool is_exact = false;
static constexpr int radix = 2;
static __float128 round_error() { return 0.5; }
static constexpr int min_exponent = -16381;
static constexpr int min_exponent10 = min_exponent * 301L / 1000L;
static constexpr int max_exponent = 16384;
static constexpr int max_exponent10 = max_exponent * 301L / 1000L;
static constexpr bool has_infinity = true;
static constexpr bool has_quiet_NaN = true;
static __float128 quiet_NaN() { return 1.0 / 0.0; }
static constexpr bool has_signaling_NaN = false;
static constexpr bool has_denorm_loss = true;
static __float128 infinity() { return 1.0 / 0.0; }
static __float128 signaling_NaN() { return 0; }
static constexpr bool is_iec559 = true;
static constexpr bool is_bounded = false;
static constexpr bool is_modulo = false;
static constexpr bool traps = false;
static constexpr bool tinyness_before = false;
};
// Type defined integral types
// for templates
template <typename T>
@ -46,7 +170,6 @@ struct get_integral_type<TSInt128>{
typedef int128_t type;
};
class TFloat128
{
public:
@ -61,6 +184,341 @@ class TFloat128
TFloat128(const __float128& x) { value = x; }
TFloat128(const int128_t& x) { value = static_cast<__float128>(x); }
// fmodq(x,y) taken from libquadmath
// Return x mod y in exact arithmetic
// Method: shift and subtract
static __float128 fmodq (__float128& x, __float128& y)
{
int64_t n,hx,hy,hz,ix,iy,sx,i;
uint64_t lx,ly,lz;
MCS_GET_FLT128_WORDS64(hx,lx,x);
MCS_GET_FLT128_WORDS64(hy,ly,y);
sx = hx&0x8000000000000000ULL; /* sign of x */
hx ^=sx; /* |x| */
hy &= 0x7fffffffffffffffLL; /* |y| */
/* purge off exception values */
if((hy|ly)==0||(hx>=0x7fff000000000000LL)|| /* y=0,or x not finite */
((hy|((ly|-ly)>>63))>0x7fff000000000000LL)) /* or y is NaN */
return (x*y)/(x*y);
if(hx<=hy) {
if((hx<hy)||(lx<ly)) return x; /* |x|<|y| return x */
if(lx==ly)
return mcs_fl_Zero[(uint64_t)sx>>63]; /* |x|=|y| return x*0*/
}
/* determine ix = ilogb(x) */
if(hx<0x0001000000000000LL) { /* subnormal x */
if(hx==0) {
for (ix = -16431, i=lx; i>0; i<<=1) ix -=1;
} else {
for (ix = -16382, i=hx<<15; i>0; i<<=1) ix -=1;
}
} else ix = (hx>>48)-0x3fff;
/* determine iy = ilogb(y) */
if(hy<0x0001000000000000LL) { /* subnormal y */
if(hy==0) {
for (iy = -16431, i=ly; i>0; i<<=1) iy -=1;
} else {
for (iy = -16382, i=hy<<15; i>0; i<<=1) iy -=1;
}
} else iy = (hy>>48)-0x3fff;
/* set up {hx,lx}, {hy,ly} and align y to x */
if(ix >= -16382)
hx = 0x0001000000000000LL|(0x0000ffffffffffffLL&hx);
else { /* subnormal x, shift x to normal */
n = -16382-ix;
if(n<=63) {
hx = (hx<<n)|(lx>>(64-n));
lx <<= n;
} else {
hx = lx<<(n-64);
lx = 0;
}
}
if(iy >= -16382)
hy = 0x0001000000000000LL|(0x0000ffffffffffffLL&hy);
else { /* subnormal y, shift y to normal */
n = -16382-iy;
if(n<=63) {
hy = (hy<<n)|(ly>>(64-n));
ly <<= n;
} else {
hy = ly<<(n-64);
ly = 0;
}
}
/* fix point fmod */
n = ix - iy;
while(n--) {
hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
if(hz<0){hx = hx+hx+(lx>>63); lx = lx+lx;}
else {
if((hz|lz)==0) /* return sign(x)*0 */
return mcs_fl_Zero[(uint64_t)sx>>63];
hx = hz+hz+(lz>>63); lx = lz+lz;
}
}
hz=hx-hy;lz=lx-ly; if(lx<ly) hz -= 1;
if(hz>=0) {hx=hz;lx=lz;}
/* convert back to floating value and restore the sign */
if((hx|lx)==0) /* return sign(x)*0 */
return mcs_fl_Zero[(uint64_t)sx>>63];
while(hx<0x0001000000000000LL) { /* normalize x */
hx = hx+hx+(lx>>63); lx = lx+lx;
iy -= 1;
}
if(iy>= -16382) { /* normalize output */
hx = ((hx-0x0001000000000000LL)|((iy+16383)<<48));
MCS_SET_FLT128_WORDS64(x,hx|sx,lx);
} else { /* subnormal output */
n = -16382 - iy;
if(n<=48) {
lx = (lx>>n)|((uint64_t)hx<<(64-n));
hx >>= n;
} else if (n<=63) {
lx = (hx<<(64-n))|(lx>>n); hx = sx;
} else {
lx = hx>>(n-64); hx = sx;
}
MCS_SET_FLT128_WORDS64(x,hx|sx,lx);
x *= mcs_fl_one; /* create necessary signal */
}
return x; /* exact output */
}
// The f() returns __float128 power p
// taken from boost::multiprecision
static inline __float128 pown(const __float128& x, const int p)
{
const bool isneg = (x < 0);
const bool isnan = (x != x);
const bool isinf = ((!isneg) ? bool(+x > (datatypes::numeric_limits<__float128>::max)())
: bool(-x > (datatypes::numeric_limits<__float128>::max)()));
if(isnan) { return x; }
if(isinf) { return datatypes::numeric_limits<__float128>::quiet_NaN(); }
const bool x_is_neg = (x < 0);
const __float128 abs_x = (x_is_neg ? -x : x);
if(p < static_cast<int>(0))
{
if(abs_x < (datatypes::numeric_limits<__float128>::min)())
{
return (x_is_neg ? -datatypes::numeric_limits<__float128>::infinity()
: +datatypes::numeric_limits<__float128>::infinity());
}
else
{
return __float128(1) / pown(x, static_cast<int>(-p));
}
}
if(p == static_cast<int>(0))
{
return __float128(1);
}
else
{
if(p == static_cast<int>(1)) { return x; }
if(abs_x > (datatypes::numeric_limits<__float128>::max)())
{
return (x_is_neg ? -datatypes::numeric_limits<__float128>::infinity()
: +datatypes::numeric_limits<__float128>::infinity());
}
if (p == static_cast<int>(2)) { return (x * x); }
else if(p == static_cast<int>(3)) { return ((x * x) * x); }
else if(p == static_cast<int>(4)) { const __float128 x2 = (x * x); return (x2 * x2); }
else
{
// The variable xn stores the binary powers of x.
__float128 result(((p % int(2)) != int(0)) ? x : __float128(1));
__float128 xn (x);
int p2 = p;
while(int(p2 /= 2) != int(0))
{
// Square xn for each binary power.
xn *= xn;
const bool has_binary_power = (int(p2 % int(2)) != int(0));
if(has_binary_power)
{
// Multiply the result with each binary power contained in the exponent.
result *= xn;
}
}
return result;
}
}
}
// fromString conversion for __float128
// algo is taken from
// boost/math/cstdfloat/cstdfloat_iostream.hpp:convert_from_string()
static __float128 fromString(const std::string& str)
{
__float128 value = 0;
const char* p = str.c_str();
if((p == static_cast<const char*>(0U)) || (*p == static_cast<char>(0)))
{
return value;
}
bool is_neg = false;
bool is_neg_expon = false;
constexpr int ten = 10;
int expon = 0;
int digits_seen = 0;
constexpr int max_digits10 = datatypes::numeric_limits<__float128>::max_digits10 + 1;
if(*p == static_cast<char>('+'))
{
++p;
}
else if(*p == static_cast<char>('-'))
{
is_neg = true;
++p;
}
const bool isnan = ((std::strcmp(p, "nan") == 0) || (std::strcmp(p, "NaN") == 0) || (std::strcmp(p, "NAN") == 0));
if(isnan)
{
value = datatypes::numeric_limits<__float128>::infinity();
if (is_neg)
{
value = -value;
}
return value;
}
const bool isinf = ((std::strcmp(p, "inf") == 0) || (std::strcmp(p, "Inf") == 0) || (std::strcmp(p, "INF") == 0));
if(isinf)
{
value = datatypes::numeric_limits<__float128>::infinity();
if (is_neg)
{
value = -value;
}
return value;
}
// Grab all the leading digits before the decimal point.
while(std::isdigit(*p))
{
value *= ten;
value += static_cast<int>(*p - '0');
++p;
++digits_seen;
}
if(*p == static_cast<char>('.'))
{
// Grab everything after the point, stop when we've seen
// enough digits, even if there are actually more available.
++p;
while(std::isdigit(*p))
{
value *= ten;
value += static_cast<int>(*p - '0');
++p;
--expon;
if(++digits_seen > max_digits10)
{
break;
}
}
while(std::isdigit(*p))
{
++p;
}
}
// Parse the exponent.
if((*p == static_cast<char>('e')) || (*p == static_cast<char>('E')))
{
++p;
if(*p == static_cast<char>('+'))
{
++p;
}
else if(*p == static_cast<char>('-'))
{
is_neg_expon = true;
++p;
}
int e2 = 0;
while(std::isdigit(*p))
{
e2 *= 10;
e2 += (*p - '0');
++p;
}
if(is_neg_expon)
{
e2 = -e2;
}
expon += e2;
}
if(expon)
{
// Scale by 10^expon. Note that 10^expon can be outside the range
// of our number type, even though the result is within range.
// If that looks likely, then split the calculation in two parts.
__float128 t;
t = ten;
if(expon > (datatypes::numeric_limits<__float128>::min_exponent10 + 2))
{
t = TFloat128::pown(t, expon);
value *= t;
}
else
{
t = TFloat128::pown(t, (expon + digits_seen + 1));
value *= t;
t = ten;
t = TFloat128::pown(t, (-digits_seen - 1));
value *= t;
}
}
if(is_neg)
{
value = -value;
}
return value;
}
// Method returns max length of a string representation
static constexpr uint8_t maxLength()
{