decimal from str

This commit is contained in:
wangjiaming0909 2025-02-19 07:35:09 +08:00
parent 77ed918248
commit dff26dc577
2 changed files with 117 additions and 70 deletions

View File

@ -60,8 +60,8 @@ static Decimal64 SCALE_MULTIPLIER_64[TSDB_DECIMAL64_MAX_PRECISION + 1] = {1LL,
typedef struct DecimalVar { typedef struct DecimalVar {
DecimalInternalType type; DecimalInternalType type;
uint8_t precision; int8_t precision;
uint8_t scale; int8_t scale;
int32_t exponent; int32_t exponent;
int8_t sign; int8_t sign;
DecimalType* pDec; DecimalType* pDec;
@ -167,6 +167,14 @@ static int32_t decimalVarFromStr(const char* str, int32_t len, DecimalVar* resul
default: default:
break; break;
} }
int32_t pos2 = pos;
while(pos2 < len) {
if (isdigit(str[pos2] || str[pos] == '.')) continue;
if (str[pos2] == 'e' || str[pos2] == 'E') {
result->exponent = atoi(str + pos2 + 1);
}
pos2++;
}
for (; pos < len && !stop; ++pos) { for (; pos < len && !stop; ++pos) {
switch (str[pos]) { switch (str[pos]) {
@ -191,10 +199,10 @@ static int32_t decimalVarFromStr(const char* str, int32_t len, DecimalVar* resul
case '9': { case '9': {
leadingZeroes = false; leadingZeroes = false;
++places; ++places;
int32_t curPrec = result->precision + places; int32_t curPrec = result->precision + places - result->exponent;
if (curPrec > maxPrecision(result->type)) { if (curPrec > maxPrecision(result->type)) {
if (afterPoint) { if (afterPoint) {
if (!rounded && curPrec - 1 == maxPrecision(result->type) && str[pos] - '0' >= 5) { if (!rounded && curPrec - 1 == maxPrecision(result->type) && str[pos] >= '5') {
Decimal64 delta = {1}; Decimal64 delta = {1};
if (places > 1) { if (places > 1) {
int32_t scaleUp = places - 1; int32_t scaleUp = places - 1;
@ -214,17 +222,21 @@ static int32_t decimalVarFromStr(const char* str, int32_t len, DecimalVar* resul
return TSDB_CODE_DECIMAL_OVERFLOW; return TSDB_CODE_DECIMAL_OVERFLOW;
} }
} else { } else {
result->precision += places; if (afterPoint && result->precision == 0) {
if (afterPoint) { result->precision = places;
result->scale += places; result->scale = places;
result->exponent -= places; } else {
result->precision += places;
if (afterPoint) {
result->scale += places;
}
while (places != 0) {
int32_t curScale = TMIN(17, places);
pOps->multiply(result->pDec, &SCALE_MULTIPLIER_64[curScale], WORD_NUM(Decimal64));
places -= curScale;
}
} }
Decimal64 digit = {str[pos] - '0'}; Decimal64 digit = {str[pos] - '0'};
while (places != 0) {
int32_t curScale = TMIN(17, places);
pOps->multiply(result->pDec, &SCALE_MULTIPLIER_64[curScale], WORD_NUM(Decimal64));
places -= curScale;
}
pOps->add(result->pDec, &digit, WORD_NUM(Decimal64)); pOps->add(result->pDec, &digit, WORD_NUM(Decimal64));
places = 0; places = 0;
break; break;
@ -232,7 +244,7 @@ static int32_t decimalVarFromStr(const char* str, int32_t len, DecimalVar* resul
} }
case 'e': case 'e':
case 'E': { case 'E': {
result->exponent += strnatoi(str + pos + 1, len - pos - 1); //result->exponent += atoi(str + pos + 1);
stop = true; stop = true;
} break; } break;
default: default:
@ -240,6 +252,8 @@ static int32_t decimalVarFromStr(const char* str, int32_t len, DecimalVar* resul
break; break;
} }
} }
if (rounded) {
}
if (result->sign < 0) { if (result->sign < 0) {
pOps->negate(result->pDec); pOps->negate(result->pDec);
} }
@ -312,7 +326,7 @@ static void decimal64ScaleDown(Decimal64* pDec, uint8_t scaleDown);
static void decimal64ScaleUp(Decimal64* pDec, uint8_t scaleUp); static void decimal64ScaleUp(Decimal64* pDec, uint8_t scaleUp);
static void decimal64ScaleTo(Decimal64* pDec, uint8_t oldScale, uint8_t newScale); static void decimal64ScaleTo(Decimal64* pDec, uint8_t oldScale, uint8_t newScale);
static void decimal64RoundWithPositiveScale(Decimal64* pDec, uint8_t prec, uint8_t scale, uint8_t toPrec, static void decimal64RoundWithPositiveScale(Decimal64* pDec, uint8_t prec, int8_t scale, uint8_t toPrec,
uint8_t toScale, DecimalRoundType roundType, bool* overflow); uint8_t toScale, DecimalRoundType roundType, bool* overflow);
static void decimal128Negate(DecimalType* pInt); static void decimal128Negate(DecimalType* pInt);
@ -1442,8 +1456,15 @@ int32_t convertToDecimal(const void* pData, const SDataType* pInputType, void* p
void decimal64ScaleDown(Decimal64* pDec, uint8_t scaleDown) { void decimal64ScaleDown(Decimal64* pDec, uint8_t scaleDown) {
if (scaleDown > 0) { if (scaleDown > 0) {
Decimal64 divisor = SCALE_MULTIPLIER_64[scaleDown]; Decimal64 divisor = SCALE_MULTIPLIER_64[scaleDown], remainder = {0};
decimal64divide(pDec, &divisor, WORD_NUM(Decimal64), NULL); decimal64divide(pDec, &divisor, WORD_NUM(Decimal64), &remainder);
decimal64Abs(&remainder);
Decimal64 half = SCALE_MULTIPLIER_64[scaleDown];
decimal64divide(&half, &decimal64Two, WORD_NUM(Decimal64), NULL);
if (!decimal64Lt(&remainder, &half, WORD_NUM(Decimal64))) {
Decimal64 delta = {DECIMAL64_SIGN(pDec)};
//decimal64Add(pDec, &delta, WORD_NUM(Decimal64));
}
} }
} }
@ -1461,7 +1482,7 @@ static void decimal64ScaleTo(Decimal64* pDec, uint8_t oldScale, uint8_t newScale
decimal64ScaleDown(pDec, oldScale - newScale); decimal64ScaleDown(pDec, oldScale - newScale);
} }
static void decimal64ScaleAndCheckOverflow(Decimal64* pDec, uint8_t scale, uint8_t toPrec, uint8_t toScale, static void decimal64ScaleAndCheckOverflow(Decimal64* pDec, int8_t scale, uint8_t toPrec, uint8_t toScale,
bool* overflow) { bool* overflow) {
int8_t deltaScale = toScale - scale; int8_t deltaScale = toScale - scale;
if (deltaScale >= 0) { if (deltaScale >= 0) {
@ -1515,7 +1536,7 @@ static int32_t decimal64CountRoundingDelta(const Decimal64* pDec, int8_t scale,
return res; return res;
} }
static void decimal64RoundWithPositiveScale(Decimal64* pDec, uint8_t prec, uint8_t scale, uint8_t toPrec, static void decimal64RoundWithPositiveScale(Decimal64* pDec, uint8_t prec, int8_t scale, uint8_t toPrec,
uint8_t toScale, DecimalRoundType roundType, bool* overflow) { uint8_t toScale, DecimalRoundType roundType, bool* overflow) {
Decimal64 scaled = *pDec; Decimal64 scaled = *pDec;
bool overflowLocal = false; bool overflowLocal = false;
@ -1559,6 +1580,18 @@ int32_t decimal64FromStr(const char* str, int32_t len, uint8_t expectPrecision,
DECIMAL64_SET_VALUE(pRes, 0); DECIMAL64_SET_VALUE(pRes, 0);
code = decimalVarFromStr(str, len, &var); code = decimalVarFromStr(str, len, &var);
if (TSDB_CODE_SUCCESS != code) return code; if (TSDB_CODE_SUCCESS != code) return code;
if (var.precision - var.scale + var.exponent - var.scale > expectPrecision - expectScale) {
return TSDB_CODE_DECIMAL_OVERFLOW;
}
if (var.exponent > var.scale) {
// e + positive, 小数点需要右移, 右移 var.exponent位
//decimal64Multiply(var.pDec, &SCALE_MULTIPLIER_64[var.exponent - var.scale], WORD_NUM(Decimal64));
var.scale -= var.exponent;
} else if (var.exponent < var.scale) {
// e + negative, 小数点需要左移, 左移 var.exponent + var.scale 位
//decimal64divide(var.pDec, &SCALE_MULTIPLIER_64[var.scale - var.exponent], WORD_NUM(Decimal64), NULL);
var.scale -= var.exponent;
}
bool overflow = false; bool overflow = false;
decimal64RoundWithPositiveScale(pRes, var.precision, var.scale, expectPrecision, expectScale, decimal64RoundWithPositiveScale(pRes, var.precision, var.scale, expectPrecision, expectScale,
ROUND_TYPE_HALF_ROUND_UP, &overflow); ROUND_TYPE_HALF_ROUND_UP, &overflow);

View File

@ -904,61 +904,75 @@ void testDecimalFromStr(std::vector<DecimalFromStrTestUnit<BitNum>>& units) {
TEST(decimal, decimalFromStr_all) { TEST(decimal, decimalFromStr_all) {
std::vector<DecimalFromStrTestUnit<64>> units = { std::vector<DecimalFromStrTestUnit<64>> units = {
{10, 2, "123.45", "123.45", false}, {18, 4, "9.999999e1", "100.0000", false},
{10, 2, "123.456", "123.46", false}, {18, 10, "1.23456e7", "12345600.0000000000", false},
{10, 2, "123.454", "123.45"}, {18, 18, "0.0000000000000000000000000010000000000000000199999e26", "0.100000000000000002", false},
{18, 2, "1234567890123456.456", "1234567890123456.46", false}, {18, 18, "0.000000000000000000000000001000000000000000009e26", "0.100000000000000001", false},
{18, 2, "9999999999999999.995", "", true}, {10, 10, "0.000000000010000000009e10", "0.1000000001", false},
{18, 2, "9999999999999999.994", "9999999999999999.99", false}, {10, 10, "0.000000000000000000009e10", "0.0000000001", false},
{18, 2, "-9999999999999999.995", "", true}, {10, 10, "0.00000000001e10", "0.1000000000", false},
{18, 2, "-9999999999999999.994", "-9999999999999999.99", false}, {10, 7, "-1234567890e-8", "-12.3456789", false},
{18, 2, "-9999999999999999.9999999", "", true}, {10, 5, "0e10", "0", true},
{10, 2, "12345678.456", "12345678.46", false}, {10, 4, "1e5", "100000.0000", false},
{10, 2, "12345678.454", "12345678.45", false}, {10, 3, "123.000E4", "1230000.000", false},
{10, 2, "99999999.999", "", true}, {10, 3, "123.456E2", "12345.600", false},
{10, 2, "-99999999.992", "-99999999.99", false}, {18, 2, "1.2345e8", "123450000.00", false},
{10, 2, "-99999999.999", "", true}, {10, 2, "1.2345e8", "123450000.00", true},
{10, 2, "-99999989.998", "-99999990.00", false}, {18, 4, "9.99999", "10.0000", false},
{10, 2, "-99999998.997", "-99999999.00", false}, {10, 2, "123.45", "123.45", false},
{10, 2, "-99999999.009", "-99999999.01", false}, {10, 2, "123.456", "123.46", false},
{18, 17, "-9.99999999999999999999", "", true}, {10, 2, "123.454", "123.45"},
{18, 16, "-99.999999999999999899999", "-99.9999999999999999", false}, {18, 2, "1234567890123456.456", "1234567890123456.46", false},
{18, 16, "-99.999999999999990099999", "-99.9999999999999901", false}, {18, 2, "9999999999999999.995", "", true},
{18, 18, "0.0000000000000000099", "0.000000000000000010", false}, {18, 2, "9999999999999999.994", "9999999999999999.99", false},
{18, 18, "0.0000000000000000001", "0", false}, {18, 2, "-9999999999999999.995", "", true},
{18, 18, "0.0000000000000000005", "0.000000000000000001", false}, {18, 2, "-9999999999999999.994", "-9999999999999999.99", false},
{18, 18, "-0.0000000000000000001", "0", false}, {18, 2, "-9999999999999999.9999999", "", true},
{18, 18, "-0.00000000000000000019999", "0", false}, {10, 2, "12345678.456", "12345678.46", false},
{18, 18, "-0.0000000000000000005", "-0.000000000000000001", false}, {10, 2, "12345678.454", "12345678.45", false},
{18, 18, "-0.00000000000000000000000000123123123", "0", false}, {10, 2, "99999999.999", "", true},
{18, 18, "0.10000000000000000000000000123123123", "0.100000000000000000", false}, {10, 2, "-99999999.992", "-99999999.99", false},
{18, 18, "0.000000000000000000000000000000000000006", "0", false}, {10, 2, "-99999999.999", "", true},
{18, 17, "1.00000000000000000999", "1.00000000000000001", false}, {10, 2, "-99999989.998", "-99999990.00", false},
{18, 17, "1.00000000000000000199", "1.00000000000000000", false}, {10, 2, "-99999998.997", "-99999999.00", false},
{15, 1, "-00000.", "0", false}, {10, 2, "-99999999.009", "-99999999.01", false},
{14, 12, "-.000", "0", false}, {18, 17, "-9.99999999999999999999", "", true},
{14, 12, "-.000000000000", "0", false}, {18, 16, "-99.999999999999999899999", "-99.9999999999999999", false},
{14, 12, "-.", "0", false}, {18, 16, "-99.999999999999990099999", "-99.9999999999999901", false},
//{10, 2, "1.2345e8", "12345000.00", false}, {18, 18, "0.0000000000000000099", "0.000000000000000010", false},
{18, 18, "0.0000000000000000001", "0", false},
{18, 18, "0.0000000000000000005", "0.000000000000000001", false},
{18, 18, "-0.0000000000000000001", "0", false},
{18, 18, "-0.00000000000000000019999", "0", false},
{18, 18, "-0.0000000000000000005", "-0.000000000000000001", false},
{18, 18, "-0.00000000000000000000000000123123123", "0", false},
{18, 18, "0.10000000000000000000000000123123123", "0.100000000000000000", false},
{18, 18, "0.000000000000000000000000000000000000006", "0", false},
{18, 17, "1.00000000000000000999", "1.00000000000000001", false},
{18, 17, "1.00000000000000000199", "1.00000000000000000", false},
{15, 1, "-00000.", "0", false},
{14, 12, "-.000", "0", false},
{14, 12, "-.000000000000", "0", false},
{14, 12, "-.", "0", false},
}; };
testDecimalFromStr(units); testDecimalFromStr(units);
std::vector<DecimalFromStrTestUnit<128>> dec128Units = { std::vector<DecimalFromStrTestUnit<128>> dec128Units = {
{38, 10, "123456789012345678901234567.89012345679", "123456789012345678901234567.8901234568", false}, {38, 10, "123456789012345678901234567.89012345679", "123456789012345678901234567.8901234568", false},
{38, 10, "123456789012345678901234567.89012345670", "123456789012345678901234567.8901234567", false}, {38, 10, "123456789012345678901234567.89012345670", "123456789012345678901234567.8901234567", false},
{38, 10, "-123456789012345678901234567.89012345671", "-123456789012345678901234567.8901234567", false}, {38, 10, "-123456789012345678901234567.89012345671", "-123456789012345678901234567.8901234567", false},
{38, 10, "-123456789012345678901234567.89012345679", "-123456789012345678901234567.8901234568", false}, {38, 10, "-123456789012345678901234567.89012345679", "-123456789012345678901234567.8901234568", false},
{38, 10, "-9999999999999999999999999999.99999999995", "", true}, {38, 10, "-9999999999999999999999999999.99999999995", "", true},
{38, 10, "-9999999999999999999999999999.99999999994", "-9999999999999999999999999999.9999999999", false}, {38, 10, "-9999999999999999999999999999.99999999994", "-9999999999999999999999999999.9999999999", false},
{38, 10, "9999999999999999999999999999.99999999996", "", true}, {38, 10, "9999999999999999999999999999.99999999996", "", true},
{38, 10, "9999999999999999999999999999.99999999994", "9999999999999999999999999999.9999999999", false}, {38, 10, "9999999999999999999999999999.99999999994", "9999999999999999999999999999.9999999999", false},
{36, 35, "9.99999999999999999999999999999999999", "9.99999999999999999999999999999999999", false}, {36, 35, "9.99999999999999999999999999999999999", "9.99999999999999999999999999999999999", false},
{36, 35, "9.999999999999999999999999999999999999111231231", "", true}, {36, 35, "9.999999999999999999999999999999999999111231231", "", true},
{38, 38, "0.000000000000000000000000000000000000001", "0", false}, {38, 38, "0.000000000000000000000000000000000000001", "0", false},
{38, 38, "0.000000000000000000000000000000000000006", "0.00000000000000000000000000000000000001", false}, {38, 38, "0.000000000000000000000000000000000000006", "0.00000000000000000000000000000000000001", false},
{38, 35, "123.000000000000000000000000000000001", "123.00000000000000000000000000000000100", false}, {38, 35, "123.000000000000000000000000000000001", "123.00000000000000000000000000000000100", false},
{38, 5, "123.", "123.00000", false}, {38, 5, "123.", "123.00000", false},
{20, 4, "-.12345", "-0.1235", false}, {20, 4, "-.12345", "-0.1235", false},
}; };
testDecimalFromStr(dec128Units); testDecimalFromStr(dec128Units);