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