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 <cmath>
20 #include <memory>
21 #include <string>
22 #include <utility>
23
24 #include <gtest/gtest.h>
25
26 #include "arrow/array.h"
27 #include "arrow/buffer.h"
28 #include "arrow/compute/api.h"
29 #include "arrow/compute/kernels/test_util.h"
30 #include "arrow/type.h"
31 #include "arrow/type_traits.h"
32 #include "arrow/util/bit_util.h"
33 #include "arrow/util/checked_cast.h"
34 #include "arrow/util/math_constants.h"
35 #include "arrow/util/string.h"
36
37 #include "arrow/testing/gtest_common.h"
38 #include "arrow/testing/gtest_util.h"
39 #include "arrow/testing/random.h"
40
41 namespace arrow {
42 namespace compute {
43
44 using IntegralTypes = testing::Types<Int8Type, Int16Type, Int32Type, Int64Type, UInt8Type,
45 UInt16Type, UInt32Type, UInt64Type>;
46
47 using SignedIntegerTypes = testing::Types<Int8Type, Int16Type, Int32Type, Int64Type>;
48
49 using UnsignedIntegerTypes =
50 testing::Types<UInt8Type, UInt16Type, UInt32Type, UInt64Type>;
51
52 // TODO(kszucs): add half-float
53 using FloatingTypes = testing::Types<FloatType, DoubleType>;
54
55 // Assert that all-null-type inputs results in a null-type output.
AssertNullToNull(const std::string & func_name)56 void AssertNullToNull(const std::string& func_name) {
57 SCOPED_TRACE(func_name);
58 ASSERT_OK_AND_ASSIGN(auto func, GetFunctionRegistry()->GetFunction(func_name));
59 ASSERT_OK_AND_ASSIGN(auto nulls, MakeArrayOfNull(null(), /*length=*/7));
60 const auto n = func->arity().num_args;
61
62 {
63 std::vector<Datum> args(n, nulls);
64 ASSERT_OK_AND_ASSIGN(auto result, CallFunction(func_name, args));
65 AssertArraysEqual(*nulls, *result.make_array(), /*verbose=*/true);
66 }
67
68 {
69 std::vector<Datum> args(n, Datum(std::make_shared<NullScalar>()));
70 ASSERT_OK_AND_ASSIGN(auto result, CallFunction(func_name, args));
71 AssertScalarsEqual(NullScalar(), *result.scalar(), /*verbose=*/true);
72 }
73 }
74
75 // Construct an array of decimals, where negative scale is allowed.
76 //
77 // Works around DecimalXXX::FromString intentionally not inferring
78 // negative scales.
DecimalArrayFromJSON(const std::shared_ptr<DataType> & type,const std::string & json)79 std::shared_ptr<Array> DecimalArrayFromJSON(const std::shared_ptr<DataType>& type,
80 const std::string& json) {
81 const auto& ty = checked_cast<const DecimalType&>(*type);
82 if (ty.scale() >= 0) return ArrayFromJSON(type, json);
83 auto p = ty.precision() - ty.scale();
84 auto adjusted_ty = ty.id() == Type::DECIMAL128 ? decimal128(p, 0) : decimal256(p, 0);
85 return Cast(ArrayFromJSON(adjusted_ty, json), type).ValueOrDie().make_array();
86 }
87
88 template <typename T, typename OptionsType>
89 class TestBaseUnaryArithmetic : public TestBase {
90 protected:
91 using ArrowType = T;
92 using CType = typename ArrowType::c_type;
93
type_singleton()94 static std::shared_ptr<DataType> type_singleton() {
95 return TypeTraits<ArrowType>::type_singleton();
96 }
97
98 using UnaryFunction =
99 std::function<Result<Datum>(const Datum&, OptionsType, ExecContext*)>;
100
MakeNullScalar()101 std::shared_ptr<Scalar> MakeNullScalar() {
102 return arrow::MakeNullScalar(type_singleton());
103 }
104
MakeScalar(CType value)105 std::shared_ptr<Scalar> MakeScalar(CType value) {
106 return *arrow::MakeScalar(type_singleton(), value);
107 }
108
SetUp()109 void SetUp() override {}
110
111 // (CScalar, CScalar)
AssertUnaryOp(UnaryFunction func,CType argument,CType expected)112 void AssertUnaryOp(UnaryFunction func, CType argument, CType expected) {
113 auto arg = MakeScalar(argument);
114 auto exp = MakeScalar(expected);
115 ASSERT_OK_AND_ASSIGN(auto actual, func(arg, options_, nullptr));
116 AssertScalarsApproxEqual(*exp, *actual.scalar(), /*verbose=*/true);
117 }
118
119 // (Scalar, Scalar)
AssertUnaryOp(UnaryFunction func,const std::shared_ptr<Scalar> & arg,const std::shared_ptr<Scalar> & expected)120 void AssertUnaryOp(UnaryFunction func, const std::shared_ptr<Scalar>& arg,
121 const std::shared_ptr<Scalar>& expected) {
122 ASSERT_OK_AND_ASSIGN(auto actual, func(arg, options_, nullptr));
123 AssertScalarsApproxEqual(*expected, *actual.scalar(), /*verbose=*/true);
124 }
125
126 // (JSON, JSON)
AssertUnaryOp(UnaryFunction func,const std::string & arg_json,const std::string & expected_json)127 void AssertUnaryOp(UnaryFunction func, const std::string& arg_json,
128 const std::string& expected_json) {
129 auto arg = ArrayFromJSON(type_singleton(), arg_json);
130 auto expected = ArrayFromJSON(type_singleton(), expected_json);
131 AssertUnaryOp(func, arg, expected);
132 }
133
134 // (Array, JSON)
AssertUnaryOp(UnaryFunction func,const std::shared_ptr<Array> & arg,const std::string & expected_json)135 void AssertUnaryOp(UnaryFunction func, const std::shared_ptr<Array>& arg,
136 const std::string& expected_json) {
137 const auto expected = ArrayFromJSON(type_singleton(), expected_json);
138 AssertUnaryOp(func, arg, expected);
139 }
140
141 // (JSON, Array)
AssertUnaryOp(UnaryFunction func,const std::string & arg_json,const std::shared_ptr<Array> & expected)142 void AssertUnaryOp(UnaryFunction func, const std::string& arg_json,
143 const std::shared_ptr<Array>& expected) {
144 auto arg = ArrayFromJSON(type_singleton(), arg_json);
145 AssertUnaryOp(func, arg, expected);
146 }
147
148 // (Array, Array)
AssertUnaryOp(UnaryFunction func,const std::shared_ptr<Array> & arg,const std::shared_ptr<Array> & expected)149 void AssertUnaryOp(UnaryFunction func, const std::shared_ptr<Array>& arg,
150 const std::shared_ptr<Array>& expected) {
151 ASSERT_OK_AND_ASSIGN(auto actual, func(arg, options_, nullptr));
152 ValidateAndAssertApproxEqual(actual.make_array(), expected);
153
154 // Also check (Scalar, Scalar) operations
155 const int64_t length = expected->length();
156 for (int64_t i = 0; i < length; ++i) {
157 const auto expected_scalar = *expected->GetScalar(i);
158 ASSERT_OK_AND_ASSIGN(actual, func(*arg->GetScalar(i), options_, nullptr));
159 AssertScalarsApproxEqual(*expected_scalar, *actual.scalar(), /*verbose=*/true,
160 equal_options_);
161 }
162 }
163
AssertUnaryOpRaises(UnaryFunction func,const std::string & argument,const std::string & expected_msg)164 void AssertUnaryOpRaises(UnaryFunction func, const std::string& argument,
165 const std::string& expected_msg) {
166 auto arg = ArrayFromJSON(type_singleton(), argument);
167 EXPECT_RAISES_WITH_MESSAGE_THAT(Invalid, ::testing::HasSubstr(expected_msg),
168 func(arg, options_, nullptr));
169 for (int64_t i = 0; i < arg->length(); i++) {
170 ASSERT_OK_AND_ASSIGN(auto scalar, arg->GetScalar(i));
171 EXPECT_RAISES_WITH_MESSAGE_THAT(Invalid, ::testing::HasSubstr(expected_msg),
172 func(scalar, options_, nullptr));
173 }
174 }
175
AssertUnaryOpNotImplemented(UnaryFunction func,const std::string & argument)176 void AssertUnaryOpNotImplemented(UnaryFunction func, const std::string& argument) {
177 auto arg = ArrayFromJSON(type_singleton(), argument);
178 const char* expected_msg = "has no kernel matching input types";
179 EXPECT_RAISES_WITH_MESSAGE_THAT(NotImplemented, ::testing::HasSubstr(expected_msg),
180 func(arg, options_, nullptr));
181 }
182
ValidateAndAssertApproxEqual(const std::shared_ptr<Array> & actual,const std::string & expected)183 void ValidateAndAssertApproxEqual(const std::shared_ptr<Array>& actual,
184 const std::string& expected) {
185 const auto exp = ArrayFromJSON(type_singleton(), expected);
186 ValidateAndAssertApproxEqual(actual, exp);
187 }
188
ValidateAndAssertApproxEqual(const std::shared_ptr<Array> & actual,const std::shared_ptr<Array> & expected)189 void ValidateAndAssertApproxEqual(const std::shared_ptr<Array>& actual,
190 const std::shared_ptr<Array>& expected) {
191 ValidateOutput(*actual);
192 AssertArraysApproxEqual(*expected, *actual, /*verbose=*/true, equal_options_);
193 }
194
SetNansEqual(bool value=true)195 void SetNansEqual(bool value = true) {
196 equal_options_ = equal_options_.nans_equal(value);
197 }
198
199 OptionsType options_ = OptionsType();
200 EqualOptions equal_options_ = EqualOptions::Defaults();
201 };
202
203 // Subclasses of TestBaseUnaryArithmetic for different FunctionOptions.
204 template <typename T>
205 class TestUnaryArithmetic : public TestBaseUnaryArithmetic<T, ArithmeticOptions> {
206 protected:
207 using Base = TestBaseUnaryArithmetic<T, ArithmeticOptions>;
208 using Base::options_;
SetOverflowCheck(bool value)209 void SetOverflowCheck(bool value) { options_.check_overflow = value; }
210 };
211
212 template <typename T>
213 class TestUnaryArithmeticIntegral : public TestUnaryArithmetic<T> {};
214
215 template <typename T>
216 class TestUnaryArithmeticSigned : public TestUnaryArithmeticIntegral<T> {};
217
218 template <typename T>
219 class TestUnaryArithmeticUnsigned : public TestUnaryArithmeticIntegral<T> {};
220
221 template <typename T>
222 class TestUnaryArithmeticFloating : public TestUnaryArithmetic<T> {};
223
224 template <typename T>
225 class TestUnaryRound : public TestBaseUnaryArithmetic<T, RoundOptions> {
226 protected:
227 using Base = TestBaseUnaryArithmetic<T, RoundOptions>;
228 using Base::options_;
SetRoundMode(RoundMode value)229 void SetRoundMode(RoundMode value) { options_.round_mode = value; }
SetRoundNdigits(int64_t value)230 void SetRoundNdigits(int64_t value) { options_.ndigits = value; }
231 };
232
233 template <typename T>
234 class TestUnaryRoundIntegral : public TestUnaryRound<T> {};
235
236 template <typename T>
237 class TestUnaryRoundSigned : public TestUnaryRoundIntegral<T> {};
238
239 template <typename T>
240 class TestUnaryRoundUnsigned : public TestUnaryRoundIntegral<T> {};
241
242 template <typename T>
243 class TestUnaryRoundFloating : public TestUnaryRound<T> {};
244
245 template <typename T>
246 class TestUnaryRoundToMultiple
247 : public TestBaseUnaryArithmetic<T, RoundToMultipleOptions> {
248 protected:
249 using Base = TestBaseUnaryArithmetic<T, RoundToMultipleOptions>;
250 using Base::options_;
SetRoundMode(RoundMode value)251 void SetRoundMode(RoundMode value) { options_.round_mode = value; }
SetRoundMultiple(double value)252 void SetRoundMultiple(double value) {
253 options_.multiple = std::make_shared<DoubleScalar>(value);
254 }
255 };
256
257 template <typename T>
258 class TestUnaryRoundToMultipleIntegral : public TestUnaryRoundToMultiple<T> {};
259
260 template <typename T>
261 class TestUnaryRoundToMultipleSigned : public TestUnaryRoundToMultipleIntegral<T> {};
262
263 template <typename T>
264 class TestUnaryRoundToMultipleUnsigned : public TestUnaryRoundToMultipleIntegral<T> {};
265
266 template <typename T>
267 class TestUnaryRoundToMultipleFloating : public TestUnaryRoundToMultiple<T> {};
268
269 class TestArithmeticDecimal : public ::testing::Test {
270 protected:
PositiveScaleTypes()271 std::vector<std::shared_ptr<DataType>> PositiveScaleTypes() {
272 return {decimal128(4, 2), decimal256(4, 2), decimal128(38, 2), decimal256(76, 2)};
273 }
NegativeScaleTypes()274 std::vector<std::shared_ptr<DataType>> NegativeScaleTypes() {
275 return {decimal128(2, -2), decimal256(2, -2)};
276 }
277
278 // Validate that func(*decimals) is the same as
279 // func([cast(x, float64) x for x in decimals])
CheckDecimalToFloat(const std::string & func,const DatumVector & args)280 void CheckDecimalToFloat(const std::string& func, const DatumVector& args) {
281 DatumVector floating_args;
282 for (const auto& arg : args) {
283 if (is_decimal(arg.type()->id())) {
284 ASSERT_OK_AND_ASSIGN(auto casted, Cast(arg, float64()));
285 floating_args.push_back(casted);
286 } else {
287 floating_args.push_back(arg);
288 }
289 }
290 ASSERT_OK_AND_ASSIGN(auto expected, CallFunction(func, floating_args));
291 ASSERT_OK_AND_ASSIGN(auto actual, CallFunction(func, args));
292 auto equal_options = EqualOptions::Defaults().nans_equal(true);
293 AssertDatumsApproxEqual(actual, expected, /*verbose=*/true, equal_options);
294 }
295
CheckRaises(const std::string & func,const DatumVector & args,const std::string & substr,FunctionOptions * options=nullptr)296 void CheckRaises(const std::string& func, const DatumVector& args,
297 const std::string& substr, FunctionOptions* options = nullptr) {
298 EXPECT_RAISES_WITH_MESSAGE_THAT(Invalid, ::testing::HasSubstr(substr),
299 CallFunction(func, args, options));
300 }
301 };
302
303 template <typename T>
304 class TestBinaryArithmetic : public TestBase {
305 protected:
306 using ArrowType = T;
307 using CType = typename ArrowType::c_type;
308
type_singleton()309 static std::shared_ptr<DataType> type_singleton() {
310 return TypeTraits<ArrowType>::type_singleton();
311 }
312
313 using BinaryFunction = std::function<Result<Datum>(const Datum&, const Datum&,
314 ArithmeticOptions, ExecContext*)>;
315
SetUp()316 void SetUp() override { options_.check_overflow = false; }
317
MakeNullScalar()318 std::shared_ptr<Scalar> MakeNullScalar() {
319 return arrow::MakeNullScalar(type_singleton());
320 }
321
MakeScalar(CType value)322 std::shared_ptr<Scalar> MakeScalar(CType value) {
323 return *arrow::MakeScalar(type_singleton(), value);
324 }
325
326 // (Scalar, Scalar)
AssertBinop(BinaryFunction func,CType lhs,CType rhs,CType expected)327 void AssertBinop(BinaryFunction func, CType lhs, CType rhs, CType expected) {
328 auto left = MakeScalar(lhs);
329 auto right = MakeScalar(rhs);
330 auto exp = MakeScalar(expected);
331
332 ASSERT_OK_AND_ASSIGN(auto actual, func(left, right, options_, nullptr));
333 AssertScalarsApproxEqual(*exp, *actual.scalar(), /*verbose=*/true);
334 }
335
336 // (Scalar, Array)
AssertBinop(BinaryFunction func,CType lhs,const std::string & rhs,const std::string & expected)337 void AssertBinop(BinaryFunction func, CType lhs, const std::string& rhs,
338 const std::string& expected) {
339 auto left = MakeScalar(lhs);
340 AssertBinop(func, left, rhs, expected);
341 }
342
343 // (Scalar, Array)
AssertBinop(BinaryFunction func,const std::shared_ptr<Scalar> & left,const std::string & rhs,const std::string & expected)344 void AssertBinop(BinaryFunction func, const std::shared_ptr<Scalar>& left,
345 const std::string& rhs, const std::string& expected) {
346 auto right = ArrayFromJSON(type_singleton(), rhs);
347 auto exp = ArrayFromJSON(type_singleton(), expected);
348
349 ASSERT_OK_AND_ASSIGN(auto actual, func(left, right, options_, nullptr));
350 ValidateAndAssertApproxEqual(actual.make_array(), expected);
351 }
352
353 // (Array, Scalar)
AssertBinop(BinaryFunction func,const std::string & lhs,CType rhs,const std::string & expected)354 void AssertBinop(BinaryFunction func, const std::string& lhs, CType rhs,
355 const std::string& expected) {
356 auto right = MakeScalar(rhs);
357 AssertBinop(func, lhs, right, expected);
358 }
359
360 // (Array, Scalar) => Array
AssertBinop(BinaryFunction func,const std::string & lhs,const std::shared_ptr<Scalar> & right,const std::shared_ptr<Array> & expected)361 void AssertBinop(BinaryFunction func, const std::string& lhs,
362 const std::shared_ptr<Scalar>& right,
363 const std::shared_ptr<Array>& expected) {
364 auto left = ArrayFromJSON(type_singleton(), lhs);
365
366 ASSERT_OK_AND_ASSIGN(auto actual, func(left, right, options_, nullptr));
367 ValidateAndAssertApproxEqual(actual.make_array(), expected);
368 }
369
370 // (Array, Scalar)
AssertBinop(BinaryFunction func,const std::string & lhs,const std::shared_ptr<Scalar> & right,const std::string & expected)371 void AssertBinop(BinaryFunction func, const std::string& lhs,
372 const std::shared_ptr<Scalar>& right, const std::string& expected) {
373 auto left = ArrayFromJSON(type_singleton(), lhs);
374 auto exp = ArrayFromJSON(type_singleton(), expected);
375
376 ASSERT_OK_AND_ASSIGN(auto actual, func(left, right, options_, nullptr));
377 ValidateAndAssertApproxEqual(actual.make_array(), expected);
378 }
379
380 // (Array, Array)
AssertBinop(BinaryFunction func,const std::string & lhs,const std::string & rhs,const std::string & expected)381 void AssertBinop(BinaryFunction func, const std::string& lhs, const std::string& rhs,
382 const std::string& expected) {
383 auto left = ArrayFromJSON(type_singleton(), lhs);
384 auto right = ArrayFromJSON(type_singleton(), rhs);
385
386 AssertBinop(func, left, right, expected);
387 }
388
389 // (Array, Array) => Array
AssertBinop(BinaryFunction func,const std::string & lhs,const std::string & rhs,const std::shared_ptr<Array> & expected)390 void AssertBinop(BinaryFunction func, const std::string& lhs, const std::string& rhs,
391 const std::shared_ptr<Array>& expected) {
392 auto left = ArrayFromJSON(type_singleton(), lhs);
393 auto right = ArrayFromJSON(type_singleton(), rhs);
394
395 AssertBinop(func, left, right, expected);
396 }
397
398 // (Array, Array)
AssertBinop(BinaryFunction func,const std::shared_ptr<Array> & left,const std::shared_ptr<Array> & right,const std::string & expected_json)399 void AssertBinop(BinaryFunction func, const std::shared_ptr<Array>& left,
400 const std::shared_ptr<Array>& right,
401 const std::string& expected_json) {
402 const auto expected = ArrayFromJSON(type_singleton(), expected_json);
403 AssertBinop(func, left, right, expected);
404 }
405
AssertBinop(BinaryFunction func,const std::shared_ptr<Array> & left,const std::shared_ptr<Array> & right,const std::shared_ptr<Array> & expected)406 void AssertBinop(BinaryFunction func, const std::shared_ptr<Array>& left,
407 const std::shared_ptr<Array>& right,
408 const std::shared_ptr<Array>& expected) {
409 ASSERT_OK_AND_ASSIGN(Datum actual, func(left, right, options_, nullptr));
410 ValidateAndAssertApproxEqual(actual.make_array(), expected);
411
412 // Also check (Scalar, Scalar) operations
413 const int64_t length = expected->length();
414 for (int64_t i = 0; i < length; ++i) {
415 const auto expected_scalar = *expected->GetScalar(i);
416 ASSERT_OK_AND_ASSIGN(
417 actual, func(*left->GetScalar(i), *right->GetScalar(i), options_, nullptr));
418 AssertScalarsApproxEqual(*expected_scalar, *actual.scalar(), /*verbose=*/true,
419 equal_options_);
420 }
421 }
422
AssertBinopRaises(BinaryFunction func,const std::string & lhs,const std::string & rhs,const std::string & expected_msg)423 void AssertBinopRaises(BinaryFunction func, const std::string& lhs,
424 const std::string& rhs, const std::string& expected_msg) {
425 auto left = ArrayFromJSON(type_singleton(), lhs);
426 auto right = ArrayFromJSON(type_singleton(), rhs);
427
428 EXPECT_RAISES_WITH_MESSAGE_THAT(Invalid, testing::HasSubstr(expected_msg),
429 func(left, right, options_, nullptr));
430 }
431
ValidateAndAssertApproxEqual(const std::shared_ptr<Array> & actual,const std::string & expected)432 void ValidateAndAssertApproxEqual(const std::shared_ptr<Array>& actual,
433 const std::string& expected) {
434 ValidateAndAssertApproxEqual(actual, ArrayFromJSON(type_singleton(), expected));
435 }
436
ValidateAndAssertApproxEqual(const std::shared_ptr<Array> & actual,const std::shared_ptr<Array> & expected)437 void ValidateAndAssertApproxEqual(const std::shared_ptr<Array>& actual,
438 const std::shared_ptr<Array>& expected) {
439 ValidateOutput(*actual);
440 AssertArraysApproxEqual(*expected, *actual, /*verbose=*/true, equal_options_);
441 }
442
SetOverflowCheck(bool value=true)443 void SetOverflowCheck(bool value = true) { options_.check_overflow = value; }
444
SetNansEqual(bool value=true)445 void SetNansEqual(bool value = true) {
446 this->equal_options_ = equal_options_.nans_equal(value);
447 }
448
449 ArithmeticOptions options_ = ArithmeticOptions();
450 EqualOptions equal_options_ = EqualOptions::Defaults();
451 };
452
453 template <typename... Elements>
MakeArray(Elements...elements)454 std::string MakeArray(Elements... elements) {
455 std::vector<std::string> elements_as_strings = {std::to_string(elements)...};
456
457 std::vector<util::string_view> elements_as_views(sizeof...(Elements));
458 std::copy(elements_as_strings.begin(), elements_as_strings.end(),
459 elements_as_views.begin());
460
461 return "[" + ::arrow::internal::JoinStrings(elements_as_views, ",") + "]";
462 }
463
464 template <typename T>
465 class TestBinaryArithmeticIntegral : public TestBinaryArithmetic<T> {};
466
467 template <typename T>
468 class TestBinaryArithmeticSigned : public TestBinaryArithmeticIntegral<T> {};
469
470 template <typename T>
471 class TestBinaryArithmeticUnsigned : public TestBinaryArithmeticIntegral<T> {};
472
473 template <typename T>
474 class TestBinaryArithmeticFloating : public TestBinaryArithmetic<T> {};
475
476 template <typename T>
477 class TestBitWiseArithmetic : public TestBase {
478 protected:
479 using ArrowType = T;
480 using CType = typename ArrowType::c_type;
481
type_singleton()482 static std::shared_ptr<DataType> type_singleton() {
483 return TypeTraits<ArrowType>::type_singleton();
484 }
485
AssertUnaryOp(const std::string & func,const std::vector<uint8_t> & args,const std::vector<uint8_t> & expected)486 void AssertUnaryOp(const std::string& func, const std::vector<uint8_t>& args,
487 const std::vector<uint8_t>& expected) {
488 auto input = ExpandByteArray(args);
489 auto output = ExpandByteArray(expected);
490 ASSERT_OK_AND_ASSIGN(Datum actual, CallFunction(func, {input}));
491 ValidateAndAssertEqual(actual.make_array(), output);
492 for (int64_t i = 0; i < output->length(); i++) {
493 ASSERT_OK_AND_ASSIGN(Datum actual, CallFunction(func, {*input->GetScalar(i)}));
494 const auto expected_scalar = *output->GetScalar(i);
495 AssertScalarsEqual(*expected_scalar, *actual.scalar(), /*verbose=*/true);
496 }
497 }
498
AssertBinaryOp(const std::string & func,const std::vector<uint8_t> & arg0,const std::vector<uint8_t> & arg1,const std::vector<uint8_t> & expected)499 void AssertBinaryOp(const std::string& func, const std::vector<uint8_t>& arg0,
500 const std::vector<uint8_t>& arg1,
501 const std::vector<uint8_t>& expected) {
502 auto input0 = ExpandByteArray(arg0);
503 auto input1 = ExpandByteArray(arg1);
504 auto output = ExpandByteArray(expected);
505 ASSERT_OK_AND_ASSIGN(Datum actual, CallFunction(func, {input0, input1}));
506 ValidateAndAssertEqual(actual.make_array(), output);
507 for (int64_t i = 0; i < output->length(); i++) {
508 ASSERT_OK_AND_ASSIGN(Datum actual, CallFunction(func, {*input0->GetScalar(i),
509 *input1->GetScalar(i)}));
510 const auto expected_scalar = *output->GetScalar(i);
511 AssertScalarsEqual(*expected_scalar, *actual.scalar(), /*verbose=*/true);
512 }
513 }
514
515 // To make it easier to test different widths, tests give bytes which get repeated to
516 // make an array of the actual type
ExpandByteArray(const std::vector<uint8_t> & values)517 std::shared_ptr<Array> ExpandByteArray(const std::vector<uint8_t>& values) {
518 std::vector<CType> c_values(values.size() + 1);
519 for (size_t i = 0; i < values.size(); i++) {
520 std::memset(&c_values[i], values[i], sizeof(CType));
521 }
522 std::vector<bool> valid(values.size() + 1, true);
523 valid.back() = false;
524 std::shared_ptr<Array> arr;
525 ArrayFromVector<ArrowType>(valid, c_values, &arr);
526 return arr;
527 }
528
ValidateAndAssertEqual(const std::shared_ptr<Array> & actual,const std::shared_ptr<Array> & expected)529 void ValidateAndAssertEqual(const std::shared_ptr<Array>& actual,
530 const std::shared_ptr<Array>& expected) {
531 ASSERT_OK(actual->ValidateFull());
532 AssertArraysEqual(*expected, *actual, /*verbose=*/true);
533 }
534 };
535
536 TYPED_TEST_SUITE(TestUnaryArithmeticIntegral, IntegralTypes);
537 TYPED_TEST_SUITE(TestUnaryArithmeticSigned, SignedIntegerTypes);
538 TYPED_TEST_SUITE(TestUnaryArithmeticUnsigned, UnsignedIntegerTypes);
539 TYPED_TEST_SUITE(TestUnaryArithmeticFloating, FloatingTypes);
540
541 TYPED_TEST_SUITE(TestBinaryArithmeticIntegral, IntegralTypes);
542 TYPED_TEST_SUITE(TestBinaryArithmeticSigned, SignedIntegerTypes);
543 TYPED_TEST_SUITE(TestBinaryArithmeticUnsigned, UnsignedIntegerTypes);
544 TYPED_TEST_SUITE(TestBinaryArithmeticFloating, FloatingTypes);
545
546 TYPED_TEST_SUITE(TestBitWiseArithmetic, IntegralTypes);
547
TYPED_TEST(TestBitWiseArithmetic,BitWiseNot)548 TYPED_TEST(TestBitWiseArithmetic, BitWiseNot) {
549 this->AssertUnaryOp("bit_wise_not", std::vector<uint8_t>{0x00, 0x55, 0xAA, 0xFF},
550 std::vector<uint8_t>{0xFF, 0xAA, 0x55, 0x00});
551 }
552
TYPED_TEST(TestBitWiseArithmetic,BitWiseAnd)553 TYPED_TEST(TestBitWiseArithmetic, BitWiseAnd) {
554 this->AssertBinaryOp("bit_wise_and", std::vector<uint8_t>{0x00, 0xFF, 0x00, 0xFF},
555 std::vector<uint8_t>{0x00, 0x00, 0xFF, 0xFF},
556 std::vector<uint8_t>{0x00, 0x00, 0x00, 0xFF});
557 }
558
TYPED_TEST(TestBitWiseArithmetic,BitWiseOr)559 TYPED_TEST(TestBitWiseArithmetic, BitWiseOr) {
560 this->AssertBinaryOp("bit_wise_or", std::vector<uint8_t>{0x00, 0xFF, 0x00, 0xFF},
561 std::vector<uint8_t>{0x00, 0x00, 0xFF, 0xFF},
562 std::vector<uint8_t>{0x00, 0xFF, 0xFF, 0xFF});
563 }
564
TYPED_TEST(TestBitWiseArithmetic,BitWiseXor)565 TYPED_TEST(TestBitWiseArithmetic, BitWiseXor) {
566 this->AssertBinaryOp("bit_wise_xor", std::vector<uint8_t>{0x00, 0xFF, 0x00, 0xFF},
567 std::vector<uint8_t>{0x00, 0x00, 0xFF, 0xFF},
568 std::vector<uint8_t>{0x00, 0xFF, 0xFF, 0x00});
569 }
570
TYPED_TEST(TestBinaryArithmeticIntegral,Add)571 TYPED_TEST(TestBinaryArithmeticIntegral, Add) {
572 for (auto check_overflow : {false, true}) {
573 this->SetOverflowCheck(check_overflow);
574
575 this->AssertBinop(Add, "[]", "[]", "[]");
576 this->AssertBinop(Add, "[3, 2, 6]", "[1, 0, 2]", "[4, 2, 8]");
577 // Nulls on left side
578 this->AssertBinop(Add, "[null, 1, null]", "[3, 4, 5]", "[null, 5, null]");
579 this->AssertBinop(Add, "[3, 4, 5]", "[null, 1, null]", "[null, 5, null]");
580 // Nulls on both sides
581 this->AssertBinop(Add, "[null, 1, 2]", "[3, 4, null]", "[null, 5, null]");
582 // All nulls
583 this->AssertBinop(Add, "[null]", "[null]", "[null]");
584
585 // Scalar on the left
586 this->AssertBinop(Add, 3, "[1, 2]", "[4, 5]");
587 this->AssertBinop(Add, 3, "[null, 2]", "[null, 5]");
588 this->AssertBinop(Add, this->MakeNullScalar(), "[1, 2]", "[null, null]");
589 this->AssertBinop(Add, this->MakeNullScalar(), "[null, 2]", "[null, null]");
590 // Scalar on the right
591 this->AssertBinop(Add, "[1, 2]", 3, "[4, 5]");
592 this->AssertBinop(Add, "[null, 2]", 3, "[null, 5]");
593 this->AssertBinop(Add, "[1, 2]", this->MakeNullScalar(), "[null, null]");
594 this->AssertBinop(Add, "[null, 2]", this->MakeNullScalar(), "[null, null]");
595 }
596 }
597
TYPED_TEST(TestBinaryArithmeticIntegral,Sub)598 TYPED_TEST(TestBinaryArithmeticIntegral, Sub) {
599 for (auto check_overflow : {false, true}) {
600 this->SetOverflowCheck(check_overflow);
601
602 this->AssertBinop(Subtract, "[]", "[]", "[]");
603 this->AssertBinop(Subtract, "[3, 2, 6]", "[1, 0, 2]", "[2, 2, 4]");
604 // Nulls on left side
605 this->AssertBinop(Subtract, "[null, 4, null]", "[2, 1, 0]", "[null, 3, null]");
606 this->AssertBinop(Subtract, "[5, 4, 3]", "[null, 1, null]", "[null, 3, null]");
607 // Nulls on both sides
608 this->AssertBinop(Subtract, "[null, 4, 3]", "[2, 1, null]", "[null, 3, null]");
609 // All nulls
610 this->AssertBinop(Subtract, "[null]", "[null]", "[null]");
611
612 // Scalar on the left
613 this->AssertBinop(Subtract, 3, "[1, 2]", "[2, 1]");
614 this->AssertBinop(Subtract, 3, "[null, 2]", "[null, 1]");
615 this->AssertBinop(Subtract, this->MakeNullScalar(), "[1, 2]", "[null, null]");
616 this->AssertBinop(Subtract, this->MakeNullScalar(), "[null, 2]", "[null, null]");
617 // Scalar on the right
618 this->AssertBinop(Subtract, "[4, 5]", 3, "[1, 2]");
619 this->AssertBinop(Subtract, "[null, 5]", 3, "[null, 2]");
620 this->AssertBinop(Subtract, "[1, 2]", this->MakeNullScalar(), "[null, null]");
621 this->AssertBinop(Subtract, "[null, 2]", this->MakeNullScalar(), "[null, null]");
622 }
623 }
624
TEST(TestBinaryArithmetic,SubtractTimestamps)625 TEST(TestBinaryArithmetic, SubtractTimestamps) {
626 random::RandomArrayGenerator rand(kRandomSeed);
627
628 const int64_t length = 100;
629
630 auto lhs = rand.Int64(length, 0, 100000000);
631 auto rhs = rand.Int64(length, 0, 100000000);
632 auto expected_int64 = (*Subtract(lhs, rhs)).make_array();
633
634 for (auto unit : TimeUnit::values()) {
635 auto timestamp_ty = timestamp(unit);
636 auto duration_ty = duration(unit);
637
638 auto lhs_timestamp = *lhs->View(timestamp_ty);
639 auto rhs_timestamp = *rhs->View(timestamp_ty);
640
641 auto result = (*Subtract(lhs_timestamp, rhs_timestamp)).make_array();
642 ASSERT_TRUE(result->type()->Equals(*duration_ty));
643 AssertArraysEqual(**result->View(int64()), *expected_int64);
644 }
645 }
646
TYPED_TEST(TestBinaryArithmeticIntegral,Mul)647 TYPED_TEST(TestBinaryArithmeticIntegral, Mul) {
648 for (auto check_overflow : {false, true}) {
649 this->SetOverflowCheck(check_overflow);
650
651 this->AssertBinop(Multiply, "[]", "[]", "[]");
652 this->AssertBinop(Multiply, "[3, 2, 6]", "[1, 0, 2]", "[3, 0, 12]");
653 // Nulls on left side
654 this->AssertBinop(Multiply, "[null, 2, null]", "[4, 5, 6]", "[null, 10, null]");
655 this->AssertBinop(Multiply, "[4, 5, 6]", "[null, 2, null]", "[null, 10, null]");
656 // Nulls on both sides
657 this->AssertBinop(Multiply, "[null, 2, 3]", "[4, 5, null]", "[null, 10, null]");
658 // All nulls
659 this->AssertBinop(Multiply, "[null]", "[null]", "[null]");
660
661 // Scalar on the left
662 this->AssertBinop(Multiply, 3, "[4, 5]", "[12, 15]");
663 this->AssertBinop(Multiply, 3, "[null, 5]", "[null, 15]");
664 this->AssertBinop(Multiply, this->MakeNullScalar(), "[1, 2]", "[null, null]");
665 this->AssertBinop(Multiply, this->MakeNullScalar(), "[null, 2]", "[null, null]");
666 // Scalar on the right
667 this->AssertBinop(Multiply, "[4, 5]", 3, "[12, 15]");
668 this->AssertBinop(Multiply, "[null, 5]", 3, "[null, 15]");
669 this->AssertBinop(Multiply, "[1, 2]", this->MakeNullScalar(), "[null, null]");
670 this->AssertBinop(Multiply, "[null, 2]", this->MakeNullScalar(), "[null, null]");
671 }
672 }
673
TYPED_TEST(TestBinaryArithmeticSigned,Add)674 TYPED_TEST(TestBinaryArithmeticSigned, Add) {
675 this->AssertBinop(Add, "[-7, 6, 5, 4, 3, 2, 1]", "[-6, 5, -4, 3, -2, 1, 0]",
676 "[-13, 11, 1, 7, 1, 3, 1]");
677 this->AssertBinop(Add, -1, "[-6, 5, -4, 3, -2, 1, 0]", "[-7, 4, -5, 2, -3, 0, -1]");
678 this->AssertBinop(Add, -10, 5, -5);
679 }
680
TYPED_TEST(TestBinaryArithmeticSigned,OverflowWraps)681 TYPED_TEST(TestBinaryArithmeticSigned, OverflowWraps) {
682 using CType = typename TestFixture::CType;
683
684 auto min = std::numeric_limits<CType>::lowest();
685 auto max = std::numeric_limits<CType>::max();
686
687 this->AssertBinop(Subtract, MakeArray(min, max, min), MakeArray(1, max, max),
688 MakeArray(max, 0, 1));
689 this->AssertBinop(Multiply, MakeArray(min, max, max), MakeArray(max, 2, max),
690 MakeArray(min, CType(-2), 1));
691 }
692
TYPED_TEST(TestBinaryArithmeticIntegral,OverflowRaises)693 TYPED_TEST(TestBinaryArithmeticIntegral, OverflowRaises) {
694 using CType = typename TestFixture::CType;
695
696 auto min = std::numeric_limits<CType>::lowest();
697 auto max = std::numeric_limits<CType>::max();
698
699 this->SetOverflowCheck(true);
700
701 this->AssertBinopRaises(Add, MakeArray(min, max, max), MakeArray(CType(-1), 1, max),
702 "overflow");
703 this->AssertBinopRaises(Subtract, MakeArray(min, max), MakeArray(1, max), "overflow");
704 this->AssertBinopRaises(Subtract, MakeArray(min), MakeArray(max), "overflow");
705
706 this->AssertBinopRaises(Multiply, MakeArray(min, max, max), MakeArray(max, 2, max),
707 "overflow");
708 }
709
TYPED_TEST(TestBinaryArithmeticSigned,AddOverflowRaises)710 TYPED_TEST(TestBinaryArithmeticSigned, AddOverflowRaises) {
711 using CType = typename TestFixture::CType;
712
713 auto min = std::numeric_limits<CType>::lowest();
714 auto max = std::numeric_limits<CType>::max();
715
716 this->SetOverflowCheck(true);
717
718 this->AssertBinop(Add, MakeArray(max), MakeArray(-1), MakeArray(max - 1));
719 this->AssertBinop(Add, MakeArray(min), MakeArray(1), MakeArray(min + 1));
720 this->AssertBinop(Add, MakeArray(-1), MakeArray(2), MakeArray(1));
721 this->AssertBinop(Add, MakeArray(1), MakeArray(-2), MakeArray(-1));
722
723 this->AssertBinopRaises(Add, MakeArray(max), MakeArray(1), "overflow");
724 this->AssertBinopRaises(Add, MakeArray(min), MakeArray(-1), "overflow");
725
726 // Overflow should not be checked on underlying value slots when output would be null
727 auto left = ArrayFromJSON(this->type_singleton(), MakeArray(1, max, min));
728 auto right = ArrayFromJSON(this->type_singleton(), MakeArray(1, 1, -1));
729 left = TweakValidityBit(left, 1, false);
730 right = TweakValidityBit(right, 2, false);
731 this->AssertBinop(Add, left, right, "[2, null, null]");
732 }
733
TYPED_TEST(TestBinaryArithmeticSigned,SubOverflowRaises)734 TYPED_TEST(TestBinaryArithmeticSigned, SubOverflowRaises) {
735 using CType = typename TestFixture::CType;
736
737 auto min = std::numeric_limits<CType>::lowest();
738 auto max = std::numeric_limits<CType>::max();
739
740 this->SetOverflowCheck(true);
741
742 this->AssertBinop(Subtract, MakeArray(max), MakeArray(1), MakeArray(max - 1));
743 this->AssertBinop(Subtract, MakeArray(min), MakeArray(-1), MakeArray(min + 1));
744 this->AssertBinop(Subtract, MakeArray(-1), MakeArray(-2), MakeArray(1));
745 this->AssertBinop(Subtract, MakeArray(1), MakeArray(2), MakeArray(-1));
746
747 this->AssertBinopRaises(Subtract, MakeArray(max), MakeArray(-1), "overflow");
748 this->AssertBinopRaises(Subtract, MakeArray(min), MakeArray(1), "overflow");
749
750 // Overflow should not be checked on underlying value slots when output would be null
751 auto left = ArrayFromJSON(this->type_singleton(), MakeArray(2, max, min));
752 auto right = ArrayFromJSON(this->type_singleton(), MakeArray(1, -1, 1));
753 left = TweakValidityBit(left, 1, false);
754 right = TweakValidityBit(right, 2, false);
755 this->AssertBinop(Subtract, left, right, "[1, null, null]");
756 }
757
TYPED_TEST(TestBinaryArithmeticSigned,MulOverflowRaises)758 TYPED_TEST(TestBinaryArithmeticSigned, MulOverflowRaises) {
759 using CType = typename TestFixture::CType;
760
761 auto min = std::numeric_limits<CType>::lowest();
762 auto max = std::numeric_limits<CType>::max();
763
764 this->SetOverflowCheck(true);
765
766 this->AssertBinop(Multiply, MakeArray(max), MakeArray(-1), MakeArray(min + 1));
767 this->AssertBinop(Multiply, MakeArray(max / 2), MakeArray(-2), MakeArray(min + 2));
768
769 this->AssertBinopRaises(Multiply, MakeArray(max), MakeArray(2), "overflow");
770 this->AssertBinopRaises(Multiply, MakeArray(max / 2), MakeArray(3), "overflow");
771 this->AssertBinopRaises(Multiply, MakeArray(max / 2), MakeArray(-3), "overflow");
772
773 this->AssertBinopRaises(Multiply, MakeArray(min), MakeArray(2), "overflow");
774 this->AssertBinopRaises(Multiply, MakeArray(min / 2), MakeArray(3), "overflow");
775 this->AssertBinopRaises(Multiply, MakeArray(min), MakeArray(-1), "overflow");
776 this->AssertBinopRaises(Multiply, MakeArray(min / 2), MakeArray(-2), "overflow");
777
778 // Overflow should not be checked on underlying value slots when output would be null
779 auto left = ArrayFromJSON(this->type_singleton(), MakeArray(2, max, min / 2));
780 auto right = ArrayFromJSON(this->type_singleton(), MakeArray(1, 2, 3));
781 left = TweakValidityBit(left, 1, false);
782 right = TweakValidityBit(right, 2, false);
783 this->AssertBinop(Multiply, left, right, "[2, null, null]");
784 }
785
TYPED_TEST(TestBinaryArithmeticUnsigned,OverflowWraps)786 TYPED_TEST(TestBinaryArithmeticUnsigned, OverflowWraps) {
787 using CType = typename TestFixture::CType;
788
789 auto min = std::numeric_limits<CType>::lowest();
790 auto max = std::numeric_limits<CType>::max();
791
792 this->SetOverflowCheck(false);
793 this->AssertBinop(Add, MakeArray(min, max, max), MakeArray(CType(-1), 1, max),
794 MakeArray(max, min, CType(-2)));
795
796 this->AssertBinop(Subtract, MakeArray(min, max, min), MakeArray(1, max, max),
797 MakeArray(max, 0, 1));
798
799 this->AssertBinop(Multiply, MakeArray(min, max, max), MakeArray(max, 2, max),
800 MakeArray(min, CType(-2), 1));
801 }
802
TYPED_TEST(TestBinaryArithmeticSigned,Sub)803 TYPED_TEST(TestBinaryArithmeticSigned, Sub) {
804 this->AssertBinop(Subtract, "[0, 1, 2, 3, 4, 5, 6]", "[1, 2, 3, 4, 5, 6, 7]",
805 "[-1, -1, -1, -1, -1, -1, -1]");
806
807 this->AssertBinop(Subtract, "[0, 0, 0, 0, 0, 0, 0]", "[6, 5, 4, 3, 2, 1, 0]",
808 "[-6, -5, -4, -3, -2, -1, 0]");
809
810 this->AssertBinop(Subtract, "[10, 12, 4, 50, 50, 32, 11]", "[2, 0, 6, 1, 5, 3, 4]",
811 "[8, 12, -2, 49, 45, 29, 7]");
812
813 this->AssertBinop(Subtract, "[null, 1, 3, null, 2, 5]", "[1, 4, 2, 5, 0, 3]",
814 "[null, -3, 1, null, 2, 2]");
815 }
816
TYPED_TEST(TestBinaryArithmeticSigned,Mul)817 TYPED_TEST(TestBinaryArithmeticSigned, Mul) {
818 this->AssertBinop(Multiply, "[-10, 12, 4, 50, -5, 32, 11]", "[-2, 0, -6, 1, 5, 3, 4]",
819 "[20, 0, -24, 50, -25, 96, 44]");
820 this->AssertBinop(Multiply, -2, "[-10, 12, 4, 50, -5, 32, 11]",
821 "[20, -24, -8, -100, 10, -64, -22]");
822 this->AssertBinop(Multiply, -5, -5, 25);
823 }
824
825 // NOTE: cannot test Inf / -Inf (ARROW-9495)
826
TYPED_TEST(TestBinaryArithmeticFloating,Add)827 TYPED_TEST(TestBinaryArithmeticFloating, Add) {
828 this->AssertBinop(Add, "[]", "[]", "[]");
829
830 this->AssertBinop(Add, "[1.5, 0.5]", "[2.0, -3]", "[3.5, -2.5]");
831 // Nulls on the left
832 this->AssertBinop(Add, "[null, 0.5]", "[2.0, -3]", "[null, -2.5]");
833 // Nulls on the right
834 this->AssertBinop(Add, "[1.5, 0.5]", "[null, -3]", "[null, -2.5]");
835 // Nulls on both sides
836 this->AssertBinop(Add, "[null, 1.5, 0.5]", "[2.0, -3, null]", "[null, -1.5, null]");
837
838 // Scalar on the left
839 this->AssertBinop(Add, -1.5f, "[0.0, 2.0]", "[-1.5, 0.5]");
840 this->AssertBinop(Add, -1.5f, "[null, 2.0]", "[null, 0.5]");
841 this->AssertBinop(Add, this->MakeNullScalar(), "[0.0, 2.0]", "[null, null]");
842 this->AssertBinop(Add, this->MakeNullScalar(), "[null, 2.0]", "[null, null]");
843 // Scalar on the right
844 this->AssertBinop(Add, "[0.0, 2.0]", -1.5f, "[-1.5, 0.5]");
845 this->AssertBinop(Add, "[null, 2.0]", -1.5f, "[null, 0.5]");
846 this->AssertBinop(Add, "[0.0, 2.0]", this->MakeNullScalar(), "[null, null]");
847 this->AssertBinop(Add, "[null, 2.0]", this->MakeNullScalar(), "[null, null]");
848 }
849
TYPED_TEST(TestBinaryArithmeticFloating,Div)850 TYPED_TEST(TestBinaryArithmeticFloating, Div) {
851 for (auto check_overflow : {false, true}) {
852 this->SetOverflowCheck(check_overflow);
853 // Empty arrays
854 this->AssertBinop(Divide, "[]", "[]", "[]");
855 // Ordinary arrays
856 this->AssertBinop(Divide, "[3.4, 0.64, 1.28]", "[1, 2, 4]", "[3.4, 0.32, 0.32]");
857 // Array with nulls
858 this->AssertBinop(Divide, "[null, 1, 3.3, null, 2]", "[1, 4, 2, 5, 0.1]",
859 "[null, 0.25, 1.65, null, 20]");
860 // Scalar divides by array
861 this->AssertBinop(Divide, 10.0F, "[null, 1, 2.5, null, 2, 5]",
862 "[null, 10, 4, null, 5, 2]");
863 // Array divides by scalar
864 this->AssertBinop(Divide, "[null, 1, 2.5, null, 2, 5]", 10.0F,
865 "[null, 0.1, 0.25, null, 0.2, 0.5]");
866 // Array with infinity
867 this->AssertBinop(Divide, "[3.4, Inf, -Inf]", "[1, 2, 3]", "[3.4, Inf, -Inf]");
868 // Array with NaN
869 this->SetNansEqual(true);
870 this->AssertBinop(Divide, "[3.4, NaN, 2.0]", "[1, 2, 2.0]", "[3.4, NaN, 1.0]");
871 // Scalar divides by scalar
872 this->AssertBinop(Divide, 21.0F, 3.0F, 7.0F);
873 }
874 }
875
TYPED_TEST(TestBinaryArithmeticIntegral,Div)876 TYPED_TEST(TestBinaryArithmeticIntegral, Div) {
877 for (auto check_overflow : {false, true}) {
878 this->SetOverflowCheck(check_overflow);
879
880 // Empty arrays
881 this->AssertBinop(Divide, "[]", "[]", "[]");
882 // Ordinary arrays
883 this->AssertBinop(Divide, "[3, 2, 6]", "[1, 1, 2]", "[3, 2, 3]");
884 // Array with nulls
885 this->AssertBinop(Divide, "[null, 10, 30, null, 20]", "[1, 4, 2, 5, 10]",
886 "[null, 2, 15, null, 2]");
887 // Scalar divides by array
888 this->AssertBinop(Divide, 33, "[null, 1, 3, null, 2]", "[null, 33, 11, null, 16]");
889 // Array divides by scalar
890 this->AssertBinop(Divide, "[null, 10, 30, null, 2]", 3, "[null, 3, 10, null, 0]");
891 // Scalar divides by scalar
892 this->AssertBinop(Divide, 16, 7, 2);
893 }
894 }
895
TYPED_TEST(TestBinaryArithmeticSigned,Div)896 TYPED_TEST(TestBinaryArithmeticSigned, Div) {
897 // Ordinary arrays
898 this->AssertBinop(Divide, "[-3, 2, -6]", "[1, 1, 2]", "[-3, 2, -3]");
899 // Array with nulls
900 this->AssertBinop(Divide, "[null, 10, 30, null, -20]", "[1, 4, 2, 5, 10]",
901 "[null, 2, 15, null, -2]");
902 // Scalar divides by array
903 this->AssertBinop(Divide, 33, "[null, -1, -3, null, 2]", "[null, -33, -11, null, 16]");
904 // Array divides by scalar
905 this->AssertBinop(Divide, "[null, 10, 30, null, 2]", 3, "[null, 3, 10, null, 0]");
906 // Scalar divides by scalar
907 this->AssertBinop(Divide, -16, -8, 2);
908 }
909
TYPED_TEST(TestBinaryArithmeticIntegral,DivideByZero)910 TYPED_TEST(TestBinaryArithmeticIntegral, DivideByZero) {
911 for (auto check_overflow : {false, true}) {
912 this->SetOverflowCheck(check_overflow);
913 this->AssertBinopRaises(Divide, "[3, 2, 6]", "[1, 1, 0]", "divide by zero");
914 }
915 }
916
TYPED_TEST(TestBinaryArithmeticFloating,DivideByZero)917 TYPED_TEST(TestBinaryArithmeticFloating, DivideByZero) {
918 this->SetOverflowCheck(true);
919 this->AssertBinopRaises(Divide, "[3.0, 2.0, 6.0]", "[1.0, 1.0, 0.0]", "divide by zero");
920 this->AssertBinopRaises(Divide, "[3.0, 2.0, 0.0]", "[1.0, 1.0, 0.0]", "divide by zero");
921 this->AssertBinopRaises(Divide, "[3.0, 2.0, -6.0]", "[1.0, 1.0, 0.0]",
922 "divide by zero");
923
924 this->SetOverflowCheck(false);
925 this->SetNansEqual(true);
926 this->AssertBinop(Divide, "[3.0, 2.0, 6.0]", "[1.0, 1.0, 0.0]", "[3.0, 2.0, Inf]");
927 this->AssertBinop(Divide, "[3.0, 2.0, 0.0]", "[1.0, 1.0, 0.0]", "[3.0, 2.0, NaN]");
928 this->AssertBinop(Divide, "[3.0, 2.0, -6.0]", "[1.0, 1.0, 0.0]", "[3.0, 2.0, -Inf]");
929 }
930
TYPED_TEST(TestBinaryArithmeticSigned,DivideOverflowRaises)931 TYPED_TEST(TestBinaryArithmeticSigned, DivideOverflowRaises) {
932 using CType = typename TestFixture::CType;
933 auto min = std::numeric_limits<CType>::lowest();
934
935 this->SetOverflowCheck(true);
936 this->AssertBinopRaises(Divide, MakeArray(min), MakeArray(-1), "overflow");
937
938 this->SetOverflowCheck(false);
939 this->AssertBinop(Divide, MakeArray(min), MakeArray(-1), "[0]");
940 }
941
TYPED_TEST(TestBinaryArithmeticFloating,Power)942 TYPED_TEST(TestBinaryArithmeticFloating, Power) {
943 using CType = typename TestFixture::CType;
944 auto max = std::numeric_limits<CType>::max();
945 this->SetNansEqual(true);
946
947 for (auto check_overflow : {false, true}) {
948 this->SetOverflowCheck(check_overflow);
949
950 // Empty arrays
951 this->AssertBinop(Power, "[]", "[]", "[]");
952 // Ordinary arrays
953 this->AssertBinop(Power, "[3.4, 16, 0.64, 1.2, 0]", "[1, 0.5, 2, 4, 0]",
954 "[3.4, 4, 0.4096, 2.0736, 1]");
955 // Array with nulls
956 this->AssertBinop(Power, "[null, 1, 3.3, null, 2]", "[1, 4, 2, 5, 0.1]",
957 "[null, 1, 10.89, null, 1.07177346]");
958 // Scalar exponentiated by array
959 this->AssertBinop(Power, 10.0F, "[null, 1, 2.5, null, 2, 5]",
960 "[null, 10, 316.227766017, null, 100, 100000]");
961 // Array exponentiated by scalar
962 this->AssertBinop(Power, "[null, 1, 2.5, null, 2, 5]", 10.0F,
963 "[null, 1, 9536.74316406, null, 1024, 9765625]");
964 // Array with infinity
965 this->AssertBinop(Power, "[3.4, Inf, -Inf, 1.1, 100000]", "[1, 2, 3, Inf, 100000]",
966 "[3.4, Inf, -Inf, Inf, Inf]");
967 // Array with NaN
968 this->AssertBinop(Power, "[3.4, NaN, 2.0]", "[1, 2, 2.0]", "[3.4, NaN, 4.0]");
969 // Scalar exponentiated by scalar
970 this->AssertBinop(Power, 21.0F, 3.0F, 9261.0F);
971 // Divide by zero
972 this->AssertBinop(Power, "[0.0, 0.0]", "[-1.0, -3.0]", "[Inf, Inf]");
973 // Check overflow behaviour
974 this->AssertBinop(Power, max, 10, INFINITY);
975 }
976
977 // Edge cases - removing NaNs
978 this->AssertBinop(Power, "[1, NaN, 0, null, 1.2, -Inf, Inf, 1.1, 1, 0, 1, 0]",
979 "[NaN, 0, NaN, 1, null, 1, 2, -Inf, Inf, 0, 0, 42]",
980 "[1, 1, NaN, null, null, -Inf, Inf, 0, 1, 1, 1, 0]");
981 }
982
TYPED_TEST(TestBinaryArithmeticIntegral,Power)983 TYPED_TEST(TestBinaryArithmeticIntegral, Power) {
984 using CType = typename TestFixture::CType;
985 auto max = std::numeric_limits<CType>::max();
986
987 for (auto check_overflow : {false, true}) {
988 this->SetOverflowCheck(check_overflow);
989
990 // Empty arrays
991 this->AssertBinop(Power, "[]", "[]", "[]");
992 // Ordinary arrays
993 this->AssertBinop(Power, "[3, 2, 6, 2]", "[1, 1, 2, 0]", "[3, 2, 36, 1]");
994 // Array with nulls
995 this->AssertBinop(Power, "[null, 2, 3, null, 20]", "[1, 6, 2, 5, 1]",
996 "[null, 64, 9, null, 20]");
997 // Scalar exponentiated by array
998 this->AssertBinop(Power, 3, "[null, 3, 4, null, 2]", "[null, 27, 81, null, 9]");
999 // Array exponentiated by scalar
1000 this->AssertBinop(Power, "[null, 10, 3, null, 2]", 2, "[null, 100, 9, null, 4]");
1001 // Scalar exponentiated by scalar
1002 this->AssertBinop(Power, 4, 3, 64);
1003 // Edge cases
1004 this->AssertBinop(Power, "[0, 1, 0]", "[0, 0, 42]", "[1, 1, 0]");
1005 }
1006
1007 // Overflow raises
1008 this->SetOverflowCheck(true);
1009 this->AssertBinopRaises(Power, MakeArray(max), MakeArray(10), "overflow");
1010 // Disable overflow check
1011 this->SetOverflowCheck(false);
1012 this->AssertBinop(Power, max, 10, 1);
1013 }
1014
TYPED_TEST(TestBinaryArithmeticSigned,Power)1015 TYPED_TEST(TestBinaryArithmeticSigned, Power) {
1016 using CType = typename TestFixture::CType;
1017 auto max = std::numeric_limits<CType>::max();
1018
1019 for (auto check_overflow : {false, true}) {
1020 this->SetOverflowCheck(check_overflow);
1021
1022 // Empty arrays
1023 this->AssertBinop(Power, "[]", "[]", "[]");
1024 // Ordinary arrays
1025 this->AssertBinop(Power, "[-3, 2, -6, 2]", "[3, 1, 2, 0]", "[-27, 2, 36, 1]");
1026 // Array with nulls
1027 this->AssertBinop(Power, "[null, 10, 127, null, -20]", "[1, 2, 1, 5, 1]",
1028 "[null, 100, 127, null, -20]");
1029 // Scalar exponentiated by array
1030 this->AssertBinop(Power, 11, "[null, 1, null, 2]", "[null, 11, null, 121]");
1031 // Array exponentiated by scalar
1032 this->AssertBinop(Power, "[null, 1, 3, null, 2]", 3, "[null, 1, 27, null, 8]");
1033 // Scalar exponentiated by scalar
1034 this->AssertBinop(Power, 16, 1, 16);
1035 // Edge cases
1036 this->AssertBinop(Power, "[1, 0, -1, 2]", "[0, 42, 0, 1]", "[1, 0, 1, 2]");
1037 // Divide by zero raises
1038 this->AssertBinopRaises(Power, MakeArray(0), MakeArray(-1),
1039 "integers to negative integer powers are not allowed");
1040 }
1041
1042 // Overflow raises
1043 this->SetOverflowCheck(true);
1044 this->AssertBinopRaises(Power, MakeArray(max), MakeArray(10), "overflow");
1045 // Disable overflow check
1046 this->SetOverflowCheck(false);
1047 this->AssertBinop(Power, max, 10, 1);
1048 }
1049
TYPED_TEST(TestBinaryArithmeticFloating,Sub)1050 TYPED_TEST(TestBinaryArithmeticFloating, Sub) {
1051 this->AssertBinop(Subtract, "[]", "[]", "[]");
1052
1053 this->AssertBinop(Subtract, "[1.5, 0.5]", "[2.0, -3]", "[-0.5, 3.5]");
1054 // Nulls on the left
1055 this->AssertBinop(Subtract, "[null, 0.5]", "[2.0, -3]", "[null, 3.5]");
1056 // Nulls on the right
1057 this->AssertBinop(Subtract, "[1.5, 0.5]", "[null, -3]", "[null, 3.5]");
1058 // Nulls on both sides
1059 this->AssertBinop(Subtract, "[null, 1.5, 0.5]", "[2.0, -3, null]", "[null, 4.5, null]");
1060
1061 // Scalar on the left
1062 this->AssertBinop(Subtract, -1.5f, "[0.0, 2.0]", "[-1.5, -3.5]");
1063 this->AssertBinop(Subtract, -1.5f, "[null, 2.0]", "[null, -3.5]");
1064 this->AssertBinop(Subtract, this->MakeNullScalar(), "[0.0, 2.0]", "[null, null]");
1065 this->AssertBinop(Subtract, this->MakeNullScalar(), "[null, 2.0]", "[null, null]");
1066 // Scalar on the right
1067 this->AssertBinop(Subtract, "[0.0, 2.0]", -1.5f, "[1.5, 3.5]");
1068 this->AssertBinop(Subtract, "[null, 2.0]", -1.5f, "[null, 3.5]");
1069 this->AssertBinop(Subtract, "[0.0, 2.0]", this->MakeNullScalar(), "[null, null]");
1070 this->AssertBinop(Subtract, "[null, 2.0]", this->MakeNullScalar(), "[null, null]");
1071 }
1072
TYPED_TEST(TestBinaryArithmeticFloating,Mul)1073 TYPED_TEST(TestBinaryArithmeticFloating, Mul) {
1074 this->AssertBinop(Multiply, "[]", "[]", "[]");
1075
1076 this->AssertBinop(Multiply, "[1.5, 0.5]", "[2.0, -3]", "[3.0, -1.5]");
1077 // Nulls on the left
1078 this->AssertBinop(Multiply, "[null, 0.5]", "[2.0, -3]", "[null, -1.5]");
1079 // Nulls on the right
1080 this->AssertBinop(Multiply, "[1.5, 0.5]", "[null, -3]", "[null, -1.5]");
1081 // Nulls on both sides
1082 this->AssertBinop(Multiply, "[null, 1.5, 0.5]", "[2.0, -3, null]",
1083 "[null, -4.5, null]");
1084
1085 // Scalar on the left
1086 this->AssertBinop(Multiply, -1.5f, "[0.0, 2.0]", "[0.0, -3.0]");
1087 this->AssertBinop(Multiply, -1.5f, "[null, 2.0]", "[null, -3.0]");
1088 this->AssertBinop(Multiply, this->MakeNullScalar(), "[0.0, 2.0]", "[null, null]");
1089 this->AssertBinop(Multiply, this->MakeNullScalar(), "[null, 2.0]", "[null, null]");
1090 // Scalar on the right
1091 this->AssertBinop(Multiply, "[0.0, 2.0]", -1.5f, "[0.0, -3.0]");
1092 this->AssertBinop(Multiply, "[null, 2.0]", -1.5f, "[null, -3.0]");
1093 this->AssertBinop(Multiply, "[0.0, 2.0]", this->MakeNullScalar(), "[null, null]");
1094 this->AssertBinop(Multiply, "[null, 2.0]", this->MakeNullScalar(), "[null, null]");
1095 }
1096
TEST(TestBinaryArithmetic,DispatchBest)1097 TEST(TestBinaryArithmetic, DispatchBest) {
1098 for (std::string name : {"add", "subtract", "multiply", "divide", "power"}) {
1099 for (std::string suffix : {"", "_checked"}) {
1100 name += suffix;
1101
1102 CheckDispatchBest(name, {int32(), int32()}, {int32(), int32()});
1103 CheckDispatchBest(name, {int32(), null()}, {int32(), int32()});
1104 CheckDispatchBest(name, {null(), int32()}, {int32(), int32()});
1105
1106 CheckDispatchBest(name, {int32(), int8()}, {int32(), int32()});
1107 CheckDispatchBest(name, {int32(), int16()}, {int32(), int32()});
1108 CheckDispatchBest(name, {int32(), int32()}, {int32(), int32()});
1109 CheckDispatchBest(name, {int32(), int64()}, {int64(), int64()});
1110
1111 CheckDispatchBest(name, {int32(), uint8()}, {int32(), int32()});
1112 CheckDispatchBest(name, {int32(), uint16()}, {int32(), int32()});
1113 CheckDispatchBest(name, {int32(), uint32()}, {int64(), int64()});
1114 CheckDispatchBest(name, {int32(), uint64()}, {int64(), int64()});
1115
1116 CheckDispatchBest(name, {uint8(), uint8()}, {uint8(), uint8()});
1117 CheckDispatchBest(name, {uint8(), uint16()}, {uint16(), uint16()});
1118
1119 CheckDispatchBest(name, {int32(), float32()}, {float32(), float32()});
1120 CheckDispatchBest(name, {float32(), int64()}, {float32(), float32()});
1121 CheckDispatchBest(name, {float64(), int32()}, {float64(), float64()});
1122
1123 CheckDispatchBest(name, {dictionary(int8(), float64()), float64()},
1124 {float64(), float64()});
1125 CheckDispatchBest(name, {dictionary(int8(), float64()), int16()},
1126 {float64(), float64()});
1127 }
1128 }
1129
1130 CheckDispatchBest("atan2", {int32(), float64()}, {float64(), float64()});
1131 CheckDispatchBest("atan2", {int32(), uint8()}, {float64(), float64()});
1132 CheckDispatchBest("atan2", {int32(), null()}, {float64(), float64()});
1133 CheckDispatchBest("atan2", {float32(), float64()}, {float64(), float64()});
1134 // Integer always promotes to double
1135 CheckDispatchBest("atan2", {float32(), int8()}, {float64(), float64()});
1136 }
1137
TEST(TestBinaryArithmetic,Null)1138 TEST(TestBinaryArithmetic, Null) {
1139 for (std::string name : {"add", "divide", "logb", "multiply", "power", "shift_left",
1140 "shift_right", "subtract", "tan"}) {
1141 for (std::string suffix : {"", "_checked"}) {
1142 name += suffix;
1143 AssertNullToNull(name);
1144 }
1145 }
1146
1147 for (std::string name : {"atan2", "bit_wise_and", "bit_wise_or", "bit_wise_xor"}) {
1148 AssertNullToNull(name);
1149 }
1150 }
1151
TEST(TestBinaryArithmetic,AddWithImplicitCasts)1152 TEST(TestBinaryArithmetic, AddWithImplicitCasts) {
1153 CheckScalarBinary("add", ArrayFromJSON(int32(), "[0, 1, 2, null]"),
1154 ArrayFromJSON(float64(), "[0.25, 0.5, 0.75, 1.0]"),
1155 ArrayFromJSON(float64(), "[0.25, 1.5, 2.75, null]"));
1156
1157 CheckScalarBinary("add", ArrayFromJSON(int8(), "[-16, 0, 16, null]"),
1158 ArrayFromJSON(uint32(), "[3, 4, 5, 7]"),
1159 ArrayFromJSON(int64(), "[-13, 4, 21, null]"));
1160
1161 CheckScalarBinary("add",
1162 ArrayFromJSON(dictionary(int32(), int32()), "[8, 6, 3, null, 2]"),
1163 ArrayFromJSON(uint32(), "[3, 4, 5, 7, 0]"),
1164 ArrayFromJSON(int64(), "[11, 10, 8, null, 2]"));
1165
1166 CheckScalarBinary("add", ArrayFromJSON(int32(), "[0, 1, 2, null]"),
1167 std::make_shared<NullArray>(4),
1168 ArrayFromJSON(int32(), "[null, null, null, null]"));
1169
1170 CheckScalarBinary("add", ArrayFromJSON(dictionary(int32(), int8()), "[0, 1, 2, null]"),
1171 ArrayFromJSON(uint32(), "[3, 4, 5, 7]"),
1172 ArrayFromJSON(int64(), "[3, 5, 7, null]"));
1173 }
1174
TEST(TestBinaryArithmetic,AddWithImplicitCastsUint64EdgeCase)1175 TEST(TestBinaryArithmetic, AddWithImplicitCastsUint64EdgeCase) {
1176 // int64 is as wide as we can promote
1177 CheckDispatchBest("add", {int8(), uint64()}, {int64(), int64()});
1178
1179 // this works sometimes
1180 CheckScalarBinary("add", ArrayFromJSON(int8(), "[-1]"), ArrayFromJSON(uint64(), "[0]"),
1181 ArrayFromJSON(int64(), "[-1]"));
1182
1183 // ... but it can result in impossible implicit casts in the presence of uint64, since
1184 // some uint64 values cannot be cast to int64:
1185 ASSERT_RAISES(Invalid,
1186 CallFunction("add", {ArrayFromJSON(int64(), "[-1]"),
1187 ArrayFromJSON(uint64(), "[18446744073709551615]")}));
1188 }
1189
TEST(TestUnaryArithmetic,DispatchBest)1190 TEST(TestUnaryArithmetic, DispatchBest) {
1191 // All types (with _checked variant)
1192 for (std::string name : {"abs"}) {
1193 for (std::string suffix : {"", "_checked"}) {
1194 name += suffix;
1195 for (const auto& ty : {int8(), int16(), int32(), int64(), uint8(), uint16(),
1196 uint32(), uint64(), float32(), float64()}) {
1197 CheckDispatchBest(name, {ty}, {ty});
1198 CheckDispatchBest(name, {dictionary(int8(), ty)}, {ty});
1199 }
1200 }
1201 }
1202
1203 // All types
1204 for (std::string name : {"negate", "sign"}) {
1205 for (const auto& ty : {int8(), int16(), int32(), int64(), uint8(), uint16(), uint32(),
1206 uint64(), float32(), float64()}) {
1207 CheckDispatchBest(name, {ty}, {ty});
1208 CheckDispatchBest(name, {dictionary(int8(), ty)}, {ty});
1209 }
1210 }
1211
1212 // Signed types
1213 for (std::string name : {"negate_checked"}) {
1214 for (const auto& ty : {int8(), int16(), int32(), int64(), float32(), float64()}) {
1215 CheckDispatchBest(name, {ty}, {ty});
1216 CheckDispatchBest(name, {dictionary(int8(), ty)}, {ty});
1217 }
1218 }
1219
1220 // Float types (with _checked variant)
1221 for (std::string name :
1222 {"ln", "log2", "log10", "log1p", "sin", "cos", "tan", "asin", "acos"}) {
1223 for (std::string suffix : {"", "_checked"}) {
1224 name += suffix;
1225 for (const auto& ty : {float32(), float64()}) {
1226 CheckDispatchBest(name, {ty}, {ty});
1227 CheckDispatchBest(name, {dictionary(int8(), ty)}, {ty});
1228 }
1229 }
1230 }
1231
1232 // Float types
1233 for (std::string name :
1234 {"atan", "sign", "floor", "ceil", "trunc", "round", "round_to_multiple"}) {
1235 for (const auto& ty : {float32(), float64()}) {
1236 CheckDispatchBest(name, {ty}, {ty});
1237 CheckDispatchBest(name, {dictionary(int8(), ty)}, {ty});
1238 }
1239 }
1240
1241 // Integer -> Float64 (with _checked variant)
1242 for (std::string name :
1243 {"ln", "log2", "log10", "log1p", "sin", "cos", "tan", "asin", "acos"}) {
1244 for (std::string suffix : {"", "_checked"}) {
1245 name += suffix;
1246 for (const auto& ty :
1247 {int8(), int16(), int32(), int64(), uint8(), uint16(), uint32(), uint64()}) {
1248 CheckDispatchBest(name, {ty}, {float64()});
1249 CheckDispatchBest(name, {dictionary(int8(), ty)}, {float64()});
1250 }
1251 }
1252 }
1253
1254 // Integer -> Float64
1255 for (std::string name :
1256 {"atan", "floor", "ceil", "trunc", "round", "round_to_multiple"}) {
1257 for (const auto& ty :
1258 {int8(), int16(), int32(), int64(), uint8(), uint16(), uint32(), uint64()}) {
1259 CheckDispatchBest(name, {ty}, {float64()});
1260 CheckDispatchBest(name, {dictionary(int8(), ty)}, {float64()});
1261 }
1262 }
1263 }
1264
TEST(TestUnaryArithmetic,Null)1265 TEST(TestUnaryArithmetic, Null) {
1266 for (std::string name : {"abs", "acos", "asin", "cos", "ln", "log10", "log1p", "log2",
1267 "negate", "sin", "tan"}) {
1268 for (std::string suffix : {"", "_checked"}) {
1269 name += suffix;
1270 AssertNullToNull(name);
1271 }
1272 }
1273
1274 for (std::string name : {"atan", "bit_wise_not", "ceil", "floor", "round",
1275 "round_to_multiple", "sign", "trunc"}) {
1276 AssertNullToNull(name);
1277 }
1278 }
1279
TYPED_TEST(TestUnaryArithmeticSigned,Negate)1280 TYPED_TEST(TestUnaryArithmeticSigned, Negate) {
1281 using CType = typename TestFixture::CType;
1282
1283 auto min = std::numeric_limits<CType>::min();
1284 auto max = std::numeric_limits<CType>::max();
1285
1286 for (auto check_overflow : {false, true}) {
1287 this->SetOverflowCheck(check_overflow);
1288 // Empty arrays
1289 this->AssertUnaryOp(Negate, "[]", "[]");
1290 // Array with nulls
1291 this->AssertUnaryOp(Negate, "[null]", "[null]");
1292 this->AssertUnaryOp(Negate, this->MakeNullScalar(), this->MakeNullScalar());
1293 this->AssertUnaryOp(Negate, "[1, null, -10]", "[-1, null, 10]");
1294 // Arrays with zeros
1295 this->AssertUnaryOp(Negate, "[0, 0, -0]", "[0, -0, 0]");
1296 this->AssertUnaryOp(Negate, 0, -0);
1297 this->AssertUnaryOp(Negate, -0, 0);
1298 this->AssertUnaryOp(Negate, 0, 0);
1299 // Ordinary arrays (positive inputs)
1300 this->AssertUnaryOp(Negate, "[1, 10, 127]", "[-1, -10, -127]");
1301 this->AssertUnaryOp(Negate, 1, -1);
1302 this->AssertUnaryOp(Negate, this->MakeScalar(1), this->MakeScalar(-1));
1303 // Ordinary arrays (negative inputs)
1304 this->AssertUnaryOp(Negate, "[-1, -10, -127]", "[1, 10, 127]");
1305 this->AssertUnaryOp(Negate, -1, 1);
1306 this->AssertUnaryOp(Negate, MakeArray(-1), "[1]");
1307 // Min/max (wrap arounds and overflow)
1308 this->AssertUnaryOp(Negate, max, min + 1);
1309 if (check_overflow) {
1310 this->AssertUnaryOpRaises(Negate, MakeArray(min), "overflow");
1311 } else {
1312 this->AssertUnaryOp(Negate, min, min);
1313 }
1314 }
1315
1316 // Overflow should not be checked on underlying value slots when output would be null
1317 this->SetOverflowCheck(true);
1318 auto arg = ArrayFromJSON(this->type_singleton(), MakeArray(1, max, min));
1319 arg = TweakValidityBit(arg, 1, false);
1320 arg = TweakValidityBit(arg, 2, false);
1321 this->AssertUnaryOp(Negate, arg, "[-1, null, null]");
1322 }
1323
TYPED_TEST(TestUnaryArithmeticUnsigned,Negate)1324 TYPED_TEST(TestUnaryArithmeticUnsigned, Negate) {
1325 using CType = typename TestFixture::CType;
1326
1327 auto min = std::numeric_limits<CType>::min();
1328 auto max = std::numeric_limits<CType>::max();
1329
1330 // Empty arrays
1331 this->AssertUnaryOp(Negate, "[]", "[]");
1332 // Array with nulls
1333 this->AssertUnaryOp(Negate, "[null]", "[null]");
1334 this->AssertUnaryOp(Negate, this->MakeNullScalar(), this->MakeNullScalar());
1335 // Min/max (wrap around)
1336 this->AssertUnaryOp(Negate, min, min);
1337 this->AssertUnaryOp(Negate, max, 1);
1338 this->AssertUnaryOp(Negate, 1, max);
1339 // Not implemented kernels
1340 this->SetOverflowCheck(true);
1341 this->AssertUnaryOpNotImplemented(Negate, "[0]");
1342 }
1343
TYPED_TEST(TestUnaryArithmeticFloating,Negate)1344 TYPED_TEST(TestUnaryArithmeticFloating, Negate) {
1345 using CType = typename TestFixture::CType;
1346
1347 auto min = std::numeric_limits<CType>::lowest();
1348 auto max = std::numeric_limits<CType>::max();
1349
1350 for (auto check_overflow : {false, true}) {
1351 this->SetOverflowCheck(check_overflow);
1352 // Empty arrays
1353 this->AssertUnaryOp(Negate, "[]", "[]");
1354 // Array with nulls
1355 this->AssertUnaryOp(Negate, "[null]", "[null]");
1356 this->AssertUnaryOp(Negate, this->MakeNullScalar(), this->MakeNullScalar());
1357 this->AssertUnaryOp(Negate, "[1.3, null, -10.80]", "[-1.3, null, 10.80]");
1358 // Arrays with zeros
1359 this->AssertUnaryOp(Negate, "[0.0, 0.0, -0.0]", "[0.0, -0.0, 0.0]");
1360 this->AssertUnaryOp(Negate, 0.0F, -0.0F);
1361 this->AssertUnaryOp(Negate, -0.0F, 0.0F);
1362 this->AssertUnaryOp(Negate, 0.0F, 0.0F);
1363 // Ordinary arrays (positive inputs)
1364 this->AssertUnaryOp(Negate, "[1.3, 10.80, 12748.001]", "[-1.3, -10.80, -12748.001]");
1365 this->AssertUnaryOp(Negate, 1.3F, -1.3F);
1366 this->AssertUnaryOp(Negate, this->MakeScalar(1.3F), this->MakeScalar(-1.3F));
1367 // Ordinary arrays (negative inputs)
1368 this->AssertUnaryOp(Negate, "[-1.3, -10.80, -12748.001]", "[1.3, 10.80, 12748.001]");
1369 this->AssertUnaryOp(Negate, -1.3F, 1.3F);
1370 this->AssertUnaryOp(Negate, MakeArray(-1.3F), "[1.3]");
1371 // Arrays with infinites
1372 this->AssertUnaryOp(Negate, "[Inf, -Inf]", "[-Inf, Inf]");
1373 // Arrays with NaNs
1374 this->SetNansEqual(true);
1375 this->AssertUnaryOp(Negate, "[NaN]", "[NaN]");
1376 this->AssertUnaryOp(Negate, "[NaN]", "[-NaN]");
1377 this->AssertUnaryOp(Negate, "[-NaN]", "[NaN]");
1378 // Min/max
1379 this->AssertUnaryOp(Negate, min, max);
1380 this->AssertUnaryOp(Negate, max, min);
1381 }
1382 }
1383
TYPED_TEST(TestUnaryArithmeticSigned,AbsoluteValue)1384 TYPED_TEST(TestUnaryArithmeticSigned, AbsoluteValue) {
1385 using CType = typename TestFixture::CType;
1386
1387 auto min = std::numeric_limits<CType>::min();
1388 auto max = std::numeric_limits<CType>::max();
1389
1390 for (auto check_overflow : {false, true}) {
1391 this->SetOverflowCheck(check_overflow);
1392 // Empty array
1393 this->AssertUnaryOp(AbsoluteValue, "[]", "[]");
1394 // Scalar/arrays with nulls
1395 this->AssertUnaryOp(AbsoluteValue, "[null]", "[null]");
1396 this->AssertUnaryOp(AbsoluteValue, "[1, null, -10]", "[1, null, 10]");
1397 this->AssertUnaryOp(AbsoluteValue, this->MakeNullScalar(), this->MakeNullScalar());
1398 // Scalar/arrays with zeros
1399 this->AssertUnaryOp(AbsoluteValue, "[0, -0]", "[0, 0]");
1400 this->AssertUnaryOp(AbsoluteValue, -0, 0);
1401 this->AssertUnaryOp(AbsoluteValue, 0, 0);
1402 // Ordinary scalar/arrays (positive inputs)
1403 this->AssertUnaryOp(AbsoluteValue, "[1, 10, 127]", "[1, 10, 127]");
1404 this->AssertUnaryOp(AbsoluteValue, 1, 1);
1405 this->AssertUnaryOp(AbsoluteValue, this->MakeScalar(1), this->MakeScalar(1));
1406 // Ordinary scalar/arrays (negative inputs)
1407 this->AssertUnaryOp(AbsoluteValue, "[-1, -10, -127]", "[1, 10, 127]");
1408 this->AssertUnaryOp(AbsoluteValue, -1, 1);
1409 this->AssertUnaryOp(AbsoluteValue, MakeArray(-1), "[1]");
1410 // Min/max
1411 this->AssertUnaryOp(AbsoluteValue, max, max);
1412 if (check_overflow) {
1413 this->AssertUnaryOpRaises(AbsoluteValue, MakeArray(min), "overflow");
1414 } else {
1415 this->AssertUnaryOp(AbsoluteValue, min, min);
1416 }
1417 }
1418
1419 // Overflow should not be checked on underlying value slots when output would be null
1420 this->SetOverflowCheck(true);
1421 auto arg = ArrayFromJSON(this->type_singleton(), MakeArray(-1, max, min));
1422 arg = TweakValidityBit(arg, 1, false);
1423 arg = TweakValidityBit(arg, 2, false);
1424 this->AssertUnaryOp(AbsoluteValue, arg, "[1, null, null]");
1425 }
1426
TYPED_TEST(TestUnaryArithmeticUnsigned,AbsoluteValue)1427 TYPED_TEST(TestUnaryArithmeticUnsigned, AbsoluteValue) {
1428 using CType = typename TestFixture::CType;
1429
1430 auto min = std::numeric_limits<CType>::min();
1431 auto max = std::numeric_limits<CType>::max();
1432
1433 for (auto check_overflow : {false, true}) {
1434 this->SetOverflowCheck(check_overflow);
1435 // Empty arrays
1436 this->AssertUnaryOp(AbsoluteValue, "[]", "[]");
1437 // Array with nulls
1438 this->AssertUnaryOp(AbsoluteValue, "[null]", "[null]");
1439 this->AssertUnaryOp(AbsoluteValue, this->MakeNullScalar(), this->MakeNullScalar());
1440 // Ordinary arrays
1441 this->AssertUnaryOp(AbsoluteValue, "[0, 1, 10, 127]", "[0, 1, 10, 127]");
1442 // Min/max
1443 this->AssertUnaryOp(AbsoluteValue, min, min);
1444 this->AssertUnaryOp(AbsoluteValue, max, max);
1445 }
1446 }
1447
TYPED_TEST(TestUnaryArithmeticFloating,AbsoluteValue)1448 TYPED_TEST(TestUnaryArithmeticFloating, AbsoluteValue) {
1449 using CType = typename TestFixture::CType;
1450
1451 auto min = std::numeric_limits<CType>::lowest();
1452 auto max = std::numeric_limits<CType>::max();
1453
1454 for (auto check_overflow : {false, true}) {
1455 this->SetOverflowCheck(check_overflow);
1456 // Empty array
1457 this->AssertUnaryOp(AbsoluteValue, "[]", "[]");
1458 // Scalar/arrays with nulls
1459 this->AssertUnaryOp(AbsoluteValue, "[null]", "[null]");
1460 this->AssertUnaryOp(AbsoluteValue, "[1.3, null, -10.80]", "[1.3, null, 10.80]");
1461 this->AssertUnaryOp(AbsoluteValue, this->MakeNullScalar(), this->MakeNullScalar());
1462 // Scalars/arrays with zeros
1463 this->AssertUnaryOp(AbsoluteValue, "[0.0, -0.0]", "[0.0, 0.0]");
1464 this->AssertUnaryOp(AbsoluteValue, -0.0F, 0.0F);
1465 this->AssertUnaryOp(AbsoluteValue, 0.0F, 0.0F);
1466 // Ordinary scalars/arrays (positive inputs)
1467 this->AssertUnaryOp(AbsoluteValue, "[1.3, 10.80, 12748.001]",
1468 "[1.3, 10.80, 12748.001]");
1469 this->AssertUnaryOp(AbsoluteValue, 1.3F, 1.3F);
1470 this->AssertUnaryOp(AbsoluteValue, this->MakeScalar(1.3F), this->MakeScalar(1.3F));
1471 // Ordinary scalars/arrays (negative inputs)
1472 this->AssertUnaryOp(AbsoluteValue, "[-1.3, -10.80, -12748.001]",
1473 "[1.3, 10.80, 12748.001]");
1474 this->AssertUnaryOp(AbsoluteValue, -1.3F, 1.3F);
1475 this->AssertUnaryOp(AbsoluteValue, MakeArray(-1.3F), "[1.3]");
1476 // Arrays with infinites
1477 this->AssertUnaryOp(AbsoluteValue, "[Inf, -Inf]", "[Inf, Inf]");
1478 // Arrays with NaNs
1479 this->SetNansEqual(true);
1480 this->AssertUnaryOp(AbsoluteValue, "[NaN]", "[NaN]");
1481 this->AssertUnaryOp(AbsoluteValue, "[-NaN]", "[NaN]");
1482 // Min/max
1483 this->AssertUnaryOp(AbsoluteValue, min, max);
1484 this->AssertUnaryOp(AbsoluteValue, max, max);
1485 }
1486 }
1487
1488 class TestUnaryArithmeticDecimal : public TestArithmeticDecimal {};
1489
1490 // Check two modes exhaustively, give all modes a simple test
TEST_F(TestUnaryArithmeticDecimal,Round)1491 TEST_F(TestUnaryArithmeticDecimal, Round) {
1492 const auto func = "round";
1493 RoundOptions options(2, RoundMode::DOWN);
1494 for (const auto& ty : {decimal128(4, 3), decimal256(4, 3)}) {
1495 auto values = ArrayFromJSON(
1496 ty,
1497 R"(["1.010", "1.012", "1.015", "1.019", "-1.010", "-1.012", "-1.015", "-1.019", null])");
1498 options.round_mode = RoundMode::DOWN;
1499 CheckScalar(
1500 func, {values},
1501 ArrayFromJSON(
1502 ty,
1503 R"(["1.010", "1.010", "1.010", "1.010", "-1.010", "-1.020", "-1.020", "-1.020", null])"),
1504 &options);
1505 options.round_mode = RoundMode::UP;
1506 CheckScalar(
1507 func, {values},
1508 ArrayFromJSON(
1509 ty,
1510 R"(["1.010", "1.020", "1.020", "1.020", "-1.010", "-1.010", "-1.010", "-1.010", null])"),
1511 &options);
1512 options.round_mode = RoundMode::TOWARDS_ZERO;
1513 CheckScalar(
1514 func, {values},
1515 ArrayFromJSON(
1516 ty,
1517 R"(["1.010", "1.010", "1.010", "1.010", "-1.010", "-1.010", "-1.010", "-1.010", null])"),
1518 &options);
1519 options.round_mode = RoundMode::TOWARDS_INFINITY;
1520 CheckScalar(
1521 func, {values},
1522 ArrayFromJSON(
1523 ty,
1524 R"(["1.010", "1.020", "1.020", "1.020", "-1.010", "-1.020", "-1.020", "-1.020", null])"),
1525 &options);
1526 options.round_mode = RoundMode::HALF_DOWN;
1527 CheckScalar(
1528 func, {values},
1529 ArrayFromJSON(
1530 ty,
1531 R"(["1.010", "1.010", "1.010", "1.020", "-1.010", "-1.010", "-1.020", "-1.020", null])"),
1532 &options);
1533 options.round_mode = RoundMode::HALF_UP;
1534 CheckScalar(
1535 func, {values},
1536 ArrayFromJSON(
1537 ty,
1538 R"(["1.010", "1.010", "1.020", "1.020", "-1.010", "-1.010", "-1.010", "-1.020", null])"),
1539 &options);
1540 options.round_mode = RoundMode::HALF_TOWARDS_ZERO;
1541 CheckScalar(
1542 func, {values},
1543 ArrayFromJSON(
1544 ty,
1545 R"(["1.010", "1.010", "1.010", "1.020", "-1.010", "-1.010", "-1.010", "-1.020", null])"),
1546 &options);
1547 options.round_mode = RoundMode::HALF_TOWARDS_INFINITY;
1548 CheckScalar(
1549 func, {values},
1550 ArrayFromJSON(
1551 ty,
1552 R"(["1.010", "1.010", "1.020", "1.020", "-1.010", "-1.010", "-1.020", "-1.020", null])"),
1553 &options);
1554 options.round_mode = RoundMode::HALF_TO_EVEN;
1555 CheckScalar(
1556 func, {values},
1557 ArrayFromJSON(
1558 ty,
1559 R"(["1.010", "1.010", "1.020", "1.020", "-1.010", "-1.010", "-1.020", "-1.020", null])"),
1560 &options);
1561 options.round_mode = RoundMode::HALF_TO_ODD;
1562 CheckScalar(
1563 func, {values},
1564 ArrayFromJSON(
1565 ty,
1566 R"(["1.010", "1.010", "1.010", "1.020", "-1.010", "-1.010", "-1.010", "-1.020", null])"),
1567 &options);
1568 }
1569 }
1570
TEST_F(TestUnaryArithmeticDecimal,RoundTowardsInfinity)1571 TEST_F(TestUnaryArithmeticDecimal, RoundTowardsInfinity) {
1572 const auto func = "round";
1573 RoundOptions options(0, RoundMode::TOWARDS_INFINITY);
1574 for (const auto& ty : {decimal128(4, 2), decimal256(4, 2)}) {
1575 auto values = ArrayFromJSON(
1576 ty, R"(["1.00", "1.99", "1.01", "-42.00", "-42.99", "-42.15", null])");
1577 CheckScalar(func, {ArrayFromJSON(ty, R"([])")}, ArrayFromJSON(ty, R"([])"), &options);
1578 options.ndigits = 0;
1579 CheckScalar(
1580 func, {values},
1581 ArrayFromJSON(ty,
1582 R"(["1.00", "2.00", "2.00", "-42.00", "-43.00", "-43.00", null])"),
1583 &options);
1584 options.ndigits = 1;
1585 CheckScalar(
1586 func, {values},
1587 ArrayFromJSON(ty,
1588 R"(["1.00", "2.00", "1.10", "-42.00", "-43.00", "-42.20", null])"),
1589 &options);
1590 options.ndigits = 2;
1591 CheckScalar(func, {values}, values, &options);
1592 options.ndigits = 4;
1593 CheckScalar(func, {values}, values, &options);
1594 options.ndigits = 100;
1595 CheckScalar(func, {values}, values, &options);
1596 options.ndigits = -1;
1597 CheckScalar(
1598 func, {values},
1599 ArrayFromJSON(
1600 ty, R"(["10.00", "10.00", "10.00", "-50.00", "-50.00", "-50.00", null])"),
1601 &options);
1602 options.ndigits = -2;
1603 CheckRaises(func, {values}, "Rounding to -2 digits will not fit in precision",
1604 &options);
1605 options.ndigits = -1;
1606 CheckRaises(func, {ArrayFromJSON(ty, R"(["99.99"])")},
1607 "Rounded value 100.00 does not fit in precision", &options);
1608 }
1609 for (const auto& ty : {decimal128(2, -2), decimal256(2, -2)}) {
1610 auto values = DecimalArrayFromJSON(
1611 ty, R"(["10E2", "12E2", "18E2", "-10E2", "-12E2", "-18E2", null])");
1612 options.ndigits = 0;
1613 CheckScalar(func, {values}, values, &options);
1614 options.ndigits = 2;
1615 CheckScalar(func, {values}, values, &options);
1616 options.ndigits = 100;
1617 CheckScalar(func, {values}, values, &options);
1618 options.ndigits = -1;
1619 CheckScalar(func, {values}, values, &options);
1620 options.ndigits = -2;
1621 CheckScalar(func, {values}, values, &options);
1622 options.ndigits = -3;
1623 CheckScalar(func, {values},
1624 DecimalArrayFromJSON(
1625 ty, R"(["10E2", "20E2", "20E2", "-10E2", "-20E2", "-20E2", null])"),
1626 &options);
1627 options.ndigits = -4;
1628 CheckRaises(func, {values}, "Rounding to -4 digits will not fit in precision",
1629 &options);
1630 }
1631 }
1632
TEST_F(TestUnaryArithmeticDecimal,RoundHalfToEven)1633 TEST_F(TestUnaryArithmeticDecimal, RoundHalfToEven) {
1634 const auto func = "round";
1635 RoundOptions options(0, RoundMode::HALF_TO_EVEN);
1636 for (const auto& ty : {decimal128(4, 2), decimal256(4, 2)}) {
1637 auto values = ArrayFromJSON(
1638 ty,
1639 R"(["1.00", "5.99", "1.01", "-42.00", "-42.99", "-42.15", "1.50", "2.50", "-5.50", "-2.55", null])");
1640 CheckScalar(func, {ArrayFromJSON(ty, R"([])")}, ArrayFromJSON(ty, R"([])"), &options);
1641 options.ndigits = 0;
1642 CheckScalar(
1643 func, {values},
1644 ArrayFromJSON(
1645 ty,
1646 R"(["1.00", "6.00", "1.00", "-42.00", "-43.00", "-42.00", "2.00", "2.00", "-6.00", "-3.00", null])"),
1647 &options);
1648 options.ndigits = 1;
1649 CheckScalar(
1650 func, {values},
1651 ArrayFromJSON(
1652 ty,
1653 R"(["1.00", "6.00", "1.00", "-42.00", "-43.00", "-42.20", "1.50", "2.50", "-5.50", "-2.60", null])"),
1654 &options);
1655 options.ndigits = 2;
1656 CheckScalar(func, {values}, values, &options);
1657 options.ndigits = 4;
1658 CheckScalar(func, {values}, values, &options);
1659 options.ndigits = 100;
1660 CheckScalar(func, {values}, values, &options);
1661 options.ndigits = -1;
1662 CheckScalar(
1663 func, {values},
1664 ArrayFromJSON(
1665 ty,
1666 R"(["0.00", "10.00", "0.00", "-40.00", "-40.00", "-40.00", "0.00", "0.00", "-10.00", "0.00", null])"),
1667 &options);
1668 options.ndigits = -2;
1669 CheckRaises(func, {values}, "Rounding to -2 digits will not fit in precision",
1670 &options);
1671 options.ndigits = -1;
1672 CheckRaises(func, {ArrayFromJSON(ty, R"(["99.99"])")},
1673 "Rounded value 100.00 does not fit in precision", &options);
1674 }
1675 for (const auto& ty : {decimal128(2, -2), decimal256(2, -2)}) {
1676 auto values = DecimalArrayFromJSON(
1677 ty,
1678 R"(["5E2", "10E2", "12E2", "15E2", "18E2", "-10E2", "-12E2", "-15E2", "-18E2", null])");
1679 options.ndigits = 0;
1680 CheckScalar(func, {values}, values, &options);
1681 options.ndigits = 2;
1682 CheckScalar(func, {values}, values, &options);
1683 options.ndigits = 100;
1684 CheckScalar(func, {values}, values, &options);
1685 options.ndigits = -1;
1686 CheckScalar(func, {values}, values, &options);
1687 options.ndigits = -2;
1688 CheckScalar(func, {values}, values, &options);
1689 options.ndigits = -3;
1690 CheckScalar(
1691 func, {values},
1692 DecimalArrayFromJSON(
1693 ty,
1694 R"(["0", "10E2", "10E2", "20E2", "20E2", "-10E2", "-10E2", "-20E2", "-20E2", null])"),
1695 &options);
1696 options.ndigits = -4;
1697 CheckRaises(func, {values}, "Rounding to -4 digits will not fit in precision",
1698 &options);
1699 }
1700 }
1701
TEST_F(TestUnaryArithmeticDecimal,RoundCeil)1702 TEST_F(TestUnaryArithmeticDecimal, RoundCeil) {
1703 const auto func = "ceil";
1704 for (const auto& ty : PositiveScaleTypes()) {
1705 CheckScalar(func, {ArrayFromJSON(ty, R"([])")}, ArrayFromJSON(ty, R"([])"));
1706 CheckScalar(
1707 func,
1708 {ArrayFromJSON(
1709 ty, R"(["1.00", "1.99", "1.01", "-42.00", "-42.99", "-42.15", null])")},
1710 ArrayFromJSON(ty,
1711 R"(["1.00", "2.00", "2.00", "-42.00", "-42.00", "-42.00", null])"));
1712 }
1713 for (const auto& ty : {decimal128(4, 2), decimal256(4, 2)}) {
1714 CheckRaises(func, {ScalarFromJSON(ty, R"("99.99")")},
1715 "Rounded value 100.00 does not fit in precision of decimal");
1716 CheckScalar(func, {ScalarFromJSON(ty, R"("-99.99")")},
1717 ScalarFromJSON(ty, R"("-99.00")"));
1718 }
1719 for (const auto& ty : NegativeScaleTypes()) {
1720 CheckScalar(func, {ArrayFromJSON(ty, R"([])")}, ArrayFromJSON(ty, R"([])"));
1721 CheckScalar(func, {DecimalArrayFromJSON(ty, R"(["12E2", "-42E2", null])")},
1722 DecimalArrayFromJSON(ty, R"(["12E2", "-42E2", null])"));
1723 }
1724 }
1725
TEST_F(TestUnaryArithmeticDecimal,RoundFloor)1726 TEST_F(TestUnaryArithmeticDecimal, RoundFloor) {
1727 const auto func = "floor";
1728 for (const auto& ty : PositiveScaleTypes()) {
1729 CheckScalar(func, {ArrayFromJSON(ty, R"([])")}, ArrayFromJSON(ty, R"([])"));
1730 CheckScalar(
1731 func,
1732 {ArrayFromJSON(
1733 ty, R"(["1.00", "1.99", "1.01", "-42.00", "-42.99", "-42.15", null])")},
1734 ArrayFromJSON(ty,
1735 R"(["1.00", "1.00", "1.00", "-42.00", "-43.00", "-43.00", null])"));
1736 }
1737 for (const auto& ty : {decimal128(4, 2), decimal256(4, 2)}) {
1738 CheckScalar(func, {ScalarFromJSON(ty, R"("99.99")")},
1739 ScalarFromJSON(ty, R"("99.00")"));
1740 CheckRaises(func, {ScalarFromJSON(ty, R"("-99.99")")},
1741 "Rounded value -100.00 does not fit in precision of decimal");
1742 }
1743 for (const auto& ty : NegativeScaleTypes()) {
1744 CheckScalar(func, {ArrayFromJSON(ty, R"([])")}, ArrayFromJSON(ty, R"([])"));
1745 CheckScalar(func, {DecimalArrayFromJSON(ty, R"(["12E2", "-42E2", null])")},
1746 DecimalArrayFromJSON(ty, R"(["12E2", "-42E2", null])"));
1747 }
1748 }
1749
TEST_F(TestUnaryArithmeticDecimal,RoundTrunc)1750 TEST_F(TestUnaryArithmeticDecimal, RoundTrunc) {
1751 const auto func = "trunc";
1752 for (const auto& ty : PositiveScaleTypes()) {
1753 CheckScalar(func, {ArrayFromJSON(ty, R"([])")}, ArrayFromJSON(ty, R"([])"));
1754 CheckScalar(
1755 func,
1756 {ArrayFromJSON(
1757 ty, R"(["1.00", "1.99", "1.01", "-42.00", "-42.99", "-42.15", null])")},
1758 ArrayFromJSON(ty,
1759 R"(["1.00", "1.00", "1.00", "-42.00", "-42.00", "-42.00", null])"));
1760 }
1761 for (const auto& ty : {decimal128(4, 2), decimal256(4, 2)}) {
1762 CheckScalar(func, {ScalarFromJSON(ty, R"("99.99")")},
1763 ScalarFromJSON(ty, R"("99.00")"));
1764 CheckScalar(func, {ScalarFromJSON(ty, R"("-99.99")")},
1765 ScalarFromJSON(ty, R"("-99.00")"));
1766 }
1767 for (const auto& ty : NegativeScaleTypes()) {
1768 CheckScalar(func, {ArrayFromJSON(ty, R"([])")}, ArrayFromJSON(ty, R"([])"));
1769 CheckScalar(func, {DecimalArrayFromJSON(ty, R"(["12E2", "-42E2", null])")},
1770 DecimalArrayFromJSON(ty, R"(["12E2", "-42E2", null])"));
1771 }
1772 }
1773
TEST_F(TestUnaryArithmeticDecimal,RoundToMultiple)1774 TEST_F(TestUnaryArithmeticDecimal, RoundToMultiple) {
1775 const auto func = "round_to_multiple";
1776 RoundToMultipleOptions options(0, RoundMode::DOWN);
1777 for (const auto& ty : {decimal128(4, 2), decimal256(4, 2)}) {
1778 if (ty->id() == Type::DECIMAL128) {
1779 options.multiple = std::make_shared<Decimal128Scalar>(Decimal128(200), ty);
1780 } else {
1781 options.multiple = std::make_shared<Decimal256Scalar>(Decimal256(200), ty);
1782 }
1783 auto values = ArrayFromJSON(
1784 ty,
1785 R"(["-3.50", "-3.00", "-2.50", "-2.00", "-1.50", "-1.00", "-0.50", "0.00",
1786 "0.50", "1.00", "1.50", "2.00", "2.50", "3.00", "3.50", null])");
1787 options.round_mode = RoundMode::DOWN;
1788 CheckScalar(
1789 func, {values},
1790 ArrayFromJSON(
1791 ty,
1792 R"(["-4.00", "-4.00", "-4.00", "-2.00", "-2.00", "-2.00", "-2.00", "0.00",
1793 "0.00", "0.00", "0.00", "2.00", "2.00", "2.00", "2.00", null])"),
1794 &options);
1795 options.round_mode = RoundMode::UP;
1796 CheckScalar(
1797 func, {values},
1798 ArrayFromJSON(
1799 ty,
1800 R"(["-2.00", "-2.00", "-2.00", "-2.00", "-0.00", "-0.00", "-0.00", "0.00",
1801 "2.00", "2.00", "2.00", "2.00", "4.00", "4.00", "4.00", null])"),
1802 &options);
1803 options.round_mode = RoundMode::TOWARDS_ZERO;
1804 CheckScalar(
1805 func, {values},
1806 ArrayFromJSON(
1807 ty,
1808 R"(["-2.00", "-2.00", "-2.00", "-2.00", "-0.00", "-0.00", "-0.00", "0.00",
1809 "0.00", "0.00", "0.00", "2.00", "2.00", "2.00", "2.00", null])"),
1810 &options);
1811 options.round_mode = RoundMode::TOWARDS_INFINITY;
1812 CheckScalar(
1813 func, {values},
1814 ArrayFromJSON(
1815 ty,
1816 R"(["-4.00", "-4.00", "-4.00", "-2.00", "-2.00", "-2.00", "-2.00", "0.00",
1817 "2.00", "2.00", "2.00", "2.00", "4.00", "4.00", "4.00", null])"),
1818 &options);
1819 options.round_mode = RoundMode::HALF_DOWN;
1820 CheckScalar(
1821 func, {values},
1822 ArrayFromJSON(
1823 ty,
1824 R"(["-4.00", "-4.00", "-2.00", "-2.00", "-2.00", "-2.00", "-0.00", "0.00",
1825 "0.00", "0.00", "2.00", "2.00", "2.00", "2.00", "4.00", null])"),
1826 &options);
1827 options.round_mode = RoundMode::HALF_UP;
1828 CheckScalar(
1829 func, {values},
1830 ArrayFromJSON(
1831 ty,
1832 R"(["-4.00", "-2.00", "-2.00", "-2.00", "-2.00", "-0.00", "-0.00", "0.00",
1833 "0.00", "2.00", "2.00", "2.00", "2.00", "4.00", "4.00", null])"),
1834 &options);
1835 options.round_mode = RoundMode::HALF_TOWARDS_ZERO;
1836 CheckScalar(
1837 func, {values},
1838 ArrayFromJSON(
1839 ty,
1840 R"(["-4.00", "-2.00", "-2.00", "-2.00", "-2.00", "-0.00", "-0.00", "0.00",
1841 "0.00", "0.00", "2.00", "2.00", "2.00", "2.00", "4.00", null])"),
1842 &options);
1843 options.round_mode = RoundMode::HALF_TOWARDS_INFINITY;
1844 CheckScalar(
1845 func, {values},
1846 ArrayFromJSON(
1847 ty,
1848 R"(["-4.00", "-4.00", "-2.00", "-2.00", "-2.00", "-2.00", "-0.00", "0.00",
1849 "0.00", "2.00", "2.00", "2.00", "2.00", "4.00", "4.00", null])"),
1850 &options);
1851 options.round_mode = RoundMode::HALF_TO_EVEN;
1852 CheckScalar(
1853 func, {values},
1854 ArrayFromJSON(
1855 ty,
1856 R"(["-4.00", "-4.00", "-2.00", "-2.00", "-2.00", "-0.00", "-0.00", "0.00",
1857 "0.00", "0.00", "2.00", "2.00", "2.00", "4.00", "4.00", null])"),
1858 &options);
1859 options.round_mode = RoundMode::HALF_TO_ODD;
1860 CheckScalar(
1861 func, {values},
1862 ArrayFromJSON(
1863 ty,
1864 R"(["-4.00", "-2.00", "-2.00", "-2.00", "-2.00", "-2.00", "-0.00", "0.00",
1865 "0.00", "2.00", "2.00", "2.00", "2.00", "2.00", "4.00", null])"),
1866 &options);
1867 }
1868 }
1869
TEST_F(TestUnaryArithmeticDecimal,RoundToMultipleTowardsInfinity)1870 TEST_F(TestUnaryArithmeticDecimal, RoundToMultipleTowardsInfinity) {
1871 const auto func = "round_to_multiple";
1872 RoundToMultipleOptions options(0, RoundMode::TOWARDS_INFINITY);
1873 auto set_multiple = [&](const std::shared_ptr<DataType>& ty, int64_t value) {
1874 if (ty->id() == Type::DECIMAL128) {
1875 options.multiple = std::make_shared<Decimal128Scalar>(Decimal128(value), ty);
1876 } else {
1877 options.multiple = std::make_shared<Decimal256Scalar>(Decimal256(value), ty);
1878 }
1879 };
1880 for (const auto& ty : {decimal128(4, 2), decimal256(4, 2)}) {
1881 auto values = ArrayFromJSON(
1882 ty, R"(["1.00", "1.99", "1.01", "-42.00", "-42.99", "-42.15", null])");
1883 set_multiple(ty, 25);
1884 CheckScalar(func, {ArrayFromJSON(ty, R"([])")}, ArrayFromJSON(ty, R"([])"), &options);
1885 CheckScalar(
1886 func, {values},
1887 ArrayFromJSON(ty,
1888 R"(["1.00", "2.00", "1.25", "-42.00", "-43.00", "-42.25", null])"),
1889 &options);
1890 set_multiple(ty, 1);
1891 CheckScalar(func, {values}, values, &options);
1892 set_multiple(ty, 0);
1893 CheckRaises(func, {ArrayFromJSON(ty, R"(["99.99"])")},
1894 "Rounding multiple must be positive", &options);
1895 set_multiple(ty, -10);
1896 CheckRaises(func, {ArrayFromJSON(ty, R"(["99.99"])")},
1897 "Rounding multiple must be positive", &options);
1898 set_multiple(ty, 100);
1899 CheckRaises(func, {ArrayFromJSON(ty, R"(["99.99"])")},
1900 "Rounded value 100.00 does not fit in precision", &options);
1901 options.multiple = std::make_shared<DoubleScalar>(1.0);
1902 CheckRaises(func, {ArrayFromJSON(ty, R"(["99.99"])")}, "scalar, not double",
1903 &options);
1904 options.multiple =
1905 std::make_shared<Decimal128Scalar>(Decimal128(0), decimal128(3, 0));
1906 CheckRaises(func, {ArrayFromJSON(ty, R"(["99.99"])")}, "scalar, not decimal128(3, 0)",
1907 &options);
1908 options.multiple = std::make_shared<Decimal128Scalar>(decimal128(3, 0));
1909 CheckRaises(func, {ArrayFromJSON(ty, R"(["99.99"])")},
1910 "Rounding multiple must be non-null and valid", &options);
1911 options.multiple = nullptr;
1912 CheckRaises(func, {ArrayFromJSON(ty, R"(["99.99"])")},
1913 "Rounding multiple must be non-null and valid", &options);
1914 }
1915 for (const auto& ty : {decimal128(2, -2), decimal256(2, -2)}) {
1916 auto values = DecimalArrayFromJSON(
1917 ty, R"(["10E2", "12E2", "18E2", "-10E2", "-12E2", "-18E2", null])");
1918 set_multiple(ty, 4);
1919 CheckScalar(func, {values},
1920 DecimalArrayFromJSON(
1921 ty, R"(["12E2", "12E2", "20E2", "-12E2", "-12E2", "-20E2", null])"),
1922 &options);
1923 set_multiple(ty, 1);
1924 CheckScalar(func, {values}, values, &options);
1925 }
1926 }
1927
TEST_F(TestUnaryArithmeticDecimal,RoundToMultipleHalfToOdd)1928 TEST_F(TestUnaryArithmeticDecimal, RoundToMultipleHalfToOdd) {
1929 const auto func = "round_to_multiple";
1930 RoundToMultipleOptions options(0, RoundMode::HALF_TO_ODD);
1931 auto set_multiple = [&](const std::shared_ptr<DataType>& ty, int64_t value) {
1932 if (ty->id() == Type::DECIMAL128) {
1933 options.multiple = std::make_shared<Decimal128Scalar>(Decimal128(value), ty);
1934 } else {
1935 options.multiple = std::make_shared<Decimal256Scalar>(Decimal256(value), ty);
1936 }
1937 };
1938 for (const auto& ty : {decimal128(4, 2), decimal256(4, 2)}) {
1939 auto values =
1940 ArrayFromJSON(ty, R"(["-0.38", "-0.37", "-0.25", "-0.13", "-0.12", "0.00",
1941 "0.12", "0.13", "0.25", "0.37", "0.38", null])");
1942 // There is no exact halfway point, check what happens
1943 set_multiple(ty, 25);
1944 CheckScalar(func, {ArrayFromJSON(ty, R"([])")}, ArrayFromJSON(ty, R"([])"), &options);
1945 CheckScalar(func, {values},
1946 ArrayFromJSON(ty, R"(["-0.50", "-0.25", "-0.25", "-0.25", "-0.00", "0.00",
1947 "0.00", "0.25", "0.25", "0.25", "0.50", null])"),
1948 &options);
1949 set_multiple(ty, 1);
1950 CheckScalar(func, {values}, values, &options);
1951 set_multiple(ty, 24);
1952 CheckScalar(func, {ArrayFromJSON(ty, R"([])")}, ArrayFromJSON(ty, R"([])"), &options);
1953 CheckScalar(func, {values},
1954 ArrayFromJSON(ty, R"(["-0.48", "-0.48", "-0.24", "-0.24", "-0.24", "0.00",
1955 "0.24", "0.24", "0.24", "0.48", "0.48", null])"),
1956 &options);
1957 }
1958 for (const auto& ty : {decimal128(2, -2), decimal256(2, -2)}) {
1959 auto values = DecimalArrayFromJSON(
1960 ty, R"(["10E2", "12E2", "18E2", "-10E2", "-12E2", "-18E2", null])");
1961 set_multiple(ty, 4);
1962 CheckScalar(func, {values},
1963 DecimalArrayFromJSON(
1964 ty, R"(["12E2", "12E2", "20E2", "-12E2", "-12E2", "-20E2", null])"),
1965 &options);
1966 set_multiple(ty, 5);
1967 CheckScalar(func, {values},
1968 DecimalArrayFromJSON(
1969 ty, R"(["10E2", "10E2", "20E2", "-10E2", "-10E2", "-20E2", null])"),
1970 &options);
1971 set_multiple(ty, 1);
1972 CheckScalar(func, {values}, values, &options);
1973 }
1974 }
1975
1976 TYPED_TEST_SUITE(TestUnaryRoundIntegral, IntegralTypes);
1977 TYPED_TEST_SUITE(TestUnaryRoundSigned, SignedIntegerTypes);
1978 TYPED_TEST_SUITE(TestUnaryRoundUnsigned, UnsignedIntegerTypes);
1979 TYPED_TEST_SUITE(TestUnaryRoundFloating, FloatingTypes);
1980
1981 const std::vector<RoundMode> kRoundModes{
1982 RoundMode::DOWN,
1983 RoundMode::UP,
1984 RoundMode::TOWARDS_ZERO,
1985 RoundMode::TOWARDS_INFINITY,
1986 RoundMode::HALF_DOWN,
1987 RoundMode::HALF_UP,
1988 RoundMode::HALF_TOWARDS_ZERO,
1989 RoundMode::HALF_TOWARDS_INFINITY,
1990 RoundMode::HALF_TO_EVEN,
1991 RoundMode::HALF_TO_ODD,
1992 };
1993
TYPED_TEST(TestUnaryRoundSigned,Round)1994 TYPED_TEST(TestUnaryRoundSigned, Round) {
1995 // Test different rounding modes for integer rounding
1996 std::string values("[0, 1, -13, -50, 115]");
1997 this->SetRoundNdigits(0);
1998 for (const auto& round_mode : kRoundModes) {
1999 this->SetRoundMode(round_mode);
2000 this->AssertUnaryOp(Round, values, ArrayFromJSON(float64(), values));
2001 }
2002
2003 // Test different round N-digits for nearest rounding mode
2004 std::vector<std::pair<int64_t, std::string>> ndigits_and_expected{{
2005 {-2, "[0, 0, -0, -100, 100]"},
2006 {-1, "[0, 0, -10, -50, 120]"},
2007 {0, values},
2008 {1, values},
2009 {2, values},
2010 }};
2011 this->SetRoundMode(RoundMode::HALF_TOWARDS_INFINITY);
2012 for (const auto& pair : ndigits_and_expected) {
2013 this->SetRoundNdigits(pair.first);
2014 this->AssertUnaryOp(Round, values, ArrayFromJSON(float64(), pair.second));
2015 }
2016 }
2017
TYPED_TEST(TestUnaryRoundUnsigned,Round)2018 TYPED_TEST(TestUnaryRoundUnsigned, Round) {
2019 // Test different rounding modes for integer rounding
2020 std::string values("[0, 1, 13, 50, 115]");
2021 this->SetRoundNdigits(0);
2022 for (const auto& round_mode : kRoundModes) {
2023 this->SetRoundMode(round_mode);
2024 this->AssertUnaryOp(Round, values, ArrayFromJSON(float64(), values));
2025 }
2026
2027 // Test different round N-digits for nearest rounding mode
2028 std::vector<std::pair<int64_t, std::string>> ndigits_and_expected{{
2029 {-2, "[0, 0, 0, 100, 100]"},
2030 {-1, "[0, 0, 10, 50, 120]"},
2031 {0, values},
2032 {1, values},
2033 {2, values},
2034 }};
2035 this->SetRoundMode(RoundMode::HALF_TOWARDS_INFINITY);
2036 for (const auto& pair : ndigits_and_expected) {
2037 this->SetRoundNdigits(pair.first);
2038 this->AssertUnaryOp(Round, values, ArrayFromJSON(float64(), pair.second));
2039 }
2040 }
2041
TYPED_TEST(TestUnaryRoundFloating,Round)2042 TYPED_TEST(TestUnaryRoundFloating, Round) {
2043 this->SetNansEqual(true);
2044
2045 // Test different rounding modes
2046 std::string values("[3.2, 3.5, 3.7, 4.5, -3.2, -3.5, -3.7]");
2047 std::vector<std::pair<RoundMode, std::string>> rmode_and_expected{{
2048 {RoundMode::DOWN, "[3, 3, 3, 4, -4, -4, -4]"},
2049 {RoundMode::UP, "[4, 4, 4, 5, -3, -3, -3]"},
2050 {RoundMode::TOWARDS_ZERO, "[3, 3, 3, 4, -3, -3, -3]"},
2051 {RoundMode::TOWARDS_INFINITY, "[4, 4, 4, 5, -4, -4, -4]"},
2052 {RoundMode::HALF_DOWN, "[3, 3, 4, 4, -3, -4, -4]"},
2053 {RoundMode::HALF_UP, "[3, 4, 4, 5, -3, -3, -4]"},
2054 {RoundMode::HALF_TOWARDS_ZERO, "[3, 3, 4, 4, -3, -3, -4]"},
2055 {RoundMode::HALF_TOWARDS_INFINITY, "[3, 4, 4, 5, -3, -4, -4]"},
2056 {RoundMode::HALF_TO_EVEN, "[3, 4, 4, 4, -3, -4, -4]"},
2057 {RoundMode::HALF_TO_ODD, "[3, 3, 4, 5, -3, -3, -4]"},
2058 }};
2059 this->SetRoundNdigits(0);
2060 for (const auto& pair : rmode_and_expected) {
2061 this->SetRoundMode(pair.first);
2062 this->AssertUnaryOp(Round, "[]", "[]");
2063 this->AssertUnaryOp(Round, "[null, 0, Inf, -Inf, NaN, -NaN]",
2064 "[null, 0, Inf, -Inf, NaN, -NaN]");
2065 this->AssertUnaryOp(Round, values, pair.second);
2066 }
2067
2068 // Test different round N-digits for nearest rounding mode
2069 values = "[320, 3.5, 3.075, 4.5, -3.212, -35.1234, -3.045]";
2070 std::vector<std::pair<int64_t, std::string>> ndigits_and_expected{{
2071 {-2, "[300, 0, 0, 0, -0, -0, -0]"},
2072 {-1, "[320, 0, 0, 0, -0, -40, -0]"},
2073 {0, "[320, 4, 3, 5, -3, -35, -3]"},
2074 {1, "[320, 3.5, 3.1, 4.5, -3.2, -35.1, -3]"},
2075 {2, "[320, 3.5, 3.08, 4.5, -3.21, -35.12, -3.05]"},
2076 }};
2077 this->SetRoundMode(RoundMode::HALF_TOWARDS_INFINITY);
2078 for (const auto& pair : ndigits_and_expected) {
2079 this->SetRoundNdigits(pair.first);
2080 this->AssertUnaryOp(Round, values, pair.second);
2081 }
2082 }
2083
2084 TYPED_TEST_SUITE(TestUnaryRoundToMultipleIntegral, IntegralTypes);
2085 TYPED_TEST_SUITE(TestUnaryRoundToMultipleSigned, SignedIntegerTypes);
2086 TYPED_TEST_SUITE(TestUnaryRoundToMultipleUnsigned, UnsignedIntegerTypes);
2087 TYPED_TEST_SUITE(TestUnaryRoundToMultipleFloating, FloatingTypes);
2088
TYPED_TEST(TestUnaryRoundToMultipleSigned,RoundToMultiple)2089 TYPED_TEST(TestUnaryRoundToMultipleSigned, RoundToMultiple) {
2090 // Test different rounding modes for integer rounding
2091 std::string values("[0, 1, -13, -50, 115]");
2092 this->SetRoundMultiple(1);
2093 for (const auto& round_mode : kRoundModes) {
2094 this->SetRoundMode(round_mode);
2095 this->AssertUnaryOp(RoundToMultiple, values, ArrayFromJSON(float64(), values));
2096 }
2097
2098 // Test different round multiples for nearest rounding mode
2099 std::vector<std::pair<double, std::string>> multiple_and_expected{{
2100 {2, "[0, 2, -14, -50, 116]"},
2101 {0.05, "[0, 1, -13, -50, 115]"},
2102 {0.1, values},
2103 {10, "[0, 0, -10, -50, 120]"},
2104 {100, "[0, 0, -0, -100, 100]"},
2105 }};
2106 this->SetRoundMode(RoundMode::HALF_TOWARDS_INFINITY);
2107 for (const auto& pair : multiple_and_expected) {
2108 this->SetRoundMultiple(pair.first);
2109 this->AssertUnaryOp(RoundToMultiple, values, ArrayFromJSON(float64(), pair.second));
2110 }
2111 }
2112
TYPED_TEST(TestUnaryRoundToMultipleUnsigned,RoundToMultiple)2113 TYPED_TEST(TestUnaryRoundToMultipleUnsigned, RoundToMultiple) {
2114 // Test different rounding modes for integer rounding
2115 std::string values("[0, 1, 13, 50, 115]");
2116 this->SetRoundMultiple(1);
2117 for (const auto& round_mode : kRoundModes) {
2118 this->SetRoundMode(round_mode);
2119 this->AssertUnaryOp(RoundToMultiple, values, ArrayFromJSON(float64(), values));
2120 }
2121
2122 // Test different round multiples for nearest rounding mode
2123 std::vector<std::pair<double, std::string>> multiple_and_expected{{
2124 {2, "[0, 2, 14, 50, 116]"},
2125 {0.05, "[0, 1, 13, 50, 115]"},
2126 {0.1, values},
2127 {10, "[0, 0, 10, 50, 120]"},
2128 {100, "[0, 0, 0, 100, 100]"},
2129 }};
2130 this->SetRoundMode(RoundMode::HALF_TOWARDS_INFINITY);
2131 for (const auto& pair : multiple_and_expected) {
2132 this->SetRoundMultiple(pair.first);
2133 this->AssertUnaryOp(RoundToMultiple, values, ArrayFromJSON(float64(), pair.second));
2134 }
2135 }
2136
TYPED_TEST(TestUnaryRoundToMultipleFloating,RoundToMultiple)2137 TYPED_TEST(TestUnaryRoundToMultipleFloating, RoundToMultiple) {
2138 this->SetNansEqual(true);
2139
2140 // Test different rounding modes for integer rounding
2141 std::string values("[3.2, 3.5, 3.7, 4.5, -3.2, -3.5, -3.7]");
2142 std::vector<std::pair<RoundMode, std::string>> rmode_and_expected{{
2143 {RoundMode::DOWN, "[3, 3, 3, 4, -4, -4, -4]"},
2144 {RoundMode::UP, "[4, 4, 4, 5, -3, -3, -3]"},
2145 {RoundMode::TOWARDS_ZERO, "[3, 3, 3, 4, -3, -3, -3]"},
2146 {RoundMode::TOWARDS_INFINITY, "[4, 4, 4, 5, -4, -4, -4]"},
2147 {RoundMode::HALF_DOWN, "[3, 3, 4, 4, -3, -4, -4]"},
2148 {RoundMode::HALF_UP, "[3, 4, 4, 5, -3, -3, -4]"},
2149 {RoundMode::HALF_TOWARDS_ZERO, "[3, 3, 4, 4, -3, -3, -4]"},
2150 {RoundMode::HALF_TOWARDS_INFINITY, "[3, 4, 4, 5, -3, -4, -4]"},
2151 {RoundMode::HALF_TO_EVEN, "[3, 4, 4, 4, -3, -4, -4]"},
2152 {RoundMode::HALF_TO_ODD, "[3, 3, 4, 5, -3, -3, -4]"},
2153 }};
2154 this->SetRoundMultiple(1);
2155 for (const auto& pair : rmode_and_expected) {
2156 this->SetRoundMode(pair.first);
2157 this->AssertUnaryOp(RoundToMultiple, "[]", "[]");
2158 this->AssertUnaryOp(RoundToMultiple, "[null, 0, Inf, -Inf, NaN, -NaN]",
2159 "[null, 0, Inf, -Inf, NaN, -NaN]");
2160 this->AssertUnaryOp(RoundToMultiple, values, pair.second);
2161 }
2162
2163 // Test different round multiples for nearest rounding mode
2164 values = "[320, 3.5, 3.075, 4.5, -3.212, -35.1234, -3.045]";
2165 std::vector<std::pair<double, std::string>> multiple_and_expected{{
2166 {2, "[320, 4, 4, 4, -4, -36, -4]"},
2167 {0.05, "[320, 3.5, 3.1, 4.5, -3.2, -35.1, -3.05]"},
2168 {0.1, "[320, 3.5, 3.1, 4.5, -3.2, -35.1, -3]"},
2169 {10, "[320, 0, 0, 0, -0, -40, -0]"},
2170 {100, "[300, 0, 0, 0, -0, -0, -0]"},
2171 }};
2172 this->SetRoundMode(RoundMode::HALF_TOWARDS_INFINITY);
2173 for (const auto& pair : multiple_and_expected) {
2174 this->SetRoundMultiple(pair.first);
2175 this->AssertUnaryOp(RoundToMultiple, values, pair.second);
2176 }
2177
2178 this->SetRoundMultiple(-2);
2179 this->AssertUnaryOpRaises(RoundToMultiple, values, "multiple must be positive");
2180 }
2181
TEST(TestBinaryDecimalArithmetic,DispatchBest)2182 TEST(TestBinaryDecimalArithmetic, DispatchBest) {
2183 // decimal, floating point
2184 for (std::string name : {"add", "subtract", "multiply", "divide"}) {
2185 for (std::string suffix : {"", "_checked"}) {
2186 name += suffix;
2187
2188 CheckDispatchBest(name, {decimal128(1, 0), float32()}, {float32(), float32()});
2189 CheckDispatchBest(name, {decimal256(1, 0), float64()}, {float64(), float64()});
2190 CheckDispatchBest(name, {float32(), decimal256(1, 0)}, {float32(), float32()});
2191 CheckDispatchBest(name, {float64(), decimal128(1, 0)}, {float64(), float64()});
2192 }
2193 }
2194
2195 // decimal, decimal -> decimal
2196 // decimal, integer -> decimal
2197 for (std::string name : {"add", "subtract"}) {
2198 for (std::string suffix : {"", "_checked"}) {
2199 name += suffix;
2200
2201 CheckDispatchBest(name, {int64(), decimal128(1, 0)},
2202 {decimal128(19, 0), decimal128(1, 0)});
2203 CheckDispatchBest(name, {decimal128(1, 0), int64()},
2204 {decimal128(1, 0), decimal128(19, 0)});
2205
2206 CheckDispatchBest(name, {decimal128(2, 1), decimal128(2, 1)},
2207 {decimal128(2, 1), decimal128(2, 1)});
2208 CheckDispatchBest(name, {decimal256(2, 1), decimal256(2, 1)},
2209 {decimal256(2, 1), decimal256(2, 1)});
2210 CheckDispatchBest(name, {decimal128(2, 1), decimal256(2, 1)},
2211 {decimal256(2, 1), decimal256(2, 1)});
2212 CheckDispatchBest(name, {decimal256(2, 1), decimal128(2, 1)},
2213 {decimal256(2, 1), decimal256(2, 1)});
2214
2215 CheckDispatchBest(name, {decimal128(2, 0), decimal128(2, 1)},
2216 {decimal128(3, 1), decimal128(2, 1)});
2217 CheckDispatchBest(name, {decimal128(2, 1), decimal128(2, 0)},
2218 {decimal128(2, 1), decimal128(3, 1)});
2219 }
2220 }
2221 {
2222 std::string name = "multiply";
2223 for (std::string suffix : {"", "_checked"}) {
2224 name += suffix;
2225
2226 CheckDispatchBest(name, {int64(), decimal128(1, 0)},
2227 {decimal128(19, 0), decimal128(1, 0)});
2228 CheckDispatchBest(name, {decimal128(1, 0), int64()},
2229 {decimal128(1, 0), decimal128(19, 0)});
2230
2231 CheckDispatchBest(name, {decimal128(2, 1), decimal128(2, 1)},
2232 {decimal128(2, 1), decimal128(2, 1)});
2233 CheckDispatchBest(name, {decimal256(2, 1), decimal256(2, 1)},
2234 {decimal256(2, 1), decimal256(2, 1)});
2235 CheckDispatchBest(name, {decimal128(2, 1), decimal256(2, 1)},
2236 {decimal256(2, 1), decimal256(2, 1)});
2237 CheckDispatchBest(name, {decimal256(2, 1), decimal128(2, 1)},
2238 {decimal256(2, 1), decimal256(2, 1)});
2239
2240 CheckDispatchBest(name, {decimal128(2, 0), decimal128(2, 1)},
2241 {decimal128(2, 0), decimal128(2, 1)});
2242 CheckDispatchBest(name, {decimal128(2, 1), decimal128(2, 0)},
2243 {decimal128(2, 1), decimal128(2, 0)});
2244 }
2245 }
2246 {
2247 std::string name = "divide";
2248 for (std::string suffix : {"", "_checked"}) {
2249 name += suffix;
2250 SCOPED_TRACE(name);
2251
2252 CheckDispatchBest(name, {int64(), decimal128(1, 0)},
2253 {decimal128(23, 4), decimal128(1, 0)});
2254 CheckDispatchBest(name, {decimal128(1, 0), int64()},
2255 {decimal128(21, 20), decimal128(19, 0)});
2256
2257 CheckDispatchBest(name, {decimal128(2, 1), decimal128(2, 1)},
2258 {decimal128(6, 5), decimal128(2, 1)});
2259 CheckDispatchBest(name, {decimal256(2, 1), decimal256(2, 1)},
2260 {decimal256(6, 5), decimal256(2, 1)});
2261 CheckDispatchBest(name, {decimal128(2, 1), decimal256(2, 1)},
2262 {decimal256(6, 5), decimal256(2, 1)});
2263 CheckDispatchBest(name, {decimal256(2, 1), decimal128(2, 1)},
2264 {decimal256(6, 5), decimal256(2, 1)});
2265
2266 CheckDispatchBest(name, {decimal128(2, 0), decimal128(2, 1)},
2267 {decimal128(7, 5), decimal128(2, 1)});
2268 CheckDispatchBest(name, {decimal128(2, 1), decimal128(2, 0)},
2269 {decimal128(5, 4), decimal128(2, 0)});
2270 }
2271 }
2272 }
2273
2274 // reference result from bc (precsion=100, scale=40)
TEST(TestBinaryArithmeticDecimal,AddSubtract)2275 TEST(TestBinaryArithmeticDecimal, AddSubtract) {
2276 // array array, decimal128
2277 {
2278 auto left = ArrayFromJSON(decimal128(30, 3),
2279 R"([
2280 "1.000",
2281 "-123456789012345678901234567.890",
2282 "98765432109876543210.987",
2283 "-999999999999999999999999999.999"
2284 ])");
2285 auto right = ArrayFromJSON(decimal128(20, 9),
2286 R"([
2287 "-1.000000000",
2288 "12345678901.234567890",
2289 "98765.432101234",
2290 "-99999999999.999999999"
2291 ])");
2292 auto added = ArrayFromJSON(decimal128(37, 9),
2293 R"([
2294 "0.000000000",
2295 "-123456789012345666555555666.655432110",
2296 "98765432109876641976.419101234",
2297 "-1000000000000000099999999999.998999999"
2298 ])");
2299 auto subtracted = ArrayFromJSON(decimal128(37, 9),
2300 R"([
2301 "2.000000000",
2302 "-123456789012345691246913469.124567890",
2303 "98765432109876444445.554898766",
2304 "-999999999999999899999999999.999000001"
2305 ])");
2306 CheckScalarBinary("add", left, right, added);
2307 CheckScalarBinary("subtract", left, right, subtracted);
2308 }
2309
2310 // array array, decimal256
2311 {
2312 auto left = ArrayFromJSON(decimal256(30, 20),
2313 R"([
2314 "-1.00000000000000000001",
2315 "1234567890.12345678900000000000",
2316 "-9876543210.09876543210987654321",
2317 "9999999999.99999999999999999999"
2318 ])");
2319 auto right = ArrayFromJSON(decimal256(30, 10),
2320 R"([
2321 "1.0000000000",
2322 "-1234567890.1234567890",
2323 "6789.5432101234",
2324 "99999999999999999999.9999999999"
2325 ])");
2326 auto added = ArrayFromJSON(decimal256(41, 20),
2327 R"([
2328 "-0.00000000000000000001",
2329 "0.00000000000000000000",
2330 "-9876536420.55555530870987654321",
2331 "100000000009999999999.99999999989999999999"
2332 ])");
2333 auto subtracted = ArrayFromJSON(decimal256(41, 20),
2334 R"([
2335 "-2.00000000000000000001",
2336 "2469135780.24691357800000000000",
2337 "-9876549999.64197555550987654321",
2338 "-99999999989999999999.99999999990000000001"
2339 ])");
2340 CheckScalarBinary("add", left, right, added);
2341 CheckScalarBinary("subtract", left, right, subtracted);
2342 }
2343
2344 // scalar array
2345 {
2346 auto left = ScalarFromJSON(decimal128(6, 1), R"("12345.6")");
2347 auto right = ArrayFromJSON(decimal128(10, 3),
2348 R"(["1.234", "1234.000", "-9876.543", "666.888"])");
2349 auto added = ArrayFromJSON(decimal128(11, 3),
2350 R"(["12346.834", "13579.600", "2469.057", "13012.488"])");
2351 auto left_sub_right = ArrayFromJSON(
2352 decimal128(11, 3), R"(["12344.366", "11111.600", "22222.143", "11678.712"])");
2353 auto right_sub_left = ArrayFromJSON(
2354 decimal128(11, 3), R"(["-12344.366", "-11111.600", "-22222.143", "-11678.712"])");
2355 CheckScalarBinary("add", left, right, added);
2356 CheckScalarBinary("add", right, left, added);
2357 CheckScalarBinary("subtract", left, right, left_sub_right);
2358 CheckScalarBinary("subtract", right, left, right_sub_left);
2359 }
2360
2361 // scalar scalar
2362 {
2363 auto left = ScalarFromJSON(decimal256(3, 0), R"("666")");
2364 auto right = ScalarFromJSON(decimal256(3, 0), R"("888")");
2365 auto added = ScalarFromJSON(decimal256(4, 0), R"("1554")");
2366 auto subtracted = ScalarFromJSON(decimal256(4, 0), R"("-222")");
2367 CheckScalarBinary("add", left, right, added);
2368 CheckScalarBinary("subtract", left, right, subtracted);
2369 }
2370
2371 // decimal128 decimal256
2372 {
2373 auto left = ScalarFromJSON(decimal128(3, 0), R"("666")");
2374 auto right = ScalarFromJSON(decimal256(3, 0), R"("888")");
2375 auto added = ScalarFromJSON(decimal256(4, 0), R"("1554")");
2376 CheckScalarBinary("add", left, right, added);
2377 CheckScalarBinary("add", right, left, added);
2378 }
2379
2380 // decimal float
2381 {
2382 auto left = ScalarFromJSON(decimal128(3, 0), R"("666")");
2383 ASSIGN_OR_ABORT(auto right, arrow::MakeScalar(float64(), 888));
2384 ASSIGN_OR_ABORT(auto added, arrow::MakeScalar(float64(), 1554));
2385 CheckScalarBinary("add", left, right, added);
2386 CheckScalarBinary("add", right, left, added);
2387 }
2388
2389 // TODO: decimal integer
2390
2391 // failed case: result maybe overflow
2392 {
2393 std::shared_ptr<Scalar> left, right;
2394
2395 left = ScalarFromJSON(decimal128(21, 20), R"("0.12345678901234567890")");
2396 right = ScalarFromJSON(decimal128(21, 1), R"("1.0")");
2397 ASSERT_RAISES(Invalid, CallFunction("add", {left, right}));
2398 ASSERT_RAISES(Invalid, CallFunction("subtract", {left, right}));
2399
2400 left = ScalarFromJSON(decimal256(75, 0), R"("0")");
2401 right = ScalarFromJSON(decimal256(2, 1), R"("0.0")");
2402 ASSERT_RAISES(Invalid, CallFunction("add", {left, right}));
2403 ASSERT_RAISES(Invalid, CallFunction("subtract", {left, right}));
2404 }
2405 }
2406
TEST(TestBinaryArithmeticDecimal,Multiply)2407 TEST(TestBinaryArithmeticDecimal, Multiply) {
2408 // array array, decimal128
2409 {
2410 auto left = ArrayFromJSON(decimal128(20, 10),
2411 R"([
2412 "1234567890.1234567890",
2413 "-0.0000000001",
2414 "-9999999999.9999999999"
2415 ])");
2416 auto right = ArrayFromJSON(decimal128(13, 3),
2417 R"([
2418 "1234567890.123",
2419 "0.001",
2420 "-9999999999.999"
2421 ])");
2422 auto expected = ArrayFromJSON(decimal128(34, 13),
2423 R"([
2424 "1524157875323319737.9870903950470",
2425 "-0.0000000000001",
2426 "99999999999989999999.0000000000001"
2427 ])");
2428 CheckScalarBinary("multiply", left, right, expected);
2429 }
2430
2431 // array array, decimal26
2432 {
2433 auto left = ArrayFromJSON(decimal256(30, 3),
2434 R"([
2435 "123456789012345678901234567.890",
2436 "0.000"
2437 ])");
2438 auto right = ArrayFromJSON(decimal256(20, 9),
2439 R"([
2440 "-12345678901.234567890",
2441 "99999999999.999999999"
2442 ])");
2443 auto expected = ArrayFromJSON(decimal256(51, 12),
2444 R"([
2445 "-1524157875323883675034293577501905199.875019052100",
2446 "0.000000000000"
2447 ])");
2448 CheckScalarBinary("multiply", left, right, expected);
2449 }
2450
2451 // scalar array
2452 {
2453 auto left = ScalarFromJSON(decimal128(3, 2), R"("3.14")");
2454 auto right = ArrayFromJSON(decimal128(1, 0), R"(["1", "2", "3", "4", "5"])");
2455 auto expected =
2456 ArrayFromJSON(decimal128(5, 2), R"(["3.14", "6.28", "9.42", "12.56", "15.70"])");
2457 CheckScalarBinary("multiply", left, right, expected);
2458 CheckScalarBinary("multiply", right, left, expected);
2459 }
2460
2461 // scalar scalar
2462 {
2463 auto left = ScalarFromJSON(decimal128(1, 0), R"("1")");
2464 auto right = ScalarFromJSON(decimal128(1, 0), R"("1")");
2465 auto expected = ScalarFromJSON(decimal128(3, 0), R"("1")");
2466 CheckScalarBinary("multiply", left, right, expected);
2467 }
2468
2469 // decimal128 decimal256
2470 {
2471 auto left = ScalarFromJSON(decimal128(3, 2), R"("6.66")");
2472 auto right = ScalarFromJSON(decimal256(3, 1), R"("88.8")");
2473 auto expected = ScalarFromJSON(decimal256(7, 3), R"("591.408")");
2474 CheckScalarBinary("multiply", left, right, expected);
2475 CheckScalarBinary("multiply", right, left, expected);
2476 }
2477
2478 // decimal float
2479 {
2480 auto left = ScalarFromJSON(decimal128(3, 0), R"("666")");
2481 ASSIGN_OR_ABORT(auto right, arrow::MakeScalar(float64(), 888));
2482 ASSIGN_OR_ABORT(auto expected, arrow::MakeScalar(float64(), 591408));
2483 CheckScalarBinary("multiply", left, right, expected);
2484 CheckScalarBinary("multiply", right, left, expected);
2485 }
2486
2487 // TODO: decimal integer
2488
2489 // failed case: result maybe overflow
2490 {
2491 auto left = ScalarFromJSON(decimal128(20, 0), R"("1")");
2492 auto right = ScalarFromJSON(decimal128(18, 1), R"("1.0")");
2493 ASSERT_RAISES(Invalid, CallFunction("multiply", {left, right}));
2494 }
2495 }
2496
TEST(TestBinaryArithmeticDecimal,Divide)2497 TEST(TestBinaryArithmeticDecimal, Divide) {
2498 // array array, decimal128
2499 {
2500 auto left = ArrayFromJSON(decimal128(13, 3), R"(["1234567890.123", "0.001"])");
2501 auto right = ArrayFromJSON(decimal128(3, 0), R"(["-987", "999"])");
2502 auto expected =
2503 ArrayFromJSON(decimal128(17, 7), R"(["-1250828.6627386", "0.0000010"])");
2504 CheckScalarBinary("divide", left, right, expected);
2505 }
2506
2507 // array array, decimal256
2508 {
2509 auto left = ArrayFromJSON(decimal256(20, 10),
2510 R"(["1234567890.1234567890", "9999999999.9999999999"])");
2511 auto right = ArrayFromJSON(decimal256(13, 3), R"(["1234567890.123", "0.001"])");
2512 auto expected = ArrayFromJSON(
2513 decimal256(34, 21),
2514 R"(["1.000000000000369999093", "9999999999999.999999900000000000000"])");
2515 CheckScalarBinary("divide", left, right, expected);
2516 }
2517
2518 // scalar array
2519 {
2520 auto left = ScalarFromJSON(decimal128(1, 0), R"("1")");
2521 auto right = ArrayFromJSON(decimal128(1, 0), R"(["1", "2", "3", "4"])");
2522 auto left_div_right =
2523 ArrayFromJSON(decimal128(5, 4), R"(["1.0000", "0.5000", "0.3333", "0.2500"])");
2524 auto right_div_left =
2525 ArrayFromJSON(decimal128(5, 4), R"(["1.0000", "2.0000", "3.0000", "4.0000"])");
2526 CheckScalarBinary("divide", left, right, left_div_right);
2527 CheckScalarBinary("divide", right, left, right_div_left);
2528 }
2529
2530 // scalar scalar
2531 {
2532 auto left = ScalarFromJSON(decimal256(6, 5), R"("2.71828")");
2533 auto right = ScalarFromJSON(decimal256(6, 5), R"("3.14159")");
2534 auto expected = ScalarFromJSON(decimal256(13, 7), R"("0.8652561")");
2535 CheckScalarBinary("divide", left, right, expected);
2536 }
2537
2538 // decimal128 decimal256
2539 {
2540 auto left = ScalarFromJSON(decimal256(6, 5), R"("2.71828")");
2541 auto right = ScalarFromJSON(decimal128(6, 5), R"("3.14159")");
2542 auto left_div_right = ScalarFromJSON(decimal256(13, 7), R"("0.8652561")");
2543 auto right_div_left = ScalarFromJSON(decimal256(13, 7), R"("1.1557271")");
2544 CheckScalarBinary("divide", left, right, left_div_right);
2545 CheckScalarBinary("divide", right, left, right_div_left);
2546 }
2547
2548 // decimal float
2549 {
2550 auto left = ScalarFromJSON(decimal128(3, 0), R"("100")");
2551 ASSIGN_OR_ABORT(auto right, arrow::MakeScalar(float64(), 50));
2552 ASSIGN_OR_ABORT(auto left_div_right, arrow::MakeScalar(float64(), 2));
2553 ASSIGN_OR_ABORT(auto right_div_left, arrow::MakeScalar(float64(), 0.5));
2554 CheckScalarBinary("divide", left, right, left_div_right);
2555 CheckScalarBinary("divide", right, left, right_div_left);
2556 }
2557
2558 // TODO: decimal integer
2559
2560 // failed case: result maybe overflow
2561 {
2562 auto left = ScalarFromJSON(decimal128(20, 20), R"("0.12345678901234567890")");
2563 auto right = ScalarFromJSON(decimal128(20, 0), R"("12345678901234567890")");
2564 ASSERT_RAISES(Invalid, CallFunction("divide", {left, right}));
2565 }
2566
2567 // failed case: divide by 0
2568 {
2569 auto left = ScalarFromJSON(decimal256(1, 0), R"("1")");
2570 auto right = ScalarFromJSON(decimal256(1, 0), R"("0")");
2571 ASSERT_RAISES(Invalid, CallFunction("divide", {left, right}));
2572 }
2573 }
2574
TYPED_TEST(TestBinaryArithmeticIntegral,ShiftLeft)2575 TYPED_TEST(TestBinaryArithmeticIntegral, ShiftLeft) {
2576 for (auto check_overflow : {false, true}) {
2577 this->SetOverflowCheck(check_overflow);
2578
2579 this->AssertBinop(ShiftLeft, "[]", "[]", "[]");
2580 this->AssertBinop(ShiftLeft, "[0, 1, 2, 3]", "[2, 3, 4, 5]", "[0, 8, 32, 96]");
2581 // Nulls on one side
2582 this->AssertBinop(ShiftLeft, "[0, null, 2, 3]", "[2, 3, 4, 5]", "[0, null, 32, 96]");
2583 this->AssertBinop(ShiftLeft, "[0, 1, 2, 3]", "[2, 3, null, 5]", "[0, 8, null, 96]");
2584 // Nulls on both sides
2585 this->AssertBinop(ShiftLeft, "[0, null, 2, 3]", "[2, 3, null, 5]",
2586 "[0, null, null, 96]");
2587 // All nulls
2588 this->AssertBinop(ShiftLeft, "[null]", "[null]", "[null]");
2589
2590 // Scalar on the left
2591 this->AssertBinop(ShiftLeft, 2, "[null, 5]", "[null, 64]");
2592 this->AssertBinop(ShiftLeft, this->MakeNullScalar(), "[null, 5]", "[null, null]");
2593 // Scalar on the right
2594 this->AssertBinop(ShiftLeft, "[null, 5]", 3, "[null, 40]");
2595 this->AssertBinop(ShiftLeft, "[null, 5]", this->MakeNullScalar(), "[null, null]");
2596 }
2597 }
2598
TYPED_TEST(TestBinaryArithmeticIntegral,ShiftRight)2599 TYPED_TEST(TestBinaryArithmeticIntegral, ShiftRight) {
2600 for (auto check_overflow : {false, true}) {
2601 this->SetOverflowCheck(check_overflow);
2602
2603 this->AssertBinop(ShiftRight, "[]", "[]", "[]");
2604 this->AssertBinop(ShiftRight, "[0, 1, 4, 8]", "[1, 1, 1, 4]", "[0, 0, 2, 0]");
2605 // Nulls on one side
2606 this->AssertBinop(ShiftRight, "[0, null, 4, 8]", "[1, 1, 1, 4]", "[0, null, 2, 0]");
2607 this->AssertBinop(ShiftRight, "[0, 1, 4, 8]", "[1, 1, null, 4]", "[0, 0, null, 0]");
2608 // Nulls on both sides
2609 this->AssertBinop(ShiftRight, "[0, null, 4, 8]", "[1, 1, null, 4]",
2610 "[0, null, null, 0]");
2611 // All nulls
2612 this->AssertBinop(ShiftRight, "[null]", "[null]", "[null]");
2613
2614 // Scalar on the left
2615 this->AssertBinop(ShiftRight, 64, "[null, 2, 6]", "[null, 16, 1]");
2616 this->AssertBinop(ShiftRight, this->MakeNullScalar(), "[null, 2, 6]",
2617 "[null, null, null]");
2618 // Scalar on the right
2619 this->AssertBinop(ShiftRight, "[null, 3, 96]", 3, "[null, 0, 12]");
2620 this->AssertBinop(ShiftRight, "[null, 3, 96]", this->MakeNullScalar(),
2621 "[null, null, null]");
2622 }
2623 }
2624
TYPED_TEST(TestBinaryArithmeticSigned,ShiftLeftOverflowRaises)2625 TYPED_TEST(TestBinaryArithmeticSigned, ShiftLeftOverflowRaises) {
2626 using CType = typename TestFixture::CType;
2627 const CType bit_width = static_cast<CType>(std::numeric_limits<CType>::digits);
2628 const CType min = std::numeric_limits<CType>::min();
2629 this->SetOverflowCheck(true);
2630
2631 this->AssertBinop(ShiftLeft, "[1]", MakeArray(bit_width - 1),
2632 MakeArray(static_cast<CType>(1) << (bit_width - 1)));
2633 this->AssertBinop(ShiftLeft, "[2]", MakeArray(bit_width - 2),
2634 MakeArray(static_cast<CType>(1) << (bit_width - 1)));
2635 // Shift a bit into the sign bit
2636 this->AssertBinop(ShiftLeft, "[2]", MakeArray(bit_width - 1), MakeArray(min));
2637 // Shift a bit past the sign bit
2638 this->AssertBinop(ShiftLeft, "[4]", MakeArray(bit_width - 1), "[0]");
2639 this->AssertBinop(ShiftLeft, MakeArray(min), "[1]", "[0]");
2640 this->AssertBinopRaises(ShiftLeft, "[1, 2]", "[1, -1]",
2641 "shift amount must be >= 0 and less than precision of type");
2642 this->AssertBinopRaises(ShiftLeft, "[1]", MakeArray(bit_width),
2643 "shift amount must be >= 0 and less than precision of type");
2644
2645 this->SetOverflowCheck(false);
2646 this->AssertBinop(ShiftLeft, "[1, 1]", MakeArray(-1, bit_width), "[1, 1]");
2647 }
2648
TYPED_TEST(TestBinaryArithmeticSigned,ShiftRightOverflowRaises)2649 TYPED_TEST(TestBinaryArithmeticSigned, ShiftRightOverflowRaises) {
2650 using CType = typename TestFixture::CType;
2651 const CType bit_width = static_cast<CType>(std::numeric_limits<CType>::digits);
2652 const CType max = std::numeric_limits<CType>::max();
2653 const CType min = std::numeric_limits<CType>::min();
2654 this->SetOverflowCheck(true);
2655
2656 this->AssertBinop(ShiftRight, MakeArray(max), MakeArray(bit_width - 1), "[1]");
2657 this->AssertBinop(ShiftRight, "[-1, -1]", "[1, 5]", "[-1, -1]");
2658 this->AssertBinop(ShiftRight, MakeArray(min), "[1]", MakeArray(min / 2));
2659 this->AssertBinopRaises(ShiftRight, "[1, 2]", "[1, -1]",
2660 "shift amount must be >= 0 and less than precision of type");
2661 this->AssertBinopRaises(ShiftRight, "[1]", MakeArray(bit_width),
2662 "shift amount must be >= 0 and less than precision of type");
2663
2664 this->SetOverflowCheck(false);
2665 this->AssertBinop(ShiftRight, "[1, 1]", MakeArray(-1, bit_width), "[1, 1]");
2666 }
2667
TYPED_TEST(TestBinaryArithmeticUnsigned,ShiftLeftOverflowRaises)2668 TYPED_TEST(TestBinaryArithmeticUnsigned, ShiftLeftOverflowRaises) {
2669 using CType = typename TestFixture::CType;
2670 const CType bit_width = static_cast<CType>(std::numeric_limits<CType>::digits);
2671 this->SetOverflowCheck(true);
2672
2673 this->AssertBinop(ShiftLeft, "[1]", MakeArray(bit_width - 1),
2674 MakeArray(static_cast<CType>(1) << (bit_width - 1)));
2675 this->AssertBinop(ShiftLeft, "[2]", MakeArray(bit_width - 2),
2676 MakeArray(static_cast<CType>(1) << (bit_width - 1)));
2677 this->AssertBinop(ShiftLeft, "[2]", MakeArray(bit_width - 1), "[0]");
2678 this->AssertBinop(ShiftLeft, "[4]", MakeArray(bit_width - 1), "[0]");
2679 this->AssertBinopRaises(ShiftLeft, "[1]", MakeArray(bit_width),
2680 "shift amount must be >= 0 and less than precision of type");
2681 }
2682
TYPED_TEST(TestBinaryArithmeticUnsigned,ShiftRightOverflowRaises)2683 TYPED_TEST(TestBinaryArithmeticUnsigned, ShiftRightOverflowRaises) {
2684 using CType = typename TestFixture::CType;
2685 const CType bit_width = static_cast<CType>(std::numeric_limits<CType>::digits);
2686 const CType max = std::numeric_limits<CType>::max();
2687 this->SetOverflowCheck(true);
2688
2689 this->AssertBinop(ShiftRight, MakeArray(max), MakeArray(bit_width - 1), "[1]");
2690 this->AssertBinopRaises(ShiftRight, "[1]", MakeArray(bit_width),
2691 "shift amount must be >= 0 and less than precision of type");
2692 }
2693
TYPED_TEST(TestUnaryArithmeticFloating,TrigSin)2694 TYPED_TEST(TestUnaryArithmeticFloating, TrigSin) {
2695 this->SetNansEqual(true);
2696 this->AssertUnaryOp(Sin, "[Inf, -Inf]", "[NaN, NaN]");
2697 for (auto check_overflow : {false, true}) {
2698 this->SetOverflowCheck(check_overflow);
2699 this->AssertUnaryOp(Sin, "[]", "[]");
2700 this->AssertUnaryOp(Sin, "[null, NaN]", "[null, NaN]");
2701 this->AssertUnaryOp(Sin, MakeArray(0, M_PI_2, M_PI), "[0, 1, 0]");
2702 }
2703 this->AssertUnaryOpRaises(Sin, "[Inf, -Inf]", "domain error");
2704 }
2705
TYPED_TEST(TestUnaryArithmeticFloating,TrigCos)2706 TYPED_TEST(TestUnaryArithmeticFloating, TrigCos) {
2707 this->SetNansEqual(true);
2708 this->AssertUnaryOp(Cos, "[Inf, -Inf]", "[NaN, NaN]");
2709 for (auto check_overflow : {false, true}) {
2710 this->SetOverflowCheck(check_overflow);
2711 this->AssertUnaryOp(Cos, "[]", "[]");
2712 this->AssertUnaryOp(Cos, "[null, NaN]", "[null, NaN]");
2713 this->AssertUnaryOp(Cos, MakeArray(0, M_PI_2, M_PI), "[1, 0, -1]");
2714 }
2715 this->AssertUnaryOpRaises(Cos, "[Inf, -Inf]", "domain error");
2716 }
2717
TYPED_TEST(TestUnaryArithmeticFloating,TrigTan)2718 TYPED_TEST(TestUnaryArithmeticFloating, TrigTan) {
2719 this->SetNansEqual(true);
2720 this->AssertUnaryOp(Tan, "[Inf, -Inf]", "[NaN, NaN]");
2721 for (auto check_overflow : {false, true}) {
2722 this->SetOverflowCheck(check_overflow);
2723 this->AssertUnaryOp(Tan, "[]", "[]");
2724 this->AssertUnaryOp(Tan, "[null, NaN]", "[null, NaN]");
2725 // N.B. pi/2 isn't representable exactly -> there are no poles
2726 // (i.e. tan(pi/2) is merely a large value and not +Inf)
2727 this->AssertUnaryOp(Tan, MakeArray(0, M_PI), "[0, 0]");
2728 }
2729 this->AssertUnaryOpRaises(Tan, "[Inf, -Inf]", "domain error");
2730 }
2731
TYPED_TEST(TestUnaryArithmeticFloating,TrigAsin)2732 TYPED_TEST(TestUnaryArithmeticFloating, TrigAsin) {
2733 this->SetNansEqual(true);
2734 this->AssertUnaryOp(Asin, "[Inf, -Inf, -2, 2]", "[NaN, NaN, NaN, NaN]");
2735 for (auto check_overflow : {false, true}) {
2736 this->SetOverflowCheck(check_overflow);
2737 this->AssertUnaryOp(Asin, "[]", "[]");
2738 this->AssertUnaryOp(Asin, "[null, NaN]", "[null, NaN]");
2739 this->AssertUnaryOp(Asin, "[0, 1, -1]", MakeArray(0, M_PI_2, -M_PI_2));
2740 }
2741 this->AssertUnaryOpRaises(Asin, "[Inf, -Inf, -2, 2]", "domain error");
2742 }
2743
TYPED_TEST(TestUnaryArithmeticFloating,TrigAcos)2744 TYPED_TEST(TestUnaryArithmeticFloating, TrigAcos) {
2745 this->SetNansEqual(true);
2746 this->AssertUnaryOp(Asin, "[Inf, -Inf, -2, 2]", "[NaN, NaN, NaN, NaN]");
2747 for (auto check_overflow : {false, true}) {
2748 this->SetOverflowCheck(check_overflow);
2749 this->AssertUnaryOp(Acos, "[]", "[]");
2750 this->AssertUnaryOp(Acos, "[null, NaN]", "[null, NaN]");
2751 this->AssertUnaryOp(Acos, "[0, 1, -1]", MakeArray(M_PI_2, 0, M_PI));
2752 }
2753 this->AssertUnaryOpRaises(Acos, "[Inf, -Inf, -2, 2]", "domain error");
2754 }
2755
TYPED_TEST(TestUnaryArithmeticFloating,TrigAtan)2756 TYPED_TEST(TestUnaryArithmeticFloating, TrigAtan) {
2757 this->SetNansEqual(true);
2758 auto atan = [](const Datum& arg, ArithmeticOptions, ExecContext* ctx) {
2759 return Atan(arg, ctx);
2760 };
2761 this->AssertUnaryOp(atan, "[]", "[]");
2762 this->AssertUnaryOp(atan, "[null, NaN]", "[null, NaN]");
2763 this->AssertUnaryOp(atan, "[0, 1, -1, Inf, -Inf]",
2764 MakeArray(0, M_PI_4, -M_PI_4, M_PI_2, -M_PI_2));
2765 }
2766
TYPED_TEST(TestBinaryArithmeticFloating,TrigAtan2)2767 TYPED_TEST(TestBinaryArithmeticFloating, TrigAtan2) {
2768 this->SetNansEqual(true);
2769 auto atan2 = [](const Datum& y, const Datum& x, ArithmeticOptions, ExecContext* ctx) {
2770 return Atan2(y, x, ctx);
2771 };
2772 this->AssertBinop(atan2, "[]", "[]", "[]");
2773 this->AssertBinop(atan2, "[0, 0, null, NaN]", "[null, NaN, 0, 0]",
2774 "[null, NaN, null, NaN]");
2775 this->AssertBinop(atan2, "[0, 0, -0.0, 0, -0.0, 0, 1, 0, -1, Inf, -Inf, 0, 0]",
2776 "[0, 0, 0, -0.0, -0.0, 1, 0, -1, 0, 0, 0, Inf, -Inf]",
2777 MakeArray(0, 0, -0.0, M_PI, -M_PI, 0, M_PI_2, M_PI, -M_PI_2, M_PI_2,
2778 -M_PI_2, 0, M_PI));
2779 }
2780
TYPED_TEST(TestUnaryArithmeticIntegral,Trig)2781 TYPED_TEST(TestUnaryArithmeticIntegral, Trig) {
2782 // Integer arguments promoted to double, sanity check here
2783 auto atan = [](const Datum& arg, ArithmeticOptions, ExecContext* ctx) {
2784 return Atan(arg, ctx);
2785 };
2786 for (auto check_overflow : {false, true}) {
2787 this->SetOverflowCheck(check_overflow);
2788 this->AssertUnaryOp(Sin, "[0, 1]",
2789 ArrayFromJSON(float64(), "[0, 0.8414709848078965]"));
2790 this->AssertUnaryOp(Cos, "[0, 1]",
2791 ArrayFromJSON(float64(), "[1, 0.5403023058681398]"));
2792 this->AssertUnaryOp(Tan, "[0, 1]",
2793 ArrayFromJSON(float64(), "[0, 1.5574077246549023]"));
2794 this->AssertUnaryOp(Asin, "[0, 1]", ArrayFromJSON(float64(), MakeArray(0, M_PI_2)));
2795 this->AssertUnaryOp(Acos, "[0, 1]", ArrayFromJSON(float64(), MakeArray(M_PI_2, 0)));
2796 this->AssertUnaryOp(atan, "[0, 1]", ArrayFromJSON(float64(), MakeArray(0, M_PI_4)));
2797 }
2798 }
2799
TYPED_TEST(TestBinaryArithmeticIntegral,Trig)2800 TYPED_TEST(TestBinaryArithmeticIntegral, Trig) {
2801 // Integer arguments promoted to double, sanity check here
2802 auto ty = this->type_singleton();
2803 auto atan2 = [](const Datum& y, const Datum& x, ArithmeticOptions, ExecContext* ctx) {
2804 return Atan2(y, x, ctx);
2805 };
2806 this->AssertBinop(atan2, ArrayFromJSON(ty, "[0, 1]"), ArrayFromJSON(ty, "[1, 0]"),
2807 ArrayFromJSON(float64(), MakeArray(0, M_PI_2)));
2808 }
2809
TYPED_TEST(TestUnaryArithmeticFloating,Log)2810 TYPED_TEST(TestUnaryArithmeticFloating, Log) {
2811 using CType = typename TestFixture::CType;
2812 this->SetNansEqual(true);
2813 auto min_val = std::numeric_limits<CType>::min();
2814 auto max_val = std::numeric_limits<CType>::max();
2815 for (auto check_overflow : {false, true}) {
2816 this->SetOverflowCheck(check_overflow);
2817 this->AssertUnaryOp(Ln, "[1, 2.718281828459045, null, NaN, Inf]",
2818 "[0, 1, null, NaN, Inf]");
2819 // N.B. min() for float types is smallest normal number > 0
2820 this->AssertUnaryOp(Ln, min_val, std::log(min_val));
2821 this->AssertUnaryOp(Ln, max_val, std::log(max_val));
2822 this->AssertUnaryOp(Log10, "[1, 10, null, NaN, Inf]", "[0, 1, null, NaN, Inf]");
2823 this->AssertUnaryOp(Log10, min_val, std::log10(min_val));
2824 this->AssertUnaryOp(Log10, max_val, std::log10(max_val));
2825 this->AssertUnaryOp(Log2, "[1, 2, null, NaN, Inf]", "[0, 1, null, NaN, Inf]");
2826 this->AssertUnaryOp(Log2, min_val, std::log2(min_val));
2827 this->AssertUnaryOp(Log2, max_val, std::log2(max_val));
2828 this->AssertUnaryOp(Log1p, "[0, 1.718281828459045, null, NaN, Inf]",
2829 "[0, 1, null, NaN, Inf]");
2830 this->AssertUnaryOp(Log1p, min_val, std::log1p(min_val));
2831 this->AssertUnaryOp(Log1p, max_val, std::log1p(max_val));
2832 }
2833 this->SetOverflowCheck(false);
2834 this->AssertUnaryOp(Ln, "[-Inf, -1, 0, Inf]", "[NaN, NaN, -Inf, Inf]");
2835 this->AssertUnaryOp(Log10, "[-Inf, -1, 0, Inf]", "[NaN, NaN, -Inf, Inf]");
2836 this->AssertUnaryOp(Log2, "[-Inf, -1, 0, Inf]", "[NaN, NaN, -Inf, Inf]");
2837 this->AssertUnaryOp(Log1p, "[-Inf, -2, -1, Inf]", "[NaN, NaN, -Inf, Inf]");
2838 this->SetOverflowCheck(true);
2839 this->AssertUnaryOpRaises(Ln, "[0]", "logarithm of zero");
2840 this->AssertUnaryOpRaises(Ln, "[-1]", "logarithm of negative number");
2841 this->AssertUnaryOpRaises(Ln, "[-Inf]", "logarithm of negative number");
2842
2843 auto lowest_val = MakeScalar(std::numeric_limits<CType>::lowest());
2844 // N.B. RapidJSON on some platforms raises "Number too big to be stored in double" so
2845 // don't bounce through JSON
2846 EXPECT_RAISES_WITH_MESSAGE_THAT(Invalid,
2847 ::testing::HasSubstr("logarithm of negative number"),
2848 Ln(lowest_val, this->options_));
2849 this->AssertUnaryOpRaises(Log10, "[0]", "logarithm of zero");
2850 this->AssertUnaryOpRaises(Log10, "[-1]", "logarithm of negative number");
2851 this->AssertUnaryOpRaises(Log10, "[-Inf]", "logarithm of negative number");
2852 EXPECT_RAISES_WITH_MESSAGE_THAT(Invalid,
2853 ::testing::HasSubstr("logarithm of negative number"),
2854 Log10(lowest_val, this->options_));
2855 this->AssertUnaryOpRaises(Log2, "[0]", "logarithm of zero");
2856 this->AssertUnaryOpRaises(Log2, "[-1]", "logarithm of negative number");
2857 this->AssertUnaryOpRaises(Log2, "[-Inf]", "logarithm of negative number");
2858 EXPECT_RAISES_WITH_MESSAGE_THAT(Invalid,
2859 ::testing::HasSubstr("logarithm of negative number"),
2860 Log2(lowest_val, this->options_));
2861 this->AssertUnaryOpRaises(Log1p, "[-1]", "logarithm of zero");
2862 this->AssertUnaryOpRaises(Log1p, "[-2]", "logarithm of negative number");
2863 this->AssertUnaryOpRaises(Log1p, "[-Inf]", "logarithm of negative number");
2864 EXPECT_RAISES_WITH_MESSAGE_THAT(Invalid,
2865 ::testing::HasSubstr("logarithm of negative number"),
2866 Log1p(lowest_val, this->options_));
2867 }
2868
TYPED_TEST(TestUnaryArithmeticIntegral,Log)2869 TYPED_TEST(TestUnaryArithmeticIntegral, Log) {
2870 // Integer arguments promoted to double, sanity check here
2871 for (auto check_overflow : {false, true}) {
2872 this->SetOverflowCheck(check_overflow);
2873 this->AssertUnaryOp(Ln, "[1, null]", ArrayFromJSON(float64(), "[0, null]"));
2874 this->AssertUnaryOp(Log10, "[1, 10, null]", ArrayFromJSON(float64(), "[0, 1, null]"));
2875 this->AssertUnaryOp(Log2, "[1, 2, null]", ArrayFromJSON(float64(), "[0, 1, null]"));
2876 this->AssertUnaryOp(Log1p, "[0, null]", ArrayFromJSON(float64(), "[0, null]"));
2877 }
2878 }
2879
TYPED_TEST(TestBinaryArithmeticIntegral,Log)2880 TYPED_TEST(TestBinaryArithmeticIntegral, Log) {
2881 // Integer arguments promoted to double, sanity check here
2882 this->AssertBinop(Logb, "[1, 10, null]", "[10, 10, null]",
2883 ArrayFromJSON(float64(), "[0, 1, null]"));
2884 this->AssertBinop(Logb, "[1, 2, null]", "[2, 2, null]",
2885 ArrayFromJSON(float64(), "[0, 1, null]"));
2886 this->AssertBinop(Logb, "[10, 100, null]", this->MakeScalar(10),
2887 ArrayFromJSON(float64(), "[1, 2, null]"));
2888 }
2889
TYPED_TEST(TestBinaryArithmeticFloating,Log)2890 TYPED_TEST(TestBinaryArithmeticFloating, Log) {
2891 using CType = typename TestFixture::CType;
2892 this->SetNansEqual(true);
2893 auto min_val = std::numeric_limits<CType>::min();
2894 auto max_val = std::numeric_limits<CType>::max();
2895 for (auto check_overflow : {false, true}) {
2896 this->SetOverflowCheck(check_overflow);
2897 // N.B. min() for float types is smallest normal number > 0
2898 this->AssertBinop(Logb, "[1, 10, null, NaN, Inf]", "[100, 10, null, 2, 10]",
2899 "[0, 1, null, NaN, Inf]");
2900 this->AssertBinop(Logb, min_val, 10,
2901 static_cast<CType>(std::log(min_val) / std::log(10)));
2902 this->AssertBinop(Logb, max_val, 10,
2903 static_cast<CType>(std::log(max_val) / std::log(10)));
2904 }
2905 this->AssertBinop(Logb, "[1.0, 10.0, null]", "[10.0, 10.0, null]", "[0.0, 1.0, null]");
2906 this->AssertBinop(Logb, "[1.0, 2.0, null]", "[2.0, 2.0, null]", "[0.0, 1.0, null]");
2907 this->AssertBinop(Logb, "[10.0, 100.0, 1000.0, null]", this->MakeScalar(10),
2908 "[1.0, 2.0, 3.0, null]");
2909 this->SetOverflowCheck(false);
2910 this->AssertBinop(Logb, "[-Inf, -1, 0, Inf]", this->MakeScalar(10),
2911 "[NaN, NaN, -Inf, Inf]");
2912 this->AssertBinop(Logb, "[-Inf, -1, 0, Inf]", this->MakeScalar(2),
2913 "[NaN, NaN, -Inf, Inf]");
2914 this->AssertBinop(Logb, "[-Inf, -1, 0, Inf]", "[2, 10, 0, 0]", "[NaN, NaN, NaN, NaN]");
2915 this->AssertBinop(Logb, "[-Inf, -1, 0, Inf]", this->MakeScalar(0),
2916 "[NaN, NaN, NaN, NaN]");
2917 this->AssertBinop(Logb, "[-Inf, -2, -1, Inf]", this->MakeScalar(2),
2918 "[NaN, NaN, NaN, Inf]");
2919 this->SetOverflowCheck(true);
2920 this->AssertBinopRaises(Logb, "[0]", "[2]", "logarithm of zero");
2921 this->AssertBinopRaises(Logb, "[-1]", "[2]", "logarithm of negative number");
2922 this->AssertBinopRaises(Logb, "[-Inf]", "[2]", "logarithm of negative number");
2923 }
2924
TYPED_TEST(TestBinaryArithmeticSigned,Log)2925 TYPED_TEST(TestBinaryArithmeticSigned, Log) {
2926 // Integer arguments promoted to double, sanity check here
2927 this->SetNansEqual(true);
2928 this->SetOverflowCheck(false);
2929 this->AssertBinop(Logb, "[-1, 0]", this->MakeScalar(10),
2930 ArrayFromJSON(float64(), "[NaN, -Inf]"));
2931 this->AssertBinop(Logb, "[-1, 0]", this->MakeScalar(2),
2932 ArrayFromJSON(float64(), "[NaN, -Inf]"));
2933 this->AssertBinop(Logb, "[10, 100]", this->MakeScalar(-1),
2934 ArrayFromJSON(float64(), "[NaN, NaN]"));
2935 this->AssertBinop(Logb, "[-1, 0, null]", this->MakeScalar(-1),
2936 ArrayFromJSON(float64(), "[NaN, NaN, null]"));
2937 this->AssertBinop(Logb, "[10, 100]", this->MakeScalar(0),
2938 ArrayFromJSON(float64(), "[0, 0]"));
2939 this->SetOverflowCheck(true);
2940 this->AssertBinopRaises(Logb, "[0]", "[10]", "logarithm of zero");
2941 this->AssertBinopRaises(Logb, "[-1]", "[10]", "logarithm of negative number");
2942 this->AssertBinopRaises(Logb, "[10]", "[0]", "logarithm of zero");
2943 this->AssertBinopRaises(Logb, "[100]", "[-1]", "logarithm of negative number");
2944 }
2945
TYPED_TEST(TestUnaryArithmeticSigned,Log)2946 TYPED_TEST(TestUnaryArithmeticSigned, Log) {
2947 // Integer arguments promoted to double, sanity check here
2948 this->SetNansEqual(true);
2949 this->SetOverflowCheck(false);
2950 this->AssertUnaryOp(Ln, "[-1, 0]", ArrayFromJSON(float64(), "[NaN, -Inf]"));
2951 this->AssertUnaryOp(Log10, "[-1, 0]", ArrayFromJSON(float64(), "[NaN, -Inf]"));
2952 this->AssertUnaryOp(Log2, "[-1, 0]", ArrayFromJSON(float64(), "[NaN, -Inf]"));
2953 this->AssertUnaryOp(Log1p, "[-2, -1]", ArrayFromJSON(float64(), "[NaN, -Inf]"));
2954 this->SetOverflowCheck(true);
2955 this->AssertUnaryOpRaises(Ln, "[0]", "logarithm of zero");
2956 this->AssertUnaryOpRaises(Ln, "[-1]", "logarithm of negative number");
2957 this->AssertUnaryOpRaises(Log10, "[0]", "logarithm of zero");
2958 this->AssertUnaryOpRaises(Log10, "[-1]", "logarithm of negative number");
2959 this->AssertUnaryOpRaises(Log2, "[0]", "logarithm of zero");
2960 this->AssertUnaryOpRaises(Log2, "[-1]", "logarithm of negative number");
2961 this->AssertUnaryOpRaises(Log1p, "[-1]", "logarithm of zero");
2962 this->AssertUnaryOpRaises(Log1p, "[-2]", "logarithm of negative number");
2963 }
2964
TYPED_TEST(TestUnaryArithmeticSigned,Sign)2965 TYPED_TEST(TestUnaryArithmeticSigned, Sign) {
2966 using CType = typename TestFixture::CType;
2967 auto min = std::numeric_limits<CType>::min();
2968 auto max = std::numeric_limits<CType>::max();
2969
2970 auto sign = [](const Datum& arg, ArithmeticOptions, ExecContext* ctx) {
2971 return Sign(arg, ctx);
2972 };
2973
2974 this->AssertUnaryOp(sign, "[]", ArrayFromJSON(int8(), "[]"));
2975 this->AssertUnaryOp(sign, "[null]", ArrayFromJSON(int8(), "[null]"));
2976 this->AssertUnaryOp(sign, "[1, null, -10]", ArrayFromJSON(int8(), "[1, null, -1]"));
2977 this->AssertUnaryOp(sign, "[0]", ArrayFromJSON(int8(), "[0]"));
2978 this->AssertUnaryOp(sign, "[1, 10, 127]", ArrayFromJSON(int8(), "[1, 1, 1]"));
2979 this->AssertUnaryOp(sign, "[-1, -10, -127]", ArrayFromJSON(int8(), "[-1, -1, -1]"));
2980 this->AssertUnaryOp(sign, this->MakeScalar(min), *arrow::MakeScalar(int8(), -1));
2981 this->AssertUnaryOp(sign, this->MakeScalar(max), *arrow::MakeScalar(int8(), 1));
2982 }
2983
TYPED_TEST(TestUnaryArithmeticUnsigned,Sign)2984 TYPED_TEST(TestUnaryArithmeticUnsigned, Sign) {
2985 using CType = typename TestFixture::CType;
2986 auto min = std::numeric_limits<CType>::min();
2987 auto max = std::numeric_limits<CType>::max();
2988
2989 auto sign = [](const Datum& arg, ArithmeticOptions, ExecContext* ctx) {
2990 return Sign(arg, ctx);
2991 };
2992
2993 this->AssertUnaryOp(sign, "[]", ArrayFromJSON(int8(), "[]"));
2994 this->AssertUnaryOp(sign, "[null]", ArrayFromJSON(int8(), "[null]"));
2995 this->AssertUnaryOp(sign, "[1, null, 10]", ArrayFromJSON(int8(), "[1, null, 1]"));
2996 this->AssertUnaryOp(sign, "[0]", ArrayFromJSON(int8(), "[0]"));
2997 this->AssertUnaryOp(sign, "[1, 10, 127]", ArrayFromJSON(int8(), "[1, 1, 1]"));
2998 this->AssertUnaryOp(sign, this->MakeScalar(min), *arrow::MakeScalar(int8(), 0));
2999 this->AssertUnaryOp(sign, this->MakeScalar(max), *arrow::MakeScalar(int8(), 1));
3000 }
3001
TYPED_TEST(TestUnaryArithmeticFloating,Sign)3002 TYPED_TEST(TestUnaryArithmeticFloating, Sign) {
3003 using CType = typename TestFixture::CType;
3004 auto min = std::numeric_limits<CType>::lowest();
3005 auto max = std::numeric_limits<CType>::max();
3006
3007 this->SetNansEqual(true);
3008
3009 auto sign = [](const Datum& arg, ArithmeticOptions, ExecContext* ctx) {
3010 return Sign(arg, ctx);
3011 };
3012
3013 this->AssertUnaryOp(sign, "[]", "[]");
3014 this->AssertUnaryOp(sign, "[null]", "[null]");
3015 this->AssertUnaryOp(sign, "[1.3, null, -10.80]", "[1, null, -1]");
3016 this->AssertUnaryOp(sign, "[0.0, -0.0]", "[0, 0]");
3017 this->AssertUnaryOp(sign, "[1.3, 10.80, 12748.001]", "[1, 1, 1]");
3018 this->AssertUnaryOp(sign, "[-1.3, -10.80, -12748.001]", "[-1, -1, -1]");
3019 this->AssertUnaryOp(sign, "[Inf, -Inf]", "[1, -1]");
3020 this->AssertUnaryOp(sign, "[NaN]", "[NaN]");
3021 this->AssertUnaryOp(sign, this->MakeScalar(min), this->MakeScalar(-1));
3022 this->AssertUnaryOp(sign, this->MakeScalar(max), this->MakeScalar(1));
3023 }
3024
TYPED_TEST(TestUnaryArithmeticSigned,Floor)3025 TYPED_TEST(TestUnaryArithmeticSigned, Floor) {
3026 auto floor = [](const Datum& arg, ArithmeticOptions, ExecContext* ctx) {
3027 return Floor(arg, ctx);
3028 };
3029
3030 this->AssertUnaryOp(floor, "[]", ArrayFromJSON(float64(), "[]"));
3031 this->AssertUnaryOp(floor, "[null]", ArrayFromJSON(float64(), "[null]"));
3032 this->AssertUnaryOp(floor, "[1, null, -10]",
3033 ArrayFromJSON(float64(), "[1, null, -10]"));
3034 this->AssertUnaryOp(floor, "[0]", ArrayFromJSON(float64(), "[0]"));
3035 this->AssertUnaryOp(floor, "[1, 10, 127]", ArrayFromJSON(float64(), "[1, 10, 127]"));
3036 this->AssertUnaryOp(floor, "[-1, -10, -127]",
3037 ArrayFromJSON(float64(), "[-1, -10, -127]"));
3038 }
3039
TYPED_TEST(TestUnaryArithmeticUnsigned,Floor)3040 TYPED_TEST(TestUnaryArithmeticUnsigned, Floor) {
3041 auto floor = [](const Datum& arg, ArithmeticOptions, ExecContext* ctx) {
3042 return Floor(arg, ctx);
3043 };
3044
3045 this->AssertUnaryOp(floor, "[]", ArrayFromJSON(float64(), "[]"));
3046 this->AssertUnaryOp(floor, "[null]", ArrayFromJSON(float64(), "[null]"));
3047 this->AssertUnaryOp(floor, "[1, null, 10]", ArrayFromJSON(float64(), "[1, null, 10]"));
3048 this->AssertUnaryOp(floor, "[0]", ArrayFromJSON(float64(), "[0]"));
3049 this->AssertUnaryOp(floor, "[1, 10, 127]", ArrayFromJSON(float64(), "[1, 10, 127]"));
3050 }
3051
TYPED_TEST(TestUnaryArithmeticFloating,Floor)3052 TYPED_TEST(TestUnaryArithmeticFloating, Floor) {
3053 using CType = typename TestFixture::CType;
3054 auto min = std::numeric_limits<CType>::lowest();
3055 auto max = std::numeric_limits<CType>::max();
3056
3057 this->SetNansEqual(true);
3058
3059 auto floor = [](const Datum& arg, ArithmeticOptions, ExecContext* ctx) {
3060 return Floor(arg, ctx);
3061 };
3062
3063 this->AssertUnaryOp(floor, "[]", "[]");
3064 this->AssertUnaryOp(floor, "[null]", "[null]");
3065 this->AssertUnaryOp(floor, "[1.3, null, -10.80]", "[1, null, -11]");
3066 this->AssertUnaryOp(floor, "[0.0, -0.0]", "[0, 0]");
3067 this->AssertUnaryOp(floor, "[1.3, 10.80, 12748.001]", "[1, 10, 12748]");
3068 this->AssertUnaryOp(floor, "[-1.3, -10.80, -12748.001]", "[-2, -11, -12749]");
3069 this->AssertUnaryOp(floor, "[Inf, -Inf]", "[Inf, -Inf]");
3070 this->AssertUnaryOp(floor, "[NaN]", "[NaN]");
3071 this->AssertUnaryOp(floor, this->MakeScalar(min), this->MakeScalar(min));
3072 this->AssertUnaryOp(floor, this->MakeScalar(max), this->MakeScalar(max));
3073 }
3074
TYPED_TEST(TestUnaryArithmeticSigned,Ceil)3075 TYPED_TEST(TestUnaryArithmeticSigned, Ceil) {
3076 auto ceil = [](const Datum& arg, ArithmeticOptions, ExecContext* ctx) {
3077 return Ceil(arg, ctx);
3078 };
3079
3080 this->AssertUnaryOp(ceil, "[]", ArrayFromJSON(float64(), "[]"));
3081 this->AssertUnaryOp(ceil, "[null]", ArrayFromJSON(float64(), "[null]"));
3082 this->AssertUnaryOp(ceil, "[1, null, -10]", ArrayFromJSON(float64(), "[1, null, -10]"));
3083 this->AssertUnaryOp(ceil, "[0]", ArrayFromJSON(float64(), "[0]"));
3084 this->AssertUnaryOp(ceil, "[1, 10, 127]", ArrayFromJSON(float64(), "[1, 10, 127]"));
3085 this->AssertUnaryOp(ceil, "[-1, -10, -127]",
3086 ArrayFromJSON(float64(), "[-1, -10, -127]"));
3087 }
3088
TYPED_TEST(TestUnaryArithmeticUnsigned,Ceil)3089 TYPED_TEST(TestUnaryArithmeticUnsigned, Ceil) {
3090 auto ceil = [](const Datum& arg, ArithmeticOptions, ExecContext* ctx) {
3091 return Ceil(arg, ctx);
3092 };
3093
3094 this->AssertUnaryOp(ceil, "[]", ArrayFromJSON(float64(), "[]"));
3095 this->AssertUnaryOp(ceil, "[null]", ArrayFromJSON(float64(), "[null]"));
3096 this->AssertUnaryOp(ceil, "[1, null, 10]", ArrayFromJSON(float64(), "[1, null, 10]"));
3097 this->AssertUnaryOp(ceil, "[0]", ArrayFromJSON(float64(), "[0]"));
3098 this->AssertUnaryOp(ceil, "[1, 10, 127]", ArrayFromJSON(float64(), "[1, 10, 127]"));
3099 }
3100
TYPED_TEST(TestUnaryArithmeticFloating,Ceil)3101 TYPED_TEST(TestUnaryArithmeticFloating, Ceil) {
3102 using CType = typename TestFixture::CType;
3103 auto min = std::numeric_limits<CType>::lowest();
3104 auto max = std::numeric_limits<CType>::max();
3105
3106 this->SetNansEqual(true);
3107
3108 auto ceil = [](const Datum& arg, ArithmeticOptions, ExecContext* ctx) {
3109 return Ceil(arg, ctx);
3110 };
3111
3112 this->AssertUnaryOp(ceil, "[]", "[]");
3113 this->AssertUnaryOp(ceil, "[null]", "[null]");
3114 this->AssertUnaryOp(ceil, "[1.3, null, -10.80]", "[2, null, -10]");
3115 this->AssertUnaryOp(ceil, "[0.0, -0.0]", "[0, 0]");
3116 this->AssertUnaryOp(ceil, "[1.3, 10.80, 12748.001]", "[2, 11, 12749]");
3117 this->AssertUnaryOp(ceil, "[-1.3, -10.80, -12748.001]", "[-1, -10, -12748]");
3118 this->AssertUnaryOp(ceil, "[Inf, -Inf]", "[Inf, -Inf]");
3119 this->AssertUnaryOp(ceil, "[NaN]", "[NaN]");
3120 this->AssertUnaryOp(ceil, this->MakeScalar(min), this->MakeScalar(min));
3121 this->AssertUnaryOp(ceil, this->MakeScalar(max), this->MakeScalar(max));
3122 }
3123
TYPED_TEST(TestUnaryArithmeticSigned,Trunc)3124 TYPED_TEST(TestUnaryArithmeticSigned, Trunc) {
3125 auto trunc = [](const Datum& arg, ArithmeticOptions, ExecContext* ctx) {
3126 return Trunc(arg, ctx);
3127 };
3128
3129 this->AssertUnaryOp(trunc, "[]", ArrayFromJSON(float64(), "[]"));
3130 this->AssertUnaryOp(trunc, "[null]", ArrayFromJSON(float64(), "[null]"));
3131 this->AssertUnaryOp(trunc, "[1, null, -10]",
3132 ArrayFromJSON(float64(), "[1, null, -10]"));
3133 this->AssertUnaryOp(trunc, "[0]", ArrayFromJSON(float64(), "[0]"));
3134 this->AssertUnaryOp(trunc, "[1, 10, 127]", ArrayFromJSON(float64(), "[1, 10, 127]"));
3135 this->AssertUnaryOp(trunc, "[-1, -10, -127]",
3136 ArrayFromJSON(float64(), "[-1, -10, -127]"));
3137 }
3138
TYPED_TEST(TestUnaryArithmeticUnsigned,Trunc)3139 TYPED_TEST(TestUnaryArithmeticUnsigned, Trunc) {
3140 auto trunc = [](const Datum& arg, ArithmeticOptions, ExecContext* ctx) {
3141 return Trunc(arg, ctx);
3142 };
3143
3144 this->AssertUnaryOp(trunc, "[]", ArrayFromJSON(float64(), "[]"));
3145 this->AssertUnaryOp(trunc, "[null]", ArrayFromJSON(float64(), "[null]"));
3146 this->AssertUnaryOp(trunc, "[1, null, 10]", ArrayFromJSON(float64(), "[1, null, 10]"));
3147 this->AssertUnaryOp(trunc, "[0]", ArrayFromJSON(float64(), "[0]"));
3148 this->AssertUnaryOp(trunc, "[1, 10, 127]", ArrayFromJSON(float64(), "[1, 10, 127]"));
3149 }
3150
TYPED_TEST(TestUnaryArithmeticFloating,Trunc)3151 TYPED_TEST(TestUnaryArithmeticFloating, Trunc) {
3152 using CType = typename TestFixture::CType;
3153 auto min = std::numeric_limits<CType>::lowest();
3154 auto max = std::numeric_limits<CType>::max();
3155
3156 this->SetNansEqual(true);
3157
3158 auto trunc = [](const Datum& arg, ArithmeticOptions, ExecContext* ctx) {
3159 return Trunc(arg, ctx);
3160 };
3161
3162 this->AssertUnaryOp(trunc, "[]", "[]");
3163 this->AssertUnaryOp(trunc, "[null]", "[null]");
3164 this->AssertUnaryOp(trunc, "[1.3, null, -10.80]", "[1, null, -10]");
3165 this->AssertUnaryOp(trunc, "[0.0, -0.0]", "[0, 0]");
3166 this->AssertUnaryOp(trunc, "[1.3, 10.80, 12748.001]", "[1, 10, 12748]");
3167 this->AssertUnaryOp(trunc, "[-1.3, -10.80, -12748.001]", "[-1, -10, -12748]");
3168 this->AssertUnaryOp(trunc, "[Inf, -Inf]", "[Inf, -Inf]");
3169 this->AssertUnaryOp(trunc, "[NaN]", "[NaN]");
3170 this->AssertUnaryOp(trunc, this->MakeScalar(min), this->MakeScalar(min));
3171 this->AssertUnaryOp(trunc, this->MakeScalar(max), this->MakeScalar(max));
3172 }
3173 } // namespace compute
3174 } // namespace arrow
3175