decimal add test cases
This commit is contained in:
parent
76e849b5cf
commit
fe9d297cba
|
@ -177,7 +177,7 @@ typedef struct SColumnDataAgg {
|
|||
struct {
|
||||
uint64_t decimal128Sum[2];
|
||||
uint64_t decimal128Max[2];
|
||||
uint64_t decimal128Min[2];
|
||||
uint64_t decimal128Min[2]; // TODO wjm 1. use deicmal128Sum for decimal64, 2. add overflow flag
|
||||
};
|
||||
};
|
||||
} SColumnDataAgg;
|
||||
|
|
|
@ -4253,7 +4253,7 @@ static FORCE_INLINE void tColDataCalcSMADecimal64Type(SColData* pColData, SColum
|
|||
pAggs->numOfNull++;
|
||||
break;
|
||||
case 2:
|
||||
CALC_DECIMAL_SUM_MAX_MIN(Decimal64, pOps, pColData, pSum, pMax, pMin);
|
||||
CALC_DECIMAL_SUM_MAX_MIN(Decimal64, pOps, pColData, pSum, pMax, pMin);// TODO wjm what if overflow
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -27,6 +27,10 @@ typedef struct _UInt128 {
|
|||
uint64_t high;
|
||||
} _UInt128;
|
||||
|
||||
typedef struct Int256 {
|
||||
char data[32];
|
||||
} Int256;
|
||||
|
||||
// TODO wjm use cmake to check if the compiler supports __int128_t
|
||||
#if defined(__GNUC__) || defined(__clang__)
|
||||
// #if 0
|
||||
|
|
|
@ -170,8 +170,7 @@ static int32_t decimalVarFromStr(const char* str, int32_t len, DecimalVar* resul
|
|||
if (afterPoint) {
|
||||
break;
|
||||
} else {
|
||||
// TODO wjm value too large
|
||||
return TSDB_CODE_INVALID_DATA_FMT;
|
||||
return TSDB_CODE_DECIMAL_OVERFLOW;
|
||||
}
|
||||
} else {
|
||||
result->precision += places;
|
||||
|
@ -250,9 +249,6 @@ static int32_t decimalGetWhole(const DecimalType* pDec, DecimalInternalType type
|
|||
DECIMAL64_CLONE(pWhole, pDec);
|
||||
Decimal64 scaleMul = SCALE_MULTIPLIER_64[scale];
|
||||
pOps->divide(pWhole, &scaleMul, 1, NULL);
|
||||
if (TSDB_CODE_SUCCESS != 0) {
|
||||
// TODO wjm
|
||||
}
|
||||
pOps->abs(pWhole);
|
||||
} else {
|
||||
memcpy(pWhole, pDec, DECIMAL_GET_WORD_NUM(type) * sizeof(DecimalWord));
|
||||
|
@ -646,7 +642,7 @@ static void extractDecimal128Digits(const Decimal128* pDec, uint64_t* digits, in
|
|||
*digitNum = 0;
|
||||
makeUInt128(&a, DECIMAL128_HIGH_WORD(pDec), DECIMAL128_LOW_WORD(pDec));
|
||||
while (!uInt128Eq(&a, &uInt128Zero)) {
|
||||
uint64_t hi = a >> 64; // TODO wjm ???
|
||||
uint64_t hi = a >> 64; // TODO wjm use function, UInt128 may be a struct.
|
||||
uint64_t lo = a;
|
||||
|
||||
uint64_t hiQuotient = hi / k1e18;
|
||||
|
@ -901,6 +897,7 @@ int32_t decimalOp(EOperatorType op, const SDataType* pLeftT, const SDataType* pR
|
|||
|
||||
switch (op) {
|
||||
case OP_TYPE_ADD:
|
||||
// TODO wjm check overflow
|
||||
decimalAdd(&left, <, &right, &rt, pOutT);
|
||||
break;
|
||||
case OP_TYPE_SUB:
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#include <iostream>
|
||||
#include <array>
|
||||
#include <random>
|
||||
#include <memory>
|
||||
|
||||
#include "decimal.h"
|
||||
#include "tdatablock.h"
|
||||
|
@ -124,6 +125,7 @@ struct NumericType<64> {
|
|||
using Type = Numeric64;
|
||||
static constexpr int8_t dataType = TSDB_DATA_TYPE_DECIMAL64;
|
||||
static constexpr int8_t maxPrec = TSDB_DECIMAL64_MAX_PRECISION;
|
||||
static constexpr int8_t bytes = DECIMAL64_BYTES;
|
||||
};
|
||||
|
||||
template <>
|
||||
|
@ -131,6 +133,7 @@ struct NumericType<128> {
|
|||
using Type = Numeric128;
|
||||
static constexpr int8_t dataType = TSDB_DATA_TYPE_DECIMAL;
|
||||
static constexpr int8_t maxPrec = TSDB_DECIMAL_MAX_PRECISION;
|
||||
static constexpr int8_t bytes = DECIMAL128_BYTES;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
@ -174,15 +177,19 @@ class Numeric {
|
|||
throw std::string(tstrerror(code));
|
||||
}
|
||||
}
|
||||
Numeric() = default;
|
||||
Numeric(const Numeric& o) = default;
|
||||
~Numeric() = default;
|
||||
Numeric& operator=(const Numeric& o) = default;
|
||||
|
||||
SDataType getRetType(EOperatorType op, const SDataType& lt, const SDataType& rt) const {
|
||||
static SDataType getRetType(EOperatorType op, const SDataType& lt, const SDataType& rt) {
|
||||
SDataType ot = {0};
|
||||
decimalGetRetType(<, &rt, op, &ot);
|
||||
return ot;
|
||||
}
|
||||
SDataType type() const {
|
||||
return {.type = NumericType<BitNum>::dataType, .precision = prec(), .scale = scale(), .bytes = NumericType<BitNum>::bytes};
|
||||
}
|
||||
uint8_t prec() const { return prec_; }
|
||||
uint8_t scale() const { return scale_; }
|
||||
const Type& dec() const { return dec_; }
|
||||
|
@ -195,8 +202,8 @@ class Numeric {
|
|||
|
||||
template <int BitNum2, int BitNumO>
|
||||
Numeric<BitNumO> binaryOp(const Numeric<BitNum2>& r, EOperatorType op) {
|
||||
SDataType lt{.type = NumericType<BitNum>::dataType, .precision = prec_, .scale = scale_, .bytes = BitNum};
|
||||
SDataType rt{.type = NumericType<BitNum2>::dataType, .precision = r.prec(), .scale = r.scale(), .bytes = BitNum2};
|
||||
SDataType lt{.type = NumericType<BitNum>::dataType, .precision = prec_, .scale = scale_, .bytes = NumericType<BitNum>::bytes};
|
||||
SDataType rt{.type = NumericType<BitNum2>::dataType, .precision = r.prec(), .scale = r.scale(), .bytes = NumericType<BitNum2>::bytes};
|
||||
SDataType ot = getRetType(op, lt, rt);
|
||||
Numeric<BitNumO> out{ot.precision, ot.scale, "0"};
|
||||
int32_t code = decimalOp(op, <, &rt, &ot, &dec_, &r.dec(), &out);
|
||||
|
@ -207,12 +214,13 @@ class Numeric {
|
|||
template <int BitNumO, typename T>
|
||||
Numeric<BitNumO> binaryOp(const T& r, EOperatorType op) {
|
||||
using TypeInfo = TrivialTypeInfo<T>;
|
||||
SDataType lt{.type = NumericType<BitNum>::dataType, .precision = prec_, .scale = scale_, .bytes = BitNum};
|
||||
SDataType lt{.type = NumericType<BitNum>::dataType, .precision = prec_, .scale = scale_, .bytes = NumericType<BitNum>::bytes};
|
||||
SDataType rt{.type = TypeInfo::dataType, .precision = 0, .scale = 0, .bytes = TypeInfo::bytes};
|
||||
SDataType ot = getRetType(op, lt, rt);
|
||||
Numeric<BitNumO> out{ot.precision, ot.scale, "0"};
|
||||
int32_t code = decimalOp(op, <, &rt, &ot, &dec_, &r, &out);
|
||||
if (code != 0) throw std::overflow_error(tstrerror(code));
|
||||
if (code == TSDB_CODE_DECIMAL_OVERFLOW) throw std::overflow_error(tstrerror(code));
|
||||
if (code != 0) throw std::runtime_error(tstrerror(code));
|
||||
return out;
|
||||
}
|
||||
#define DEFINE_OPERATOR(op, op_type) \
|
||||
|
@ -233,7 +241,13 @@ class Numeric {
|
|||
template <typename T, int BitNumO = 128> \
|
||||
Numeric<BitNumO> operator op(const T & r) { \
|
||||
cout << *this << " " #op " " << r << "(" << typeid(T).name() << ")" << " = "; \
|
||||
auto res = binaryOp<BitNumO, T>(r, op_type); \
|
||||
Numeric<BitNumO> res = {}; \
|
||||
try { \
|
||||
res = binaryOp<BitNumO, T>(r, op_type); \
|
||||
} catch (...) { \
|
||||
cout << "Exception caught during binaryOp" << endl; \
|
||||
throw; \
|
||||
} \
|
||||
cout << res << endl; \
|
||||
return res; \
|
||||
}
|
||||
|
@ -306,7 +320,7 @@ class Numeric {
|
|||
DEFINE_OPERATOR_T(float);
|
||||
DEFINE_OPERATOR_T(double);
|
||||
|
||||
Numeric operator=(const char* str) {
|
||||
Numeric& operator=(const char* str) {
|
||||
std::string s = str;
|
||||
int32_t code = 0;
|
||||
if (BitNum == 64) {
|
||||
|
@ -330,7 +344,7 @@ class Numeric {
|
|||
}
|
||||
|
||||
#define DEFINE_OPERATOR_EQ_T(type) \
|
||||
Numeric operator=(type v) { \
|
||||
Numeric& operator=(type v) { \
|
||||
int32_t code = 0; \
|
||||
if (BitNum == 64) { \
|
||||
DEFINE_OPERATOR_FROM_FOR_BITNUM(type, 64); \
|
||||
|
@ -352,6 +366,23 @@ class Numeric {
|
|||
DEFINE_OPERATOR_EQ_T(bool);
|
||||
DEFINE_OPERATOR_EQ_T(double);
|
||||
DEFINE_OPERATOR_EQ_T(float);
|
||||
|
||||
Numeric& operator=(const Decimal128& d) {
|
||||
SDataType inputDt = {.type = TSDB_DATA_TYPE_DECIMAL, .precision = prec(), .scale = scale(), .bytes = DECIMAL128_BYTES};
|
||||
SDataType outputDt = {.type = NumericType<BitNum>::dataType, .precision = prec(), .scale = scale(), .bytes = NumericType<BitNum>::bytes};
|
||||
int32_t code = convertToDecimal(&d, &inputDt, &dec_, &outputDt);
|
||||
if (code == TSDB_CODE_DECIMAL_OVERFLOW) throw std::overflow_error(tstrerror(code));
|
||||
if (code != 0) throw std::runtime_error(tstrerror(code));
|
||||
return *this;
|
||||
}
|
||||
Numeric& operator=(const Decimal64& d) {
|
||||
SDataType inputDt = {.type = TSDB_DATA_TYPE_DECIMAL64, .precision = prec(), .scale = scale(), .bytes = DECIMAL64_BYTES};
|
||||
SDataType outputDt = {.type = NumericType<BitNum>::dataType, .precision = prec_, .scale = scale_, .bytes = NumericType<BitNum>::bytes};
|
||||
int32_t code = convertToDecimal(&d, &inputDt, &dec_, &outputDt);
|
||||
if (code == TSDB_CODE_DECIMAL_OVERFLOW) throw std::overflow_error(tstrerror(code));
|
||||
if (code != 0) throw std::runtime_error(tstrerror(code));
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <int BitNum>
|
||||
|
@ -897,6 +928,69 @@ TEST(decimal, randomGenerator) {
|
|||
}
|
||||
}
|
||||
|
||||
TEST(deicmal, decimalFromStr_all) {
|
||||
// TODO test e/E
|
||||
}
|
||||
|
||||
#define ASSERT_OVERFLOW(op) \
|
||||
try { \
|
||||
auto res = op; \
|
||||
} catch (std::overflow_error & e) { \
|
||||
} catch (std::exception & e) { \
|
||||
FAIL(); \
|
||||
}
|
||||
|
||||
TEST(decimal, op_overflow) {
|
||||
// divide 0 error
|
||||
Numeric<128> dec{38, 2, string(36, '9') + ".99"};
|
||||
ASSERT_OVERFLOW(dec / 0); // TODO wjm add divide by 0 error code
|
||||
|
||||
// test decimal128Max
|
||||
Numeric<128> max{38, 10, "0"};
|
||||
max = decimal128Max;
|
||||
ASSERT_EQ(max.toString(), "9999999999999999999999999999.9999999999");
|
||||
|
||||
{
|
||||
// multiply overflow
|
||||
ASSERT_OVERFLOW(max * 10);
|
||||
}
|
||||
{
|
||||
// multiply not overflow, no trim scale
|
||||
Numeric<64> dec64{18, 10, "99999999.9999999999"};
|
||||
Numeric<128> dec128{19, 10, "999999999.9999999999"};
|
||||
|
||||
auto rett = Numeric<64>::getRetType(OP_TYPE_MULTI, dec64.type(), dec128.type());
|
||||
ASSERT_EQ(rett.precision, 38);
|
||||
ASSERT_EQ(rett.type, TSDB_DATA_TYPE_DECIMAL);
|
||||
ASSERT_EQ(rett.scale, dec64.scale() + dec128.scale());
|
||||
|
||||
auto res = dec64 * dec128;
|
||||
ASSERT_EQ(res.toString(), "99999999999999999.89000000000000000001");
|
||||
|
||||
// multiply not overflow, trim scale from 20 - 19
|
||||
Numeric<128> dec128_2{20, 10, "9999999999.9999999999"};
|
||||
rett = Numeric<128>::getRetType(OP_TYPE_MULTI, dec64.type(), dec128_2.type());
|
||||
ASSERT_EQ(rett.scale, 19);
|
||||
res = dec64 * dec128_2;
|
||||
ASSERT_EQ(res.toString(), "999999999999999998.9900000000000000000");
|
||||
|
||||
// trim scale from 20 - 18
|
||||
dec128_2 = {21, 10, "99999999999.9999999999"};
|
||||
rett = Numeric<128>::getRetType(OP_TYPE_MULTI, dec64.type(), dec128_2.type());
|
||||
ASSERT_EQ(rett.scale, 18);
|
||||
res = dec64 * dec128_2;
|
||||
ASSERT_EQ(res.toString(), "9999999999999999990.000000000000000000");
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
// multiply middle res overflow, but final res not overflow
|
||||
// same scale multiply
|
||||
// different scale multiply
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
return RUN_ALL_TESTS();
|
||||
|
|
Loading…
Reference in New Issue