Skip to content

Commit 70068f9

Browse files
committed
feat: add rescale
1 parent 4e062ea commit 70068f9

File tree

2 files changed

+41
-2
lines changed

2 files changed

+41
-2
lines changed

src/iceberg/expression/decimal.cc

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1234,6 +1234,18 @@ static inline uint64_t UInt64FromBigEndian(const uint8_t* bytes, int32_t length)
12341234
#endif
12351235
}
12361236

1237+
static bool RescaleWouldCauseDataLoss(const Decimal& value, int32_t delta_scale,
1238+
const Decimal& multiplier, Decimal* result) {
1239+
if (delta_scale < 0) {
1240+
auto result = value.Divide(multiplier);
1241+
assert(result);
1242+
return result->second != 0;
1243+
}
1244+
1245+
*result = value * multiplier;
1246+
return (value < 0) ? *result > value : *result < value;
1247+
}
1248+
12371249
} // namespace
12381250

12391251
Result<Decimal> Decimal::FromReal(float x, int32_t precision, int32_t scale) {
@@ -1322,7 +1334,23 @@ Result<Decimal> Decimal::Rescale(int32_t orig_scale, int32_t new_scale) const {
13221334
return *this;
13231335
}
13241336

1325-
return NotImplemented("Decimal::Rescale is not implemented yet");
1337+
const int32_t delta_scale = new_scale - orig_scale;
1338+
const int32_t abs_delta_scale = std::abs(delta_scale);
1339+
Decimal out;
1340+
1341+
assert(abs_delta_scale <= kMaxScale);
1342+
1343+
auto& multiplier = kDecimal128PowersOfTen[abs_delta_scale];
1344+
1345+
const bool rescale_would_cause_data_loss =
1346+
RescaleWouldCauseDataLoss(*this, delta_scale, multiplier, &out);
1347+
1348+
if (rescale_would_cause_data_loss) {
1349+
return Invalid("Rescale would cause data loss: {} -> {}", ToIntegerString(),
1350+
out.ToIntegerString());
1351+
}
1352+
1353+
return out;
13261354
}
13271355

13281356
bool Decimal::FitsInPrecision(int32_t precision) const {

test/decimal_test.cc

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,9 @@ TEST(TestDecimalFromReal, FromFloat) {
558558
// 2**14 - 2**-10
559559
FromFloatTestParam{
560560
.real = 16383.999f, .precision = 8, .scale = 3, .expected_string = "16383.999"},
561-
FromFloatTestParam{16383.999f, .precision = 19, .scale = 3,
561+
FromFloatTestParam{.real = 16383.999f,
562+
.precision = 19,
563+
.scale = 3,
562564
.expected_string = "16383.999"},
563565
// 1 - 2**-24
564566
FromFloatTestParam{.real = 0.99999994f,
@@ -1291,4 +1293,13 @@ TEST(DecimalTest, Negate) {
12911293
check(Decimal(12, 0xFFFFFFFFFFFFFFFFULL), Decimal(-13, 1));
12921294
}
12931295

1296+
TEST(DecimalTest, Rescale) {
1297+
ASSERT_EQ(Decimal(11100), Decimal(111).Rescale(0, 2).value());
1298+
ASSERT_EQ(Decimal(111), Decimal(11100).Rescale(2, 0).value());
1299+
ASSERT_EQ(Decimal(5), Decimal(500000).Rescale(6, 1).value());
1300+
ASSERT_EQ(Decimal(500000), Decimal(5).Rescale(1, 6).value());
1301+
1302+
ASSERT_THAT(Decimal(5).Rescale(1, 6), IsError(ErrorKind::kInvalid));
1303+
}
1304+
12941305
} // namespace iceberg

0 commit comments

Comments
 (0)