Skip to content

Commit a64a202

Browse files
committed
fix cast from string to decimal
1 parent 97d2829 commit a64a202

File tree

1 file changed

+73
-5
lines changed

1 file changed

+73
-5
lines changed

velox/type/DecimalUtilOp.h

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -166,17 +166,85 @@ class DecimalUtilOp {
166166
}
167167
}
168168

169+
// Convert a number of scientific notation to normal.
170+
inline static std::string getNormalNumber(const std::string& value) {
171+
size_t dotPos = value.find('.');
172+
size_t expPos = value.find('E');
173+
if (expPos == std::string::npos) {
174+
return value;
175+
}
176+
177+
std::string ints;
178+
std::string digits;
179+
// Get the integers and digits from the base number.
180+
if (dotPos == std::string::npos) {
181+
ints = value.substr(0, expPos);
182+
digits = "";
183+
} else {
184+
ints = value.substr(0, dotPos);
185+
digits = value.substr(dotPos + 1, expPos - dotPos - 1);
186+
}
187+
188+
size_t pos = value.find("E+");
189+
// Handle number with positive exponent.
190+
if (pos != std::string::npos) {
191+
int exponent = std::stoi(value.substr(pos + 2, value.length()));
192+
std::string number = ints;
193+
if (exponent >= digits.length()) {
194+
// Dot is not needed.
195+
number = ints + digits;
196+
for (int i = 0; i < exponent - digits.length(); i++) {
197+
number += '0';
198+
}
199+
} else {
200+
number += digits.substr(0, exponent) + '.' + digits.substr(exponent + 1, digits.length());
201+
}
202+
return number;
203+
}
204+
pos = value.find("E-");
205+
if (pos != std::string::npos) {
206+
int exponent = std::stoi(value.substr(pos + 2, value.length()));
207+
std::string number;
208+
if (exponent < ints.length()) {
209+
number = ints.substr(0, ints.length() - exponent) + '.' +
210+
ints.substr(ints.length() - exponent + 1, ints.length());
211+
} else {
212+
number = "0.";
213+
for (int i = 0; i < exponent - ints.length(); i++) {
214+
number += '0';
215+
}
216+
number += ints;
217+
number += digits;
218+
}
219+
return number;
220+
}
221+
return value;
222+
}
223+
224+
inline static double roundUp(double value, int decimalPlaces) {
225+
const double multiplier = std::pow(10.0, decimalPlaces);
226+
return std::ceil(value * multiplier) / multiplier;
227+
}
228+
169229
// return unscaled value and scale
170230
inline static std::pair<std::string, uint8_t> splitVarChar(
171-
const StringView& value) {
172-
std::string s = value.str();
231+
const StringView& value, int toScale) {
232+
std::string s = getNormalNumber(value.str());
173233
size_t pos = s.find('.');
174234
if (pos == std::string::npos) {
175235
return {s.substr(0, pos), 0};
236+
} else if (toScale < scales.length()) {
237+
// If toScale is less than scales.length(), the string scales will be cut and rounded.
238+
std::string roundedValue = std::to_string(roundUp(std::stod(s), toScale));
239+
std::string scales = roundedValue.substr(pos + 1, roundedValue.length());
240+
return {
241+
roundedValue.substr(0, pos) + scales,
242+
scales.length()};
176243
} else {
244+
std::string scales = s.substr(pos + 1, s.length());
177245
return {
178-
s.substr(0, pos) + s.substr(pos + 1, s.length()),
179-
s.length() - pos - 1};
246+
s.substr(0, pos) + scales,
247+
scales.length()};
180248
}
181249
}
182250

@@ -237,7 +305,7 @@ class DecimalUtilOp {
237305
static_assert(
238306
std::is_same_v<TOutput, UnscaledShortDecimal> ||
239307
std::is_same_v<TOutput, UnscaledLongDecimal>);
240-
auto [unscaledStr, fromScale] = splitVarChar(inputValue);
308+
auto [unscaledStr, fromScale] = splitVarChar(inputValue, toScale);
241309
uint8_t fromPrecision = unscaledStr.size();
242310
VELOX_CHECK_LE(
243311
fromPrecision, DecimalType<TypeKind::LONG_DECIMAL>::kMaxPrecision);

0 commit comments

Comments
 (0)