decimal from str
This commit is contained in:
parent
77ed918248
commit
dff26dc577
|
@ -60,8 +60,8 @@ static Decimal64 SCALE_MULTIPLIER_64[TSDB_DECIMAL64_MAX_PRECISION + 1] = {1LL,
|
|||
|
||||
typedef struct DecimalVar {
|
||||
DecimalInternalType type;
|
||||
uint8_t precision;
|
||||
uint8_t scale;
|
||||
int8_t precision;
|
||||
int8_t scale;
|
||||
int32_t exponent;
|
||||
int8_t sign;
|
||||
DecimalType* pDec;
|
||||
|
@ -167,6 +167,14 @@ static int32_t decimalVarFromStr(const char* str, int32_t len, DecimalVar* resul
|
|||
default:
|
||||
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) {
|
||||
switch (str[pos]) {
|
||||
|
@ -191,10 +199,10 @@ static int32_t decimalVarFromStr(const char* str, int32_t len, DecimalVar* resul
|
|||
case '9': {
|
||||
leadingZeroes = false;
|
||||
++places;
|
||||
int32_t curPrec = result->precision + places;
|
||||
int32_t curPrec = result->precision + places - result->exponent;
|
||||
if (curPrec > maxPrecision(result->type)) {
|
||||
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};
|
||||
if (places > 1) {
|
||||
int32_t scaleUp = places - 1;
|
||||
|
@ -213,18 +221,22 @@ static int32_t decimalVarFromStr(const char* str, int32_t len, DecimalVar* resul
|
|||
} else {
|
||||
return TSDB_CODE_DECIMAL_OVERFLOW;
|
||||
}
|
||||
} else {
|
||||
if (afterPoint && result->precision == 0) {
|
||||
result->precision = places;
|
||||
result->scale = places;
|
||||
} else {
|
||||
result->precision += places;
|
||||
if (afterPoint) {
|
||||
result->scale += places;
|
||||
result->exponent -= places;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
Decimal64 digit = {str[pos] - '0'};
|
||||
pOps->add(result->pDec, &digit, WORD_NUM(Decimal64));
|
||||
places = 0;
|
||||
break;
|
||||
|
@ -232,7 +244,7 @@ static int32_t decimalVarFromStr(const char* str, int32_t len, DecimalVar* resul
|
|||
}
|
||||
case 'e':
|
||||
case 'E': {
|
||||
result->exponent += strnatoi(str + pos + 1, len - pos - 1);
|
||||
//result->exponent += atoi(str + pos + 1);
|
||||
stop = true;
|
||||
} break;
|
||||
default:
|
||||
|
@ -240,6 +252,8 @@ static int32_t decimalVarFromStr(const char* str, int32_t len, DecimalVar* resul
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (rounded) {
|
||||
}
|
||||
if (result->sign < 0) {
|
||||
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 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);
|
||||
|
||||
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) {
|
||||
if (scaleDown > 0) {
|
||||
Decimal64 divisor = SCALE_MULTIPLIER_64[scaleDown];
|
||||
decimal64divide(pDec, &divisor, WORD_NUM(Decimal64), NULL);
|
||||
Decimal64 divisor = SCALE_MULTIPLIER_64[scaleDown], remainder = {0};
|
||||
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);
|
||||
}
|
||||
|
||||
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) {
|
||||
int8_t deltaScale = toScale - scale;
|
||||
if (deltaScale >= 0) {
|
||||
|
@ -1515,7 +1536,7 @@ static int32_t decimal64CountRoundingDelta(const Decimal64* pDec, int8_t scale,
|
|||
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) {
|
||||
Decimal64 scaled = *pDec;
|
||||
bool overflowLocal = false;
|
||||
|
@ -1559,6 +1580,18 @@ int32_t decimal64FromStr(const char* str, int32_t len, uint8_t expectPrecision,
|
|||
DECIMAL64_SET_VALUE(pRes, 0);
|
||||
code = decimalVarFromStr(str, len, &var);
|
||||
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;
|
||||
decimal64RoundWithPositiveScale(pRes, var.precision, var.scale, expectPrecision, expectScale,
|
||||
ROUND_TYPE_HALF_ROUND_UP, &overflow);
|
||||
|
|
|
@ -904,6 +904,21 @@ void testDecimalFromStr(std::vector<DecimalFromStrTestUnit<BitNum>>& units) {
|
|||
|
||||
TEST(decimal, decimalFromStr_all) {
|
||||
std::vector<DecimalFromStrTestUnit<64>> units = {
|
||||
{18, 4, "9.999999e1", "100.0000", false},
|
||||
{18, 10, "1.23456e7", "12345600.0000000000", false},
|
||||
{18, 18, "0.0000000000000000000000000010000000000000000199999e26", "0.100000000000000002", false},
|
||||
{18, 18, "0.000000000000000000000000001000000000000000009e26", "0.100000000000000001", false},
|
||||
{10, 10, "0.000000000010000000009e10", "0.1000000001", false},
|
||||
{10, 10, "0.000000000000000000009e10", "0.0000000001", false},
|
||||
{10, 10, "0.00000000001e10", "0.1000000000", false},
|
||||
{10, 7, "-1234567890e-8", "-12.3456789", false},
|
||||
{10, 5, "0e10", "0", true},
|
||||
{10, 4, "1e5", "100000.0000", false},
|
||||
{10, 3, "123.000E4", "1230000.000", false},
|
||||
{10, 3, "123.456E2", "12345.600", false},
|
||||
{18, 2, "1.2345e8", "123450000.00", false},
|
||||
{10, 2, "1.2345e8", "123450000.00", true},
|
||||
{18, 4, "9.99999", "10.0000", false},
|
||||
{10, 2, "123.45", "123.45", false},
|
||||
{10, 2, "123.456", "123.46", false},
|
||||
{10, 2, "123.454", "123.45"},
|
||||
|
@ -939,7 +954,6 @@ TEST(decimal, decimalFromStr_all) {
|
|||
{14, 12, "-.000", "0", false},
|
||||
{14, 12, "-.000000000000", "0", false},
|
||||
{14, 12, "-.", "0", false},
|
||||
//{10, 2, "1.2345e8", "12345000.00", false},
|
||||
};
|
||||
testDecimalFromStr(units);
|
||||
|
||||
|
|
Loading…
Reference in New Issue