1 | // Licensed to the Apache Software Foundation (ASF) under one |
2 | // or more contributor license agreements. See the NOTICE file |
3 | // distributed with this work for additional information |
4 | // regarding copyright ownership. The ASF licenses this file |
5 | // to you under the Apache License, Version 2.0 (the |
6 | // "License"); you may not use this file except in compliance |
7 | // with the License. You may obtain a copy of the License at |
8 | // |
9 | // http://www.apache.org/licenses/LICENSE-2.0 |
10 | // |
11 | // Unless required by applicable law or agreed to in writing, |
12 | // software distributed under the License is distributed on an |
13 | // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
14 | // KIND, either express or implied. See the License for the |
15 | // specific language governing permissions and limitations |
16 | // under the License. |
17 | |
18 | #include <algorithm> |
19 | #include <array> |
20 | #include <cmath> |
21 | #include <cstdint> |
22 | #include <string> |
23 | #include <tuple> |
24 | |
25 | #include <gtest/gtest.h> |
26 | |
27 | #include "arrow/status.h" |
28 | #include "arrow/test-util.h" |
29 | #include "arrow/util/decimal.h" |
30 | #include "arrow/util/macros.h" |
31 | |
32 | namespace arrow { |
33 | |
34 | class DecimalTestFixture : public ::testing::Test { |
35 | public: |
36 | DecimalTestFixture() : integer_value_(23423445), string_value_("234.23445" ) {} |
37 | Decimal128 integer_value_; |
38 | std::string string_value_; |
39 | }; |
40 | |
41 | TEST_F(DecimalTestFixture, TestToString) { |
42 | Decimal128 decimal(this->integer_value_); |
43 | int32_t scale = 5; |
44 | std::string result = decimal.ToString(scale); |
45 | ASSERT_EQ(result, this->string_value_); |
46 | } |
47 | |
48 | TEST_F(DecimalTestFixture, TestFromString) { |
49 | Decimal128 expected(this->integer_value_); |
50 | Decimal128 result; |
51 | int32_t precision, scale; |
52 | ASSERT_OK(Decimal128::FromString(this->string_value_, &result, &precision, &scale)); |
53 | ASSERT_EQ(result, expected); |
54 | ASSERT_EQ(precision, 8); |
55 | ASSERT_EQ(scale, 5); |
56 | } |
57 | |
58 | TEST_F(DecimalTestFixture, TestStringStartingWithPlus) { |
59 | std::string plus_value("+234.234" ); |
60 | Decimal128 out; |
61 | int32_t scale; |
62 | int32_t precision; |
63 | ASSERT_OK(Decimal128::FromString(plus_value, &out, &precision, &scale)); |
64 | ASSERT_EQ(234234, out); |
65 | ASSERT_EQ(6, precision); |
66 | ASSERT_EQ(3, scale); |
67 | } |
68 | |
69 | TEST_F(DecimalTestFixture, TestStringStartingWithPlus128) { |
70 | std::string plus_value("+2342394230592.232349023094" ); |
71 | Decimal128 expected_value("2342394230592232349023094" ); |
72 | Decimal128 out; |
73 | int32_t scale; |
74 | int32_t precision; |
75 | ASSERT_OK(Decimal128::FromString(plus_value, &out, &precision, &scale)); |
76 | ASSERT_EQ(expected_value, out); |
77 | ASSERT_EQ(25, precision); |
78 | ASSERT_EQ(12, scale); |
79 | } |
80 | |
81 | TEST(DecimalTest, TestFromStringDecimal128) { |
82 | std::string string_value("-23049223942343532412" ); |
83 | Decimal128 result(string_value); |
84 | Decimal128 expected(static_cast<int64_t>(-230492239423435324)); |
85 | ASSERT_EQ(result, expected * 100 - 12); |
86 | |
87 | // Sanity check that our number is actually using more than 64 bits |
88 | ASSERT_NE(result.high_bits(), 0); |
89 | } |
90 | |
91 | TEST(DecimalTest, TestFromDecimalString128) { |
92 | std::string string_value("-23049223942343.532412" ); |
93 | Decimal128 result; |
94 | ASSERT_OK(Decimal128::FromString(string_value, &result)); |
95 | Decimal128 expected(static_cast<int64_t>(-230492239423435324)); |
96 | ASSERT_EQ(result, expected * 100 - 12); |
97 | |
98 | // Sanity check that our number is actually using more than 64 bits |
99 | ASSERT_NE(result.high_bits(), 0); |
100 | } |
101 | |
102 | TEST(DecimalTest, TestDecimal32SignedRoundTrip) { |
103 | Decimal128 expected("-3402692" ); |
104 | |
105 | auto bytes = expected.ToBytes(); |
106 | Decimal128 result(bytes.data()); |
107 | ASSERT_EQ(expected, result); |
108 | } |
109 | |
110 | TEST(DecimalTest, TestDecimal64SignedRoundTrip) { |
111 | Decimal128 expected; |
112 | std::string string_value("-34034293045.921" ); |
113 | ASSERT_OK(Decimal128::FromString(string_value, &expected)); |
114 | |
115 | auto bytes = expected.ToBytes(); |
116 | Decimal128 result(bytes.data()); |
117 | |
118 | ASSERT_EQ(expected, result); |
119 | } |
120 | |
121 | TEST(DecimalTest, TestDecimalStringAndBytesRoundTrip) { |
122 | Decimal128 expected; |
123 | std::string string_value("-340282366920938463463374607431.711455" ); |
124 | ASSERT_OK(Decimal128::FromString(string_value, &expected)); |
125 | |
126 | std::string expected_string_value("-340282366920938463463374607431711455" ); |
127 | Decimal128 expected_underlying_value(expected_string_value); |
128 | |
129 | ASSERT_EQ(expected, expected_underlying_value); |
130 | |
131 | auto bytes = expected.ToBytes(); |
132 | |
133 | Decimal128 result(bytes.data()); |
134 | |
135 | ASSERT_EQ(expected, result); |
136 | } |
137 | |
138 | TEST(DecimalTest, TestInvalidInputMinus) { |
139 | std::string invalid_value("-" ); |
140 | Decimal128 out; |
141 | Status status = Decimal128::FromString(invalid_value, &out); |
142 | ASSERT_RAISES(Invalid, status); |
143 | } |
144 | |
145 | TEST(DecimalTest, TestInvalidInputDot) { |
146 | std::string invalid_value("0.0.0" ); |
147 | Decimal128 out; |
148 | Status status = Decimal128::FromString(invalid_value, &out); |
149 | ASSERT_RAISES(Invalid, status); |
150 | } |
151 | |
152 | TEST(DecimalTest, TestInvalidInputEmbeddedMinus) { |
153 | std::string invalid_value("0-13-32" ); |
154 | Decimal128 out; |
155 | Status status = Decimal128::FromString(invalid_value, &out); |
156 | ASSERT_RAISES(Invalid, status); |
157 | } |
158 | |
159 | TEST(DecimalTest, TestInvalidInputSingleChar) { |
160 | std::string invalid_value("a" ); |
161 | Decimal128 out; |
162 | Status status = Decimal128::FromString(invalid_value, &out); |
163 | ASSERT_RAISES(Invalid, status); |
164 | } |
165 | |
166 | TEST(DecimalTest, TestInvalidInputWithValidSubstring) { |
167 | std::string invalid_value("-23092.235-" ); |
168 | Decimal128 out; |
169 | Status status = Decimal128::FromString(invalid_value, &out); |
170 | auto msg = status.message(); |
171 | ASSERT_RAISES(Invalid, status); |
172 | } |
173 | |
174 | TEST(DecimalTest, TestInvalidInputWithMinusPlus) { |
175 | std::string invalid_value("-+23092.235" ); |
176 | Decimal128 out; |
177 | Status status = Decimal128::FromString(invalid_value, &out); |
178 | ASSERT_RAISES(Invalid, status); |
179 | } |
180 | |
181 | TEST(DecimalTest, TestInvalidInputWithPlusMinus) { |
182 | std::string invalid_value("+-23092.235" ); |
183 | Decimal128 out; |
184 | Status status = Decimal128::FromString(invalid_value, &out); |
185 | ASSERT_RAISES(Invalid, status); |
186 | } |
187 | |
188 | TEST(DecimalTest, TestInvalidInputWithLeadingZeros) { |
189 | std::string invalid_value("00a" ); |
190 | Decimal128 out; |
191 | Status status = Decimal128::FromString(invalid_value, &out); |
192 | ASSERT_RAISES(Invalid, status); |
193 | } |
194 | |
195 | TEST(DecimalZerosTest, LeadingZerosNoDecimalPoint) { |
196 | std::string string_value("0000000" ); |
197 | Decimal128 d; |
198 | int32_t precision; |
199 | int32_t scale; |
200 | ASSERT_OK(Decimal128::FromString(string_value, &d, &precision, &scale)); |
201 | ASSERT_EQ(0, precision); |
202 | ASSERT_EQ(0, scale); |
203 | ASSERT_EQ(0, d); |
204 | } |
205 | |
206 | TEST(DecimalZerosTest, LeadingZerosDecimalPoint) { |
207 | std::string string_value("000.0000" ); |
208 | Decimal128 d; |
209 | int32_t precision; |
210 | int32_t scale; |
211 | ASSERT_OK(Decimal128::FromString(string_value, &d, &precision, &scale)); |
212 | ASSERT_EQ(4, precision); |
213 | ASSERT_EQ(4, scale); |
214 | ASSERT_EQ(0, d); |
215 | } |
216 | |
217 | TEST(DecimalZerosTest, NoLeadingZerosDecimalPoint) { |
218 | std::string string_value(".00000" ); |
219 | Decimal128 d; |
220 | int32_t precision; |
221 | int32_t scale; |
222 | ASSERT_OK(Decimal128::FromString(string_value, &d, &precision, &scale)); |
223 | ASSERT_EQ(5, precision); |
224 | ASSERT_EQ(5, scale); |
225 | ASSERT_EQ(0, d); |
226 | } |
227 | |
228 | template <typename T> |
229 | class Decimal128Test : public ::testing::Test { |
230 | public: |
231 | Decimal128Test() : value_(42) {} |
232 | const T value_; |
233 | }; |
234 | |
235 | using Decimal128Types = |
236 | ::testing::Types<char, unsigned char, short, unsigned short, // NOLINT |
237 | int, unsigned int, long, unsigned long, // NOLINT |
238 | long long, unsigned long long // NOLINT |
239 | >; |
240 | |
241 | TYPED_TEST_CASE(Decimal128Test, Decimal128Types); |
242 | |
243 | TYPED_TEST(Decimal128Test, ConstructibleFromAnyIntegerType) { |
244 | Decimal128 value(this->value_); |
245 | ASSERT_EQ(42, value.low_bits()); |
246 | } |
247 | |
248 | TEST(Decimal128TestTrue, ConstructibleFromBool) { |
249 | Decimal128 value(true); |
250 | ASSERT_EQ(1, value.low_bits()); |
251 | } |
252 | |
253 | TEST(Decimal128TestFalse, ConstructibleFromBool) { |
254 | Decimal128 value(false); |
255 | ASSERT_EQ(0, value.low_bits()); |
256 | } |
257 | |
258 | TEST(Decimal128Test, Division) { |
259 | const std::string expected_string_value("-23923094039234029" ); |
260 | const Decimal128 value(expected_string_value); |
261 | const Decimal128 result(value / 3); |
262 | const Decimal128 expected_value("-7974364679744676" ); |
263 | ASSERT_EQ(expected_value, result); |
264 | } |
265 | |
266 | TEST(Decimal128Test, PrintLargePositiveValue) { |
267 | const std::string string_value("99999999999999999999999999999999999999" ); |
268 | const Decimal128 value(string_value); |
269 | const std::string printed_value = value.ToIntegerString(); |
270 | ASSERT_EQ(string_value, printed_value); |
271 | } |
272 | |
273 | TEST(Decimal128Test, PrintLargeNegativeValue) { |
274 | const std::string string_value("-99999999999999999999999999999999999999" ); |
275 | const Decimal128 value(string_value); |
276 | const std::string printed_value = value.ToIntegerString(); |
277 | ASSERT_EQ(string_value, printed_value); |
278 | } |
279 | |
280 | TEST(Decimal128Test, PrintMaxValue) { |
281 | const std::string string_value("170141183460469231731687303715884105727" ); |
282 | const Decimal128 value(string_value); |
283 | const std::string printed_value = value.ToIntegerString(); |
284 | ASSERT_EQ(string_value, printed_value); |
285 | } |
286 | |
287 | TEST(Decimal128Test, PrintMinValue) { |
288 | const std::string string_value("-170141183460469231731687303715884105728" ); |
289 | const Decimal128 value(string_value); |
290 | const std::string printed_value = value.ToIntegerString(); |
291 | ASSERT_EQ(string_value, printed_value); |
292 | } |
293 | |
294 | class Decimal128PrintingTest |
295 | : public ::testing::TestWithParam<std::tuple<int32_t, int32_t, std::string>> {}; |
296 | |
297 | TEST_P(Decimal128PrintingTest, Print) { |
298 | int32_t test_value; |
299 | int32_t scale; |
300 | std::string expected_string; |
301 | std::tie(test_value, scale, expected_string) = GetParam(); |
302 | const Decimal128 value(test_value); |
303 | const std::string printed_value = value.ToString(scale); |
304 | ASSERT_EQ(expected_string, printed_value); |
305 | } |
306 | |
307 | INSTANTIATE_TEST_CASE_P(Decimal128PrintingTest, Decimal128PrintingTest, |
308 | ::testing::Values(std::make_tuple(123, 1, "12.3" ), |
309 | std::make_tuple(123, 5, "0.00123" ), |
310 | std::make_tuple(123, 10, "1.23E-8" ), |
311 | std::make_tuple(123, -1, "1.23E+3" ), |
312 | std::make_tuple(-123, -1, "-1.23E+3" ), |
313 | std::make_tuple(123, -3, "1.23E+5" ), |
314 | std::make_tuple(-123, -3, "-1.23E+5" ), |
315 | std::make_tuple(12345, -3, "1.2345E+7" ))); |
316 | |
317 | class Decimal128ParsingTest |
318 | : public ::testing::TestWithParam<std::tuple<std::string, uint64_t, int32_t>> {}; |
319 | |
320 | TEST_P(Decimal128ParsingTest, Parse) { |
321 | std::string test_string; |
322 | uint64_t expected_low_bits; |
323 | int32_t expected_scale; |
324 | std::tie(test_string, expected_low_bits, expected_scale) = GetParam(); |
325 | Decimal128 value; |
326 | int32_t scale; |
327 | ASSERT_OK(Decimal128::FromString(test_string, &value, NULLPTR, &scale)); |
328 | ASSERT_EQ(value.low_bits(), expected_low_bits); |
329 | ASSERT_EQ(expected_scale, scale); |
330 | } |
331 | |
332 | INSTANTIATE_TEST_CASE_P(Decimal128ParsingTest, Decimal128ParsingTest, |
333 | ::testing::Values(std::make_tuple("12.3" , 123ULL, 1), |
334 | std::make_tuple("0.00123" , 123ULL, 5), |
335 | std::make_tuple("1.23E-8" , 123ULL, 10), |
336 | std::make_tuple("-1.23E-8" , -123LL, 10), |
337 | std::make_tuple("1.23E+3" , 1230ULL, 0), |
338 | std::make_tuple("-1.23E+3" , -1230LL, 0), |
339 | std::make_tuple("1.23E+5" , 123000ULL, 0), |
340 | std::make_tuple("1.2345E+7" , 12345000ULL, 0), |
341 | std::make_tuple("1.23e-8" , 123ULL, 10), |
342 | std::make_tuple("-1.23e-8" , -123LL, 10), |
343 | std::make_tuple("1.23e+3" , 1230ULL, 0), |
344 | std::make_tuple("-1.23e+3" , -1230LL, 0), |
345 | std::make_tuple("1.23e+5" , 123000ULL, 0), |
346 | std::make_tuple("1.2345e+7" , 12345000ULL, 0))); |
347 | |
348 | class Decimal128ParsingTestInvalid : public ::testing::TestWithParam<std::string> {}; |
349 | |
350 | TEST_P(Decimal128ParsingTestInvalid, Parse) { |
351 | std::string test_string = GetParam(); |
352 | Decimal128 value; |
353 | ASSERT_RAISES(Invalid, Decimal128::FromString(test_string, &value)); |
354 | } |
355 | |
356 | INSTANTIATE_TEST_CASE_P(Decimal128ParsingTestInvalid, Decimal128ParsingTestInvalid, |
357 | ::testing::Values("0.00123D/3" , "1.23eA8" , "1.23E+3A" , |
358 | "-1.23E--5" , "1.2345E+++07" )); |
359 | |
360 | TEST(Decimal128ParseTest, WithExponentAndNullptrScale) { |
361 | Decimal128 value; |
362 | ASSERT_OK(Decimal128::FromString("1.23E-8" , &value)); |
363 | |
364 | const Decimal128 expected_value(123); |
365 | ASSERT_EQ(expected_value, value); |
366 | } |
367 | |
368 | TEST(Decimal128Test, TestSmallNumberFormat) { |
369 | Decimal128 value("0.2" ); |
370 | std::string expected("0.2" ); |
371 | |
372 | const int32_t scale = 1; |
373 | std::string result = value.ToString(scale); |
374 | ASSERT_EQ(expected, result); |
375 | } |
376 | |
377 | TEST(Decimal128Test, TestNoDecimalPointExponential) { |
378 | Decimal128 value; |
379 | int32_t precision; |
380 | int32_t scale; |
381 | ASSERT_OK(Decimal128::FromString("1E1" , &value, &precision, &scale)); |
382 | ASSERT_EQ(10, value.low_bits()); |
383 | ASSERT_EQ(2, precision); |
384 | ASSERT_EQ(0, scale); |
385 | } |
386 | |
387 | TEST(Decimal128Test, TestFromBigEndian) { |
388 | // We test out a variety of scenarios: |
389 | // |
390 | // * Positive values that are left shifted |
391 | // and filled in with the same bit pattern |
392 | // * Negated of the positive values |
393 | // * Complement of the positive values |
394 | // |
395 | // For the positive values, we can call FromBigEndian |
396 | // with a length that is less than 16, whereas we must |
397 | // pass all 16 bytes for the negative and complement. |
398 | // |
399 | // We use a number of bit patterns to increase the coverage |
400 | // of scenarios |
401 | for (int32_t start : {1, 15, /* 00001111 */ |
402 | 85, /* 01010101 */ |
403 | 127 /* 01111111 */}) { |
404 | Decimal128 value(start); |
405 | for (int ii = 0; ii < 16; ++ii) { |
406 | auto little_endian = value.ToBytes(); |
407 | std::reverse(little_endian.begin(), little_endian.end()); |
408 | Decimal128 out; |
409 | // Limit the number of bytes we are passing to make |
410 | // sure that it works correctly. That's why all of the |
411 | // 'start' values don't have a 1 in the most significant |
412 | // bit place |
413 | ASSERT_OK(Decimal128::FromBigEndian(little_endian.data() + 15 - ii, ii + 1, &out)); |
414 | ASSERT_EQ(value, out); |
415 | |
416 | // Negate it and convert to big endian |
417 | auto negated = -value; |
418 | little_endian = negated.ToBytes(); |
419 | std::reverse(little_endian.begin(), little_endian.end()); |
420 | // The sign bit is looked up in the MSB |
421 | ASSERT_OK(Decimal128::FromBigEndian(little_endian.data() + 15 - ii, ii + 1, &out)); |
422 | ASSERT_EQ(negated, out); |
423 | |
424 | // Take the complement and convert to big endian |
425 | auto complement = ~value; |
426 | little_endian = complement.ToBytes(); |
427 | std::reverse(little_endian.begin(), little_endian.end()); |
428 | ASSERT_OK(Decimal128::FromBigEndian(little_endian.data(), 16, &out)); |
429 | ASSERT_EQ(complement, out); |
430 | |
431 | value <<= 8; |
432 | value += Decimal128(start); |
433 | } |
434 | } |
435 | } |
436 | |
437 | TEST(Decimal128Test, TestFromBigEndianBadLength) { |
438 | Decimal128 out; |
439 | ASSERT_RAISES(Invalid, Decimal128::FromBigEndian(0, -1, &out)); |
440 | ASSERT_RAISES(Invalid, Decimal128::FromBigEndian(0, 17, &out)); |
441 | } |
442 | |
443 | TEST(Decimal128Test, TestToInteger) { |
444 | Decimal128 value1("1234" ); |
445 | int32_t out1; |
446 | |
447 | Decimal128 value2("-1234" ); |
448 | int64_t out2; |
449 | |
450 | ASSERT_OK(value1.ToInteger(&out1)); |
451 | ASSERT_EQ(1234, out1); |
452 | |
453 | ASSERT_OK(value1.ToInteger(&out2)); |
454 | ASSERT_EQ(1234, out2); |
455 | |
456 | ASSERT_OK(value2.ToInteger(&out1)); |
457 | ASSERT_EQ(-1234, out1); |
458 | |
459 | ASSERT_OK(value2.ToInteger(&out2)); |
460 | ASSERT_EQ(-1234, out2); |
461 | |
462 | Decimal128 invalid_int32(static_cast<int64_t>(std::pow(2, 31))); |
463 | ASSERT_RAISES(Invalid, invalid_int32.ToInteger(&out1)); |
464 | |
465 | Decimal128 invalid_int64("12345678912345678901" ); |
466 | ASSERT_RAISES(Invalid, invalid_int64.ToInteger(&out2)); |
467 | } |
468 | |
469 | TEST(Decimal128Test, GetWholeAndFraction) { |
470 | Decimal128 value("123456" ); |
471 | Decimal128 whole; |
472 | Decimal128 fraction; |
473 | int32_t out; |
474 | |
475 | value.GetWholeAndFraction(0, &whole, &fraction); |
476 | ASSERT_OK(whole.ToInteger(&out)); |
477 | ASSERT_EQ(123456, out); |
478 | ASSERT_OK(fraction.ToInteger(&out)); |
479 | ASSERT_EQ(0, out); |
480 | |
481 | value.GetWholeAndFraction(1, &whole, &fraction); |
482 | ASSERT_OK(whole.ToInteger(&out)); |
483 | ASSERT_EQ(12345, out); |
484 | ASSERT_OK(fraction.ToInteger(&out)); |
485 | ASSERT_EQ(6, out); |
486 | |
487 | value.GetWholeAndFraction(5, &whole, &fraction); |
488 | ASSERT_OK(whole.ToInteger(&out)); |
489 | ASSERT_EQ(1, out); |
490 | ASSERT_OK(fraction.ToInteger(&out)); |
491 | ASSERT_EQ(23456, out); |
492 | |
493 | value.GetWholeAndFraction(7, &whole, &fraction); |
494 | ASSERT_OK(whole.ToInteger(&out)); |
495 | ASSERT_EQ(0, out); |
496 | ASSERT_OK(fraction.ToInteger(&out)); |
497 | ASSERT_EQ(123456, out); |
498 | } |
499 | |
500 | TEST(Decimal128Test, GetWholeAndFractionNegative) { |
501 | Decimal128 value("-123456" ); |
502 | Decimal128 whole; |
503 | Decimal128 fraction; |
504 | int32_t out; |
505 | |
506 | value.GetWholeAndFraction(0, &whole, &fraction); |
507 | ASSERT_OK(whole.ToInteger(&out)); |
508 | ASSERT_EQ(-123456, out); |
509 | ASSERT_OK(fraction.ToInteger(&out)); |
510 | ASSERT_EQ(0, out); |
511 | |
512 | value.GetWholeAndFraction(1, &whole, &fraction); |
513 | ASSERT_OK(whole.ToInteger(&out)); |
514 | ASSERT_EQ(-12345, out); |
515 | ASSERT_OK(fraction.ToInteger(&out)); |
516 | ASSERT_EQ(-6, out); |
517 | |
518 | value.GetWholeAndFraction(5, &whole, &fraction); |
519 | ASSERT_OK(whole.ToInteger(&out)); |
520 | ASSERT_EQ(-1, out); |
521 | ASSERT_OK(fraction.ToInteger(&out)); |
522 | ASSERT_EQ(-23456, out); |
523 | |
524 | value.GetWholeAndFraction(7, &whole, &fraction); |
525 | ASSERT_OK(whole.ToInteger(&out)); |
526 | ASSERT_EQ(0, out); |
527 | ASSERT_OK(fraction.ToInteger(&out)); |
528 | ASSERT_EQ(-123456, out); |
529 | } |
530 | |
531 | TEST(Decimal128Test, IncreaseScale) { |
532 | Decimal128 result; |
533 | int32_t out; |
534 | |
535 | result = Decimal128("1234" ).IncreaseScaleBy(3); |
536 | ASSERT_OK(result.ToInteger(&out)); |
537 | ASSERT_EQ(1234000, out); |
538 | |
539 | result = Decimal128("-1234" ).IncreaseScaleBy(3); |
540 | ASSERT_OK(result.ToInteger(&out)); |
541 | ASSERT_EQ(-1234000, out); |
542 | } |
543 | |
544 | TEST(Decimal128Test, ReduceScaleAndRound) { |
545 | Decimal128 result; |
546 | int32_t out; |
547 | |
548 | result = Decimal128("123456" ).ReduceScaleBy(1, false); |
549 | ASSERT_OK(result.ToInteger(&out)); |
550 | ASSERT_EQ(12345, out); |
551 | |
552 | result = Decimal128("123456" ).ReduceScaleBy(1, true); |
553 | ASSERT_OK(result.ToInteger(&out)); |
554 | ASSERT_EQ(12346, out); |
555 | |
556 | result = Decimal128("123451" ).ReduceScaleBy(1, true); |
557 | ASSERT_OK(result.ToInteger(&out)); |
558 | ASSERT_EQ(12345, out); |
559 | |
560 | result = Decimal128("-123789" ).ReduceScaleBy(2, true); |
561 | ASSERT_OK(result.ToInteger(&out)); |
562 | ASSERT_EQ(-1238, out); |
563 | |
564 | result = Decimal128("-123749" ).ReduceScaleBy(2, true); |
565 | ASSERT_OK(result.ToInteger(&out)); |
566 | ASSERT_EQ(-1237, out); |
567 | |
568 | result = Decimal128("-123750" ).ReduceScaleBy(2, true); |
569 | ASSERT_OK(result.ToInteger(&out)); |
570 | ASSERT_EQ(-1238, out); |
571 | } |
572 | |
573 | } // namespace arrow |
574 | |