Skip to content

Commit e48c9f8

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

File tree

2 files changed

+42
-3
lines changed

2 files changed

+42
-3
lines changed

src/iceberg/expression/decimal.cc

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1234,6 +1234,19 @@ 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 res = value.Divide(multiplier);
1241+
assert(res);
1242+
*result = res->first;
1243+
return res->second != 0;
1244+
}
1245+
1246+
*result = value * multiplier;
1247+
return (value < 0) ? *result > value : *result < value;
1248+
}
1249+
12371250
} // namespace
12381251

12391252
Result<Decimal> Decimal::FromReal(float x, int32_t precision, int32_t scale) {
@@ -1322,7 +1335,23 @@ Result<Decimal> Decimal::Rescale(int32_t orig_scale, int32_t new_scale) const {
13221335
return *this;
13231336
}
13241337

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

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

test/decimal_test.cc

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
#include <gtest/gtest.h>
2929
#include <sys/types.h>
3030

31-
#include "gmock/gmock.h"
3231
#include "iceberg/util/port.h"
3332
#include "matchers.h"
3433

@@ -558,7 +557,9 @@ TEST(TestDecimalFromReal, FromFloat) {
558557
// 2**14 - 2**-10
559558
FromFloatTestParam{
560559
.real = 16383.999f, .precision = 8, .scale = 3, .expected_string = "16383.999"},
561-
FromFloatTestParam{16383.999f, .precision = 19, .scale = 3,
560+
FromFloatTestParam{.real = 16383.999f,
561+
.precision = 19,
562+
.scale = 3,
562563
.expected_string = "16383.999"},
563564
// 1 - 2**-24
564565
FromFloatTestParam{.real = 0.99999994f,
@@ -1291,4 +1292,13 @@ TEST(DecimalTest, Negate) {
12911292
check(Decimal(12, 0xFFFFFFFFFFFFFFFFULL), Decimal(-13, 1));
12921293
}
12931294

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

0 commit comments

Comments
 (0)