@@ -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