decimal conversion and unit tests
This commit is contained in:
parent
c1f49fee95
commit
2481c768b6
|
@ -100,7 +100,8 @@ int32_t decimalGetRetType(const SDataType* pLeftT, const SDataType* pRightT, EOp
|
|||
}
|
||||
pOutType->precision = TMIN(pOutType->precision, TSDB_DECIMAL_MAX_PRECISION);
|
||||
pOutType->scale = TMIN(pOutType->scale, TSDB_DECIMAL_MAX_SCALE);
|
||||
pOutType->type = pOutType->precision > TSDB_DECIMAL64_MAX_PRECISION ? TSDB_DATA_TYPE_DECIMAL : TSDB_DATA_TYPE_DECIMAL64;
|
||||
pOutType->type =
|
||||
pOutType->precision > TSDB_DECIMAL64_MAX_PRECISION ? TSDB_DATA_TYPE_DECIMAL : TSDB_DATA_TYPE_DECIMAL64;
|
||||
pOutType->bytes = tDataTypes[pOutType->type].bytes;
|
||||
return 0;
|
||||
}
|
||||
|
@ -286,6 +287,7 @@ static bool decimal64Eq(const DecimalType* pLeft, const DecimalType* pRight,
|
|||
static int32_t decimal64ToStr(const DecimalType* pInt, uint8_t scale, char* pBuf, int32_t bufLen);
|
||||
static void decimal64ScaleDown(Decimal64* pDec, uint8_t scaleDown);
|
||||
static void decimal64ScaleUp(Decimal64* pDec, uint8_t scaleUp);
|
||||
void decimal64ScaleTo(Decimal64* pDec, uint8_t oldScale, uint8_t newScale);
|
||||
|
||||
static void decimal128Negate(DecimalType* pInt);
|
||||
static void decimal128Abs(DecimalType* pWord);
|
||||
|
@ -752,18 +754,44 @@ static int32_t decimal64FromUint64(DecimalType* pDec, uint8_t prec, uint8_t scal
|
|||
|
||||
static int32_t decimal64FromDouble(DecimalType* pDec, uint8_t prec, uint8_t scale, double val) { return 0; }
|
||||
|
||||
static int32_t decimal64FromDecimal128(DecimalType* pDec, uint8_t pec, uint8_t scale, const DecimalType* pVal,
|
||||
static int32_t decimal64FromDecimal128(DecimalType* pDec, uint8_t prec, uint8_t scale, const DecimalType* pVal,
|
||||
uint8_t valPrec, uint8_t valScale) {
|
||||
Decimal128 dec128 = *(Decimal128*)pVal, tmpDec128 = {0};
|
||||
bool negative = DECIMAL128_SIGN(&dec128) == -1;
|
||||
if (negative) decimal128Negate(&dec128);
|
||||
tmpDec128 = dec128;
|
||||
|
||||
Decimal64 max = {0};
|
||||
DECIMAL64_GET_MAX(prec - scale, &max);
|
||||
decimal128ScaleTo(&dec128, valScale, 0);
|
||||
if (decimal128Gt(&dec128, &max, WORD_NUM(Decimal64))) {
|
||||
return TSDB_CODE_DECIMAL_OVERFLOW;
|
||||
}
|
||||
decimal128ScaleTo(&tmpDec128, valScale, scale);
|
||||
DECIMAL64_SET_VALUE((Decimal64*)pDec, DECIMAL128_LOW_WORD(&tmpDec128));
|
||||
if (negative) decimal64Negate(pDec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t decimal64FromDecimal64(DecimalType* pDec, uint8_t pec, uint8_t scale, const DecimalType* pVal,
|
||||
static int32_t decimal64FromDecimal64(DecimalType* pDec, uint8_t prec, uint8_t scale, const DecimalType* pVal,
|
||||
uint8_t valPrec, uint8_t valScale) {
|
||||
Decimal64 dec64 = *(Decimal64*)pVal, max = {0};
|
||||
bool negative = DECIMAL64_SIGN(&dec64) == -1;
|
||||
if (negative) decimal64Negate(&dec64);
|
||||
*(Decimal64*)pDec = dec64;
|
||||
|
||||
DECIMAL64_GET_MAX(prec - scale, &max);
|
||||
decimal64ScaleTo(&dec64, valScale, 0);
|
||||
if (decimal64Lt(&max, &dec64, WORD_NUM(Decimal64))) {
|
||||
return TSDB_CODE_DECIMAL_OVERFLOW;
|
||||
}
|
||||
decimal64ScaleTo(pDec, valScale, scale);
|
||||
if (negative) decimal64Negate(pDec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t decimal128FromInt64(DecimalType* pDec, uint8_t prec, uint8_t scale, int64_t val) {
|
||||
if (prec - scale <= 18) {
|
||||
if (prec - scale <= 18) {// TODO wjm test int64 with 19 digits.
|
||||
Decimal64 max = {0};
|
||||
DECIMAL64_GET_MAX(prec - scale, &max);
|
||||
if (DECIMAL64_GET_VALUE(&max) < val || -DECIMAL64_GET_VALUE(&max) > val) return TSDB_CODE_DECIMAL_OVERFLOW;
|
||||
|
@ -794,27 +822,36 @@ static int32_t decimal128FromDouble(DecimalType* pDec, uint8_t prec, uint8_t sca
|
|||
static int32_t decimal128FromDecimal64(DecimalType* pDec, uint8_t prec, uint8_t scale, const DecimalType* pVal,
|
||||
uint8_t valPrec, uint8_t valScale) {
|
||||
Decimal64 dec64 = *(Decimal64*)pVal;
|
||||
bool negative = false;
|
||||
if (DECIMAL64_SIGN(&dec64) == -1) {
|
||||
decimal64Abs(&dec64);
|
||||
negative = true;
|
||||
}
|
||||
bool negative = DECIMAL64_SIGN(&dec64) == -1;
|
||||
if (negative) decimal64Negate(&dec64);
|
||||
|
||||
makeDecimal128(pDec, 0, DECIMAL64_GET_VALUE(&dec64));
|
||||
Decimal128 max = {0};
|
||||
DECIMAL128_GET_MAX(prec - scale, &max);
|
||||
decimal64ScaleTo(&dec64, valScale, 0);
|
||||
if (decimal128Lt(&max, &dec64, WORD_NUM(Decimal64))) {
|
||||
return TSDB_CODE_DECIMAL_OVERFLOW;
|
||||
}
|
||||
makeDecimal128(pDec, 0, DECIMAL64_GET_VALUE(&dec64));
|
||||
if (negative) decimal128Negate(pDec);
|
||||
decimal128ScaleTo(pDec, valScale, scale);
|
||||
if (negative) decimal128Negate(pDec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t decimal128FromDecimal128(DecimalType* pDec, uint8_t prec, uint8_t scale, const DecimalType* pVal,
|
||||
uint8_t valPrec, uint8_t valScale) {
|
||||
bool negative = DECIMAL128_SIGN((Decimal128*)pVal) == -1;
|
||||
Decimal128 tmpDec = *(Decimal128*)pVal;
|
||||
if (negative) decimal128Negate(&tmpDec);
|
||||
*(Decimal128*)pDec = tmpDec;
|
||||
|
||||
Decimal128 max = {0};
|
||||
DECIMAL128_GET_MAX(prec - scale, &max);
|
||||
|
||||
decimal128ScaleTo(&tmpDec, valScale, 0);
|
||||
if (decimal128Lt(&max, &tmpDec, WORD_NUM(Decimal128))) {
|
||||
return TSDB_CODE_DECIMAL_OVERFLOW;
|
||||
}
|
||||
decimal128ScaleTo(pDec, valScale, scale);
|
||||
if (negative) decimal128Negate(pDec);
|
||||
return 0;
|
||||
}
|
||||
#define CHECK_OVERFLOW_AND_MAKE_DECIMAL128(pDec, v, max, ABS) \
|
||||
|
@ -972,7 +1009,7 @@ static int32_t decimal128FromDecimal128(DecimalType* pDec, uint8_t prec, uint8_t
|
|||
})
|
||||
|
||||
int32_t convertToDecimal(const void* pData, const SDataType* pInputType, void* pOut, const SDataType* pOutType) {
|
||||
if (pInputType->type == pOutType->type) return 0;
|
||||
//if (pInputType->type == pOutType->type) return 0;
|
||||
int32_t code = 0;
|
||||
|
||||
switch (pOutType->type) {
|
||||
|
|
|
@ -41,9 +41,10 @@ void extractWideInteger(__int128 a) {
|
|||
printArray<38 / DIGIT_NUM>(segments);
|
||||
}
|
||||
|
||||
void printDecimal128(const Decimal128* pDec, int8_t precision, int8_t scale) {
|
||||
void printDecimal(const DecimalType* pDec, uint8_t type, uint8_t prec, uint8_t scale) {
|
||||
char buf[64] = {0};
|
||||
decimalToStr(pDec->words, TSDB_DATA_TYPE_DECIMAL, precision, scale, buf, 64);
|
||||
int32_t code = decimalToStr(pDec, type, prec, scale, buf, 64);
|
||||
ASSERT_EQ(code, 0);
|
||||
cout << buf;
|
||||
}
|
||||
|
||||
|
@ -56,6 +57,16 @@ __int128 generate_big_int128(uint32_t digitNum) {
|
|||
return a;
|
||||
}
|
||||
|
||||
void checkDecimal(const DecimalType* pDec, uint8_t t, uint8_t prec, uint8_t scale, const char* valExpect) {
|
||||
ASSERT_TRUE(t == prec > 18 ? TSDB_DATA_TYPE_DECIMAL : TSDB_DATA_TYPE_DECIMAL64);
|
||||
ASSERT_TRUE(scale <= prec);
|
||||
char buf[64] = {0};
|
||||
int32_t code = decimalToStr(pDec, t, prec, scale, buf, 64);
|
||||
ASSERT_EQ(code, 0);
|
||||
ASSERT_STREQ(buf, valExpect);
|
||||
cout << "decimal" << (prec > 18 ? 128 : 64) << " " << (int32_t)prec << ":" << (int32_t)scale << " -> " << buf << endl;
|
||||
}
|
||||
|
||||
TEST(decimal, a) {
|
||||
__int128 a = generate_big_int128(37);
|
||||
extractWideInteger<9>(a);
|
||||
|
@ -93,17 +104,17 @@ TEST(decimal128, divide) {
|
|||
int8_t out_scale = 25;
|
||||
int8_t out_precision = std::min(precision1 - scale1 + scale2 + out_scale, 38);
|
||||
int8_t delta_scale = out_scale + scale2 - scale1;
|
||||
printDecimal128(&d, precision1, scale1);
|
||||
printDecimal(&d, TSDB_DATA_TYPE_DECIMAL, precision1, scale1);
|
||||
__int128 a = 1;
|
||||
while (delta_scale-- > 0) a *= 10;
|
||||
Decimal128 multiplier = {0};
|
||||
makeDecimal128(&multiplier, a >> 64, a);
|
||||
ops->multiply(d.words, multiplier.words, 2);
|
||||
cout << " / ";
|
||||
printDecimal128(&d2, precision2, scale2);
|
||||
printDecimal(&d2, TSDB_DATA_TYPE_DECIMAL, precision2, scale2);
|
||||
cout << " = ";
|
||||
ops->divide(d.words, d2.words, 2, remainder.words);
|
||||
printDecimal128(&d, out_precision, out_scale);
|
||||
printDecimal(&d, TSDB_DATA_TYPE_DECIMAL, out_precision, out_scale);
|
||||
}
|
||||
|
||||
TEST(decimal, cpi_taos_fetch_rows) {
|
||||
|
@ -158,12 +169,6 @@ TEST(decimal, cpi_taos_fetch_rows) {
|
|||
taos_cleanup();
|
||||
}
|
||||
|
||||
void printDecimal(const char* pDecStr, uint8_t type, uint8_t prec, uint8_t scale) {
|
||||
ASSERT_TRUE(type == prec > 18 ? TSDB_DATA_TYPE_DECIMAL : TSDB_DATA_TYPE_DECIMAL64);
|
||||
ASSERT_TRUE(scale <= prec);
|
||||
|
||||
cout << "decimal" << (prec > 18 ? 128 : 64) << " " << (int32_t)prec << ":" << (int32_t)scale << " -> " << pDecStr << endl;
|
||||
}
|
||||
|
||||
TEST(decimal, conversion) {
|
||||
// convert uint8 to decimal
|
||||
|
@ -175,11 +180,8 @@ TEST(decimal, conversion) {
|
|||
Decimal64 dec64 = {0};
|
||||
int32_t code = convertToDecimal(&i8, &inputType, &dec64, &decType);
|
||||
ASSERT_TRUE(code == 0);
|
||||
code = decimalToStr(&dec64, TSDB_DATA_TYPE_DECIMAL64, prec, scale, buf, 64);
|
||||
ASSERT_EQ(code, 0);
|
||||
cout << "convert uint8: " << (int32_t)i8 << " to decimal64 " << (uint32_t)prec << ":" << (uint32_t)scale << "-> "
|
||||
<< buf << endl;
|
||||
ASSERT_STREQ(buf, "22.00");
|
||||
cout << "convert uint8: " << (int32_t)i8 << " to ";
|
||||
checkDecimal(&dec64, TSDB_DATA_TYPE_DECIMAL64, prec, scale, "22.00");
|
||||
|
||||
Decimal128 dec128 = {0};
|
||||
decType.type = TSDB_DATA_TYPE_DECIMAL;
|
||||
|
@ -188,31 +190,20 @@ TEST(decimal, conversion) {
|
|||
decType.bytes = 16;
|
||||
code = convertToDecimal(&i8, &inputType, &dec128, &decType);
|
||||
ASSERT_TRUE(code == 0);
|
||||
code = decimalToStr(&dec128, TSDB_DATA_TYPE_DECIMAL, decType.precision, decType.scale, buf, 64);
|
||||
ASSERT_EQ(code, 0);
|
||||
cout << "convert uint8: " << (int32_t)i8 << " to ";
|
||||
printDecimal(buf, TSDB_DATA_TYPE_DECIMAL, decType.precision, decType.scale);
|
||||
const char* expect = "22.0000000000";
|
||||
ASSERT_STREQ(buf, expect);
|
||||
checkDecimal(&dec128, TSDB_DATA_TYPE_DECIMAL, decType.precision, decType.scale, "22.0000000000");
|
||||
|
||||
char inputBuf[64] = "123.000000000000000000000000000000001";
|
||||
code = decimal128FromStr(inputBuf, strlen(inputBuf), 38, 35, &dec128);
|
||||
ASSERT_EQ(code, 0);
|
||||
code = decimalToStr(&dec128, TSDB_DATA_TYPE_DECIMAL, 38, 35, buf, 64);
|
||||
ASSERT_EQ(code, 0);
|
||||
printDecimal(buf, TSDB_DATA_TYPE_DECIMAL, 38, 35);
|
||||
expect = "123.00000000000000000000000000000000100";
|
||||
ASSERT_STREQ(expect, buf);
|
||||
checkDecimal(&dec128, TSDB_DATA_TYPE_DECIMAL, 38, 35, "123.00000000000000000000000000000000100");
|
||||
|
||||
inputType.type = TSDB_DATA_TYPE_DECIMAL64;
|
||||
inputType.precision = prec;
|
||||
inputType.scale = scale;
|
||||
code = convertToDecimal(&dec64, &inputType, &dec128, &decType);
|
||||
ASSERT_EQ(code, 0);
|
||||
decimalToStr(&dec128, TSDB_DATA_TYPE_DECIMAL, 38, 10, buf, 64);
|
||||
expect = "22.0000000000";
|
||||
ASSERT_STREQ(expect, buf);
|
||||
printDecimal(buf, TSDB_DATA_TYPE_DECIMAL, 38, 10);
|
||||
checkDecimal(&dec128, TSDB_DATA_TYPE_DECIMAL, 38, 10, "22.0000000000");
|
||||
}
|
||||
|
||||
static constexpr uint64_t k1E16 = 10000000000000000LL;
|
||||
|
@ -317,10 +308,23 @@ TEST(decimal, op) {
|
|||
code = decimalOp(op, &ta, &tb, &tc, &a, &b, &res);
|
||||
ASSERT_EQ(code, 0);
|
||||
|
||||
char buf[64] = {0};
|
||||
code = decimalToStr(&res, TSDB_DATA_TYPE_DECIMAL64, tc.precision, tc.scale, buf, 64);
|
||||
checkDecimal(&res, TSDB_DATA_TYPE_DECIMAL64, tc.precision, tc.scale, "580.11");
|
||||
|
||||
a = {1234567890};
|
||||
b = {9876543210};
|
||||
ta = getDecimalType(18, 5);
|
||||
tb = getDecimalType(15, 3);
|
||||
code = decimalGetRetType(&ta, &tb, op, &tc);
|
||||
ASSERT_EQ(code, 0);
|
||||
ASSERT_STREQ(buf, "580.11");
|
||||
tExpect.precision = 19;
|
||||
tExpect.scale = 5;
|
||||
tExpect.type = TSDB_DATA_TYPE_DECIMAL;
|
||||
tExpect.bytes = sizeof(Decimal128);
|
||||
ASSERT_EQ(tExpect, tc);
|
||||
Decimal128 res128 = {0};
|
||||
code = decimalOp(op, &ta, &tb, &tc, &a, &b, &res128);
|
||||
ASSERT_EQ(code, 0);
|
||||
checkDecimal(&res128, 0, tExpect.precision, tExpect.scale, "9888888.88890");
|
||||
}
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
|
|
Loading…
Reference in New Issue