This is an automated email from the ASF dual-hosted git repository.
apitrou pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/arrow.git
The following commit(s) were added to refs/heads/master by this push:
new dc06265 ARROW-4274: [C++][Gandiva] split decimal into two parts
dc06265 is described below
commit dc062656d7da7593764cb35fd0c78ba19856a4f3
Author: Pindikura Ravindra <[email protected]>
AuthorDate: Thu Jan 24 10:23:05 2019 +0100
ARROW-4274: [C++][Gandiva] split decimal into two parts
Author: Pindikura Ravindra <[email protected]>
Author: Antoine Pitrou <[email protected]>
Closes #3414 from pravindra/split and squashes the following commits:
c96fbbfe <Antoine Pitrou> Try to fix MSVC compile failure
ed7e110c <Antoine Pitrou> Try to use newer Sphinx and breathe versions when
building the docs
2c0d870a <Pindikura Ravindra> ARROW-4274: Fix doxygen error
e2de415f <Pindikura Ravindra> ARROW-4274: Add empty constructor for older
compilers
42549b0f <Pindikura Ravindra> ARROW-4274: Address review comments
49d79333 <Pindikura Ravindra> ARROW-4274: Misc cleanups in header files
18050f8d <Pindikura Ravindra> ARROW-4274: split decimal into two parts
---
.travis.yml | 3 +-
ci/conda_env_sphinx.yml | 5 +-
ci/travis_script_python.sh | 6 +-
cpp/src/arrow/CMakeLists.txt | 1 +
cpp/src/arrow/util/basic_decimal.cc | 690 +++++++++++++++++++++
cpp/src/arrow/util/basic_decimal.h | 166 +++++
cpp/src/arrow/util/decimal.cc | 681 +-------------------
cpp/src/arrow/util/decimal.h | 137 +---
cpp/src/arrow/util/logging.h | 19 +
.../{decimal_full.h => basic_decimal_scalar.h} | 47 +-
cpp/src/gandiva/decimal_scalar.h | 54 ++
cpp/src/gandiva/decimal_type_util.cc | 4 +-
cpp/src/gandiva/jni/CMakeLists.txt | 2 +-
cpp/src/gandiva/jni/jni_common.cc | 4 +-
cpp/src/gandiva/literal_holder.h | 5 +-
cpp/src/gandiva/llvm_generator.cc | 12 +-
cpp/src/gandiva/precompiled/CMakeLists.txt | 5 +-
cpp/src/gandiva/precompiled/decimal_ops.cc | 60 +-
cpp/src/gandiva/precompiled/decimal_ops.h | 11 +-
cpp/src/gandiva/precompiled/decimal_ops_test.cc | 38 +-
cpp/src/gandiva/precompiled/decimal_wrapper.cc | 6 +-
cpp/src/gandiva/tests/decimal_single_test.cc | 20 +-
cpp/src/gandiva/tests/decimal_test.cc | 2 +-
cpp/src/gandiva/tree_expr_builder.cc | 4 +-
cpp/src/gandiva/tree_expr_builder.h | 4 +-
dev/tasks/gandiva-jars/travis.linux.yml | 1 -
docs/requirements.txt | 1 -
java/gandiva/pom.xml | 5 -
.../apache/arrow/gandiva/evaluator/JniLoader.java | 5 -
python/pyarrow/gandiva.pyx | 10 -
30 files changed, 1109 insertions(+), 899 deletions(-)
diff --git a/.travis.yml b/.travis.yml
index de0bb78..0ebd3ca 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -131,13 +131,12 @@ matrix:
- $TRAVIS_BUILD_DIR/ci/travis_install_toolchain.sh
script:
- $TRAVIS_BUILD_DIR/ci/travis_script_java.sh || travis_terminate 1
+ - ARROW_TRAVIS_PYTHON_GANDIVA=1
# Only run Plasma tests with valgrind in one of the Python builds because
# they are slow
- export PLASMA_VALGRIND=0
- $TRAVIS_BUILD_DIR/ci/travis_script_python.sh 2.7 || travis_terminate 1
- export PLASMA_VALGRIND=1
- # Gandiva tests are not enabled with python 2.7
- - ARROW_TRAVIS_PYTHON_GANDIVA=1
- $TRAVIS_BUILD_DIR/ci/travis_script_python.sh 3.6 || travis_terminate 1
- $TRAVIS_BUILD_DIR/ci/travis_upload_cpp_coverage.sh
- name: "[OS X] C++ w/ XCode 8.3"
diff --git a/ci/conda_env_sphinx.yml b/ci/conda_env_sphinx.yml
index af6b407..9acc354 100644
--- a/ci/conda_env_sphinx.yml
+++ b/ci/conda_env_sphinx.yml
@@ -16,8 +16,7 @@
# under the License.
# Requirements for building the documentation
-breathe
+# You also need to `pip install -r docs/requirements.txt`
+
doxygen
ipython
-sphinx
-sphinx_rtd_theme
diff --git a/ci/travis_script_python.sh b/ci/travis_script_python.sh
index 5732a17..f775999 100755
--- a/ci/travis_script_python.sh
+++ b/ci/travis_script_python.sh
@@ -62,6 +62,7 @@ which python
if [ "$ARROW_TRAVIS_PYTHON_DOCS" == "1" ] && [ "$PYTHON_VERSION" == "3.6" ];
then
# Install documentation dependencies
conda install -y --file ci/conda_env_sphinx.yml
+ pip install -q -r docs/requirements.txt
fi
# ARROW-2093: PyTorch increases the size of our conda dependency stack
@@ -124,7 +125,7 @@ $ARROW_CPP_BUILD_DIR/$ARROW_BUILD_TYPE/arrow-python-test
pushd $ARROW_PYTHON_DIR
# Other stuff pip install
-pip install -r requirements.txt
+pip install -q -r requirements.txt
if [ "$PYTHON_VERSION" == "3.6" ]; then
pip install -q pickle5
@@ -134,6 +135,9 @@ if [ "$ARROW_TRAVIS_COVERAGE" == "1" ]; then
pip install -q coverage
fi
+echo "=== pip list ==="
+pip list
+
export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:$ARROW_CPP_INSTALL/lib/pkgconfig
export PYARROW_BUILD_TYPE=$ARROW_BUILD_TYPE
diff --git a/cpp/src/arrow/CMakeLists.txt b/cpp/src/arrow/CMakeLists.txt
index 244d0b9..1be46b5 100644
--- a/cpp/src/arrow/CMakeLists.txt
+++ b/cpp/src/arrow/CMakeLists.txt
@@ -101,6 +101,7 @@ set(ARROW_SRCS
io/memory.cc
io/readahead.cc
+ util/basic_decimal.cc
util/bit-util.cc
util/compression.cc
util/cpu-info.cc
diff --git a/cpp/src/arrow/util/basic_decimal.cc
b/cpp/src/arrow/util/basic_decimal.cc
new file mode 100644
index 0000000..bb235f4
--- /dev/null
+++ b/cpp/src/arrow/util/basic_decimal.cc
@@ -0,0 +1,690 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "arrow/util/basic_decimal.h"
+
+#include <algorithm>
+#include <array>
+#include <climits>
+#include <cstdint>
+#include <cstdlib>
+#include <cstring>
+#include <iomanip>
+#include <limits>
+#include <string>
+
+#include "arrow/util/bit-util.h"
+#include "arrow/util/int-util.h"
+#include "arrow/util/logging.h"
+#include "arrow/util/macros.h"
+
+namespace arrow {
+
+using internal::SafeLeftShift;
+using internal::SafeSignedAdd;
+
+static const BasicDecimal128 ScaleMultipliers[] = {
+ BasicDecimal128(1LL),
+ BasicDecimal128(10LL),
+ BasicDecimal128(100LL),
+ BasicDecimal128(1000LL),
+ BasicDecimal128(10000LL),
+ BasicDecimal128(100000LL),
+ BasicDecimal128(1000000LL),
+ BasicDecimal128(10000000LL),
+ BasicDecimal128(100000000LL),
+ BasicDecimal128(1000000000LL),
+ BasicDecimal128(10000000000LL),
+ BasicDecimal128(100000000000LL),
+ BasicDecimal128(1000000000000LL),
+ BasicDecimal128(10000000000000LL),
+ BasicDecimal128(100000000000000LL),
+ BasicDecimal128(1000000000000000LL),
+ BasicDecimal128(10000000000000000LL),
+ BasicDecimal128(100000000000000000LL),
+ BasicDecimal128(1000000000000000000LL),
+ BasicDecimal128(0LL, 10000000000000000000ULL),
+ BasicDecimal128(5LL, 7766279631452241920ULL),
+ BasicDecimal128(54LL, 3875820019684212736ULL),
+ BasicDecimal128(542LL, 1864712049423024128ULL),
+ BasicDecimal128(5421LL, 200376420520689664ULL),
+ BasicDecimal128(54210LL, 2003764205206896640ULL),
+ BasicDecimal128(542101LL, 1590897978359414784ULL),
+ BasicDecimal128(5421010LL, 15908979783594147840ULL),
+ BasicDecimal128(54210108LL, 11515845246265065472ULL),
+ BasicDecimal128(542101086LL, 4477988020393345024ULL),
+ BasicDecimal128(5421010862LL, 7886392056514347008ULL),
+ BasicDecimal128(54210108624LL, 5076944270305263616ULL),
+ BasicDecimal128(542101086242LL, 13875954555633532928ULL),
+ BasicDecimal128(5421010862427LL, 9632337040368467968ULL),
+ BasicDecimal128(54210108624275LL, 4089650035136921600ULL),
+ BasicDecimal128(542101086242752LL, 4003012203950112768ULL),
+ BasicDecimal128(5421010862427522LL, 3136633892082024448ULL),
+ BasicDecimal128(54210108624275221LL, 12919594847110692864ULL),
+ BasicDecimal128(542101086242752217LL, 68739955140067328ULL),
+ BasicDecimal128(5421010862427522170LL, 687399551400673280ULL)};
+
+static const BasicDecimal128 ScaleMultipliersHalf[] = {
+ BasicDecimal128(0ULL),
+ BasicDecimal128(5ULL),
+ BasicDecimal128(50ULL),
+ BasicDecimal128(500ULL),
+ BasicDecimal128(5000ULL),
+ BasicDecimal128(50000ULL),
+ BasicDecimal128(500000ULL),
+ BasicDecimal128(5000000ULL),
+ BasicDecimal128(50000000ULL),
+ BasicDecimal128(500000000ULL),
+ BasicDecimal128(5000000000ULL),
+ BasicDecimal128(50000000000ULL),
+ BasicDecimal128(500000000000ULL),
+ BasicDecimal128(5000000000000ULL),
+ BasicDecimal128(50000000000000ULL),
+ BasicDecimal128(500000000000000ULL),
+ BasicDecimal128(5000000000000000ULL),
+ BasicDecimal128(50000000000000000ULL),
+ BasicDecimal128(500000000000000000ULL),
+ BasicDecimal128(5000000000000000000ULL),
+ BasicDecimal128(2LL, 13106511852580896768ULL),
+ BasicDecimal128(27LL, 1937910009842106368ULL),
+ BasicDecimal128(271LL, 932356024711512064ULL),
+ BasicDecimal128(2710LL, 9323560247115120640ULL),
+ BasicDecimal128(27105LL, 1001882102603448320ULL),
+ BasicDecimal128(271050LL, 10018821026034483200ULL),
+ BasicDecimal128(2710505LL, 7954489891797073920ULL),
+ BasicDecimal128(27105054LL, 5757922623132532736ULL),
+ BasicDecimal128(271050543LL, 2238994010196672512ULL),
+ BasicDecimal128(2710505431LL, 3943196028257173504ULL),
+ BasicDecimal128(27105054312LL, 2538472135152631808ULL),
+ BasicDecimal128(271050543121LL, 6937977277816766464ULL),
+ BasicDecimal128(2710505431213LL, 14039540557039009792ULL),
+ BasicDecimal128(27105054312137LL, 11268197054423236608ULL),
+ BasicDecimal128(271050543121376LL, 2001506101975056384ULL),
+ BasicDecimal128(2710505431213761LL, 1568316946041012224ULL),
+ BasicDecimal128(27105054312137610LL, 15683169460410122240ULL),
+ BasicDecimal128(271050543121376108LL, 9257742014424809472ULL),
+ BasicDecimal128(2710505431213761085LL, 343699775700336640ULL)};
+
+static constexpr uint64_t kIntMask = 0xFFFFFFFF;
+static constexpr auto kCarryBit = static_cast<uint64_t>(1) <<
static_cast<uint64_t>(32);
+
+BasicDecimal128::BasicDecimal128(const uint8_t* bytes)
+ : BasicDecimal128(
+ BitUtil::FromLittleEndian(reinterpret_cast<const
int64_t*>(bytes)[1]),
+ BitUtil::FromLittleEndian(reinterpret_cast<const
uint64_t*>(bytes)[0])) {}
+
+std::array<uint8_t, 16> BasicDecimal128::ToBytes() const {
+ std::array<uint8_t, 16> out{{0}};
+ ToBytes(out.data());
+ return out;
+}
+
+void BasicDecimal128::ToBytes(uint8_t* out) const {
+ DCHECK_NE(out, nullptr);
+ reinterpret_cast<uint64_t*>(out)[0] = BitUtil::ToLittleEndian(low_bits_);
+ reinterpret_cast<int64_t*>(out)[1] = BitUtil::ToLittleEndian(high_bits_);
+}
+
+BasicDecimal128& BasicDecimal128::Negate() {
+ low_bits_ = ~low_bits_ + 1;
+ high_bits_ = ~high_bits_;
+ if (low_bits_ == 0) {
+ high_bits_ = SafeSignedAdd<int64_t>(high_bits_, 1);
+ }
+ return *this;
+}
+
+BasicDecimal128& BasicDecimal128::Abs() { return *this < 0 ? Negate() : *this;
}
+
+BasicDecimal128& BasicDecimal128::operator+=(const BasicDecimal128& right) {
+ const uint64_t sum = low_bits_ + right.low_bits_;
+ high_bits_ = SafeSignedAdd<int64_t>(high_bits_, right.high_bits_);
+ if (sum < low_bits_) {
+ high_bits_ = SafeSignedAdd<int64_t>(high_bits_, 1);
+ }
+ low_bits_ = sum;
+ return *this;
+}
+
+BasicDecimal128& BasicDecimal128::operator-=(const BasicDecimal128& right) {
+ const uint64_t diff = low_bits_ - right.low_bits_;
+ high_bits_ -= right.high_bits_;
+ if (diff > low_bits_) {
+ --high_bits_;
+ }
+ low_bits_ = diff;
+ return *this;
+}
+
+BasicDecimal128& BasicDecimal128::operator/=(const BasicDecimal128& right) {
+ BasicDecimal128 remainder;
+ auto s = Divide(right, this, &remainder);
+ DCHECK_EQ(s, DecimalStatus::kSuccess);
+ return *this;
+}
+
+BasicDecimal128& BasicDecimal128::operator|=(const BasicDecimal128& right) {
+ low_bits_ |= right.low_bits_;
+ high_bits_ |= right.high_bits_;
+ return *this;
+}
+
+BasicDecimal128& BasicDecimal128::operator&=(const BasicDecimal128& right) {
+ low_bits_ &= right.low_bits_;
+ high_bits_ &= right.high_bits_;
+ return *this;
+}
+
+BasicDecimal128& BasicDecimal128::operator<<=(uint32_t bits) {
+ if (bits != 0) {
+ if (bits < 64) {
+ high_bits_ = SafeLeftShift(high_bits_, bits);
+ high_bits_ |= (low_bits_ >> (64 - bits));
+ low_bits_ <<= bits;
+ } else if (bits < 128) {
+ high_bits_ = static_cast<int64_t>(low_bits_) << (bits - 64);
+ low_bits_ = 0;
+ } else {
+ high_bits_ = 0;
+ low_bits_ = 0;
+ }
+ }
+ return *this;
+}
+
+BasicDecimal128& BasicDecimal128::operator>>=(uint32_t bits) {
+ if (bits != 0) {
+ if (bits < 64) {
+ low_bits_ >>= bits;
+ low_bits_ |= static_cast<uint64_t>(high_bits_ << (64 - bits));
+ high_bits_ = static_cast<int64_t>(static_cast<uint64_t>(high_bits_) >>
bits);
+ } else if (bits < 128) {
+ low_bits_ = static_cast<uint64_t>(high_bits_ >> (bits - 64));
+ high_bits_ = static_cast<int64_t>(high_bits_ >= 0L ? 0L : -1L);
+ } else {
+ high_bits_ = static_cast<int64_t>(high_bits_ >= 0L ? 0L : -1L);
+ low_bits_ = static_cast<uint64_t>(high_bits_);
+ }
+ }
+ return *this;
+}
+
+BasicDecimal128& BasicDecimal128::operator*=(const BasicDecimal128& right) {
+ // Break the left and right numbers into 32 bit chunks
+ // so that we can multiply them without overflow.
+ const uint64_t L0 = static_cast<uint64_t>(high_bits_) >> 32;
+ const uint64_t L1 = static_cast<uint64_t>(high_bits_) & kIntMask;
+ const uint64_t L2 = low_bits_ >> 32;
+ const uint64_t L3 = low_bits_ & kIntMask;
+
+ const uint64_t R0 = static_cast<uint64_t>(right.high_bits_) >> 32;
+ const uint64_t R1 = static_cast<uint64_t>(right.high_bits_) & kIntMask;
+ const uint64_t R2 = right.low_bits_ >> 32;
+ const uint64_t R3 = right.low_bits_ & kIntMask;
+
+ uint64_t product = L3 * R3;
+ low_bits_ = product & kIntMask;
+
+ uint64_t sum = product >> 32;
+
+ product = L2 * R3;
+ sum += product;
+
+ product = L3 * R2;
+ sum += product;
+
+ low_bits_ += sum << 32;
+
+ high_bits_ = static_cast<int64_t>(sum < product ? kCarryBit : 0);
+ if (sum < product) {
+ high_bits_ += kCarryBit;
+ }
+
+ high_bits_ += static_cast<int64_t>(sum >> 32);
+ high_bits_ += L1 * R3 + L2 * R2 + L3 * R1;
+ high_bits_ += (L0 * R3 + L1 * R2 + L2 * R1 + L3 * R0) << 32;
+ return *this;
+}
+
+/// Expands the given value into an array of ints so that we can work on
+/// it. The array will be converted to an absolute value and the wasNegative
+/// flag will be set appropriately. The array will remove leading zeros from
+/// the value.
+/// \param array an array of length 4 to set with the value
+/// \param was_negative a flag for whether the value was original negative
+/// \result the output length of the array
+static int64_t FillInArray(const BasicDecimal128& value, uint32_t* array,
+ bool& was_negative) {
+ uint64_t high;
+ uint64_t low;
+ const int64_t highbits = value.high_bits();
+ const uint64_t lowbits = value.low_bits();
+
+ if (highbits < 0) {
+ low = ~lowbits + 1;
+ high = static_cast<uint64_t>(~highbits);
+ if (low == 0) {
+ ++high;
+ }
+ was_negative = true;
+ } else {
+ low = lowbits;
+ high = static_cast<uint64_t>(highbits);
+ was_negative = false;
+ }
+
+ if (high != 0) {
+ if (high > std::numeric_limits<uint32_t>::max()) {
+ array[0] = static_cast<uint32_t>(high >> 32);
+ array[1] = static_cast<uint32_t>(high);
+ array[2] = static_cast<uint32_t>(low >> 32);
+ array[3] = static_cast<uint32_t>(low);
+ return 4;
+ }
+
+ array[0] = static_cast<uint32_t>(high);
+ array[1] = static_cast<uint32_t>(low >> 32);
+ array[2] = static_cast<uint32_t>(low);
+ return 3;
+ }
+
+ if (low >= std::numeric_limits<uint32_t>::max()) {
+ array[0] = static_cast<uint32_t>(low >> 32);
+ array[1] = static_cast<uint32_t>(low);
+ return 2;
+ }
+
+ if (low == 0) {
+ return 0;
+ }
+
+ array[0] = static_cast<uint32_t>(low);
+ return 1;
+}
+
+/// Shift the number in the array left by bits positions.
+/// \param array the number to shift, must have length elements
+/// \param length the number of entries in the array
+/// \param bits the number of bits to shift (0 <= bits < 32)
+static void ShiftArrayLeft(uint32_t* array, int64_t length, int64_t bits) {
+ if (length > 0 && bits != 0) {
+ for (int64_t i = 0; i < length - 1; ++i) {
+ array[i] = (array[i] << bits) | (array[i + 1] >> (32 - bits));
+ }
+ array[length - 1] <<= bits;
+ }
+}
+
+/// Shift the number in the array right by bits positions.
+/// \param array the number to shift, must have length elements
+/// \param length the number of entries in the array
+/// \param bits the number of bits to shift (0 <= bits < 32)
+static void ShiftArrayRight(uint32_t* array, int64_t length, int64_t bits) {
+ if (length > 0 && bits != 0) {
+ for (int64_t i = length - 1; i > 0; --i) {
+ array[i] = (array[i] >> bits) | (array[i - 1] << (32 - bits));
+ }
+ array[0] >>= bits;
+ }
+}
+
+/// \brief Fix the signs of the result and remainder at the end of the
division based on
+/// the signs of the dividend and divisor.
+static void FixDivisionSigns(BasicDecimal128* result, BasicDecimal128*
remainder,
+ bool dividend_was_negative, bool
divisor_was_negative) {
+ if (dividend_was_negative != divisor_was_negative) {
+ result->Negate();
+ }
+
+ if (dividend_was_negative) {
+ remainder->Negate();
+ }
+}
+
+/// \brief Build a BasicDecimal128 from a list of ints.
+static DecimalStatus BuildFromArray(BasicDecimal128* value, uint32_t* array,
+ int64_t length) {
+ switch (length) {
+ case 0:
+ *value = {static_cast<int64_t>(0)};
+ break;
+ case 1:
+ *value = {static_cast<int64_t>(array[0])};
+ break;
+ case 2:
+ *value = {static_cast<int64_t>(0),
+ (static_cast<uint64_t>(array[0]) << 32) + array[1]};
+ break;
+ case 3:
+ *value = {static_cast<int64_t>(array[0]),
+ (static_cast<uint64_t>(array[1]) << 32) + array[2]};
+ break;
+ case 4:
+ *value = {(static_cast<int64_t>(array[0]) << 32) + array[1],
+ (static_cast<uint64_t>(array[2]) << 32) + array[3]};
+ break;
+ case 5:
+ if (array[0] != 0) {
+ return DecimalStatus::kOverflow;
+ }
+ *value = {(static_cast<int64_t>(array[1]) << 32) + array[2],
+ (static_cast<uint64_t>(array[3]) << 32) + array[4]};
+ break;
+ default:
+ return DecimalStatus::kOverflow;
+ }
+
+ return DecimalStatus::kSuccess;
+}
+
+/// \brief Do a division where the divisor fits into a single 32 bit value.
+static DecimalStatus SingleDivide(const uint32_t* dividend, int64_t
dividend_length,
+ uint32_t divisor, BasicDecimal128* remainder,
+ bool dividend_was_negative, bool
divisor_was_negative,
+ BasicDecimal128* result) {
+ uint64_t r = 0;
+ uint32_t result_array[5];
+ for (int64_t j = 0; j < dividend_length; j++) {
+ r <<= 32;
+ r += dividend[j];
+ result_array[j] = static_cast<uint32_t>(r / divisor);
+ r %= divisor;
+ }
+ auto status = BuildFromArray(result, result_array, dividend_length);
+ if (status != DecimalStatus::kSuccess) {
+ return status;
+ }
+
+ *remainder = static_cast<int64_t>(r);
+ FixDivisionSigns(result, remainder, dividend_was_negative,
divisor_was_negative);
+ return DecimalStatus::kSuccess;
+}
+
+DecimalStatus BasicDecimal128::Divide(const BasicDecimal128& divisor,
+ BasicDecimal128* result,
+ BasicDecimal128* remainder) const {
+ // Split the dividend and divisor into integer pieces so that we can
+ // work on them.
+ uint32_t dividend_array[5];
+ uint32_t divisor_array[4];
+ bool dividend_was_negative;
+ bool divisor_was_negative;
+ // leave an extra zero before the dividend
+ dividend_array[0] = 0;
+ int64_t dividend_length =
+ FillInArray(*this, dividend_array + 1, dividend_was_negative) + 1;
+ int64_t divisor_length = FillInArray(divisor, divisor_array,
divisor_was_negative);
+
+ // Handle some of the easy cases.
+ if (dividend_length <= divisor_length) {
+ *remainder = *this;
+ *result = 0;
+ return DecimalStatus::kSuccess;
+ }
+
+ if (divisor_length == 0) {
+ return DecimalStatus::kDivideByZero;
+ }
+
+ if (divisor_length == 1) {
+ return SingleDivide(dividend_array, dividend_length, divisor_array[0],
remainder,
+ dividend_was_negative, divisor_was_negative, result);
+ }
+
+ int64_t result_length = dividend_length - divisor_length;
+ uint32_t result_array[4];
+
+ // Normalize by shifting both by a multiple of 2 so that
+ // the digit guessing is better. The requirement is that
+ // divisor_array[0] is greater than 2**31.
+ int64_t normalize_bits = BitUtil::CountLeadingZeros(divisor_array[0]);
+ ShiftArrayLeft(divisor_array, divisor_length, normalize_bits);
+ ShiftArrayLeft(dividend_array, dividend_length, normalize_bits);
+
+ // compute each digit in the result
+ for (int64_t j = 0; j < result_length; ++j) {
+ // Guess the next digit. At worst it is two too large
+ uint32_t guess = std::numeric_limits<uint32_t>::max();
+ const auto high_dividend =
+ static_cast<uint64_t>(dividend_array[j]) << 32 | dividend_array[j + 1];
+ if (dividend_array[j] != divisor_array[0]) {
+ guess = static_cast<uint32_t>(high_dividend / divisor_array[0]);
+ }
+
+ // catch all of the cases where guess is two too large and most of the
+ // cases where it is one too large
+ auto rhat = static_cast<uint32_t>(high_dividend -
+ guess *
static_cast<uint64_t>(divisor_array[0]));
+ while (static_cast<uint64_t>(divisor_array[1]) * guess >
+ (static_cast<uint64_t>(rhat) << 32) + dividend_array[j + 2]) {
+ --guess;
+ rhat += divisor_array[0];
+ if (static_cast<uint64_t>(rhat) < divisor_array[0]) {
+ break;
+ }
+ }
+
+ // subtract off the guess * divisor from the dividend
+ uint64_t mult = 0;
+ for (int64_t i = divisor_length - 1; i >= 0; --i) {
+ mult += static_cast<uint64_t>(guess) * divisor_array[i];
+ uint32_t prev = dividend_array[j + i + 1];
+ dividend_array[j + i + 1] -= static_cast<uint32_t>(mult);
+ mult >>= 32;
+ if (dividend_array[j + i + 1] > prev) {
+ ++mult;
+ }
+ }
+ uint32_t prev = dividend_array[j];
+ dividend_array[j] -= static_cast<uint32_t>(mult);
+
+ // if guess was too big, we add back divisor
+ if (dividend_array[j] > prev) {
+ --guess;
+ uint32_t carry = 0;
+ for (int64_t i = divisor_length - 1; i >= 0; --i) {
+ const auto sum =
+ static_cast<uint64_t>(divisor_array[i]) + dividend_array[j + i +
1] + carry;
+ dividend_array[j + i + 1] = static_cast<uint32_t>(sum);
+ carry = static_cast<uint32_t>(sum >> 32);
+ }
+ dividend_array[j] += carry;
+ }
+
+ result_array[j] = guess;
+ }
+
+ // denormalize the remainder
+ ShiftArrayRight(dividend_array, dividend_length, normalize_bits);
+
+ // return result and remainder
+ auto status = BuildFromArray(result, result_array, result_length);
+ if (status != DecimalStatus::kSuccess) {
+ return status;
+ }
+ status = BuildFromArray(remainder, dividend_array, dividend_length);
+ if (status != DecimalStatus::kSuccess) {
+ return status;
+ }
+
+ FixDivisionSigns(result, remainder, dividend_was_negative,
divisor_was_negative);
+ return DecimalStatus::kSuccess;
+}
+
+bool operator==(const BasicDecimal128& left, const BasicDecimal128& right) {
+ return left.high_bits() == right.high_bits() && left.low_bits() ==
right.low_bits();
+}
+
+bool operator!=(const BasicDecimal128& left, const BasicDecimal128& right) {
+ return !operator==(left, right);
+}
+
+bool operator<(const BasicDecimal128& left, const BasicDecimal128& right) {
+ return left.high_bits() < right.high_bits() ||
+ (left.high_bits() == right.high_bits() && left.low_bits() <
right.low_bits());
+}
+
+bool operator<=(const BasicDecimal128& left, const BasicDecimal128& right) {
+ return !operator>(left, right);
+}
+
+bool operator>(const BasicDecimal128& left, const BasicDecimal128& right) {
+ return operator<(right, left);
+}
+
+bool operator>=(const BasicDecimal128& left, const BasicDecimal128& right) {
+ return !operator<(left, right);
+}
+
+BasicDecimal128 operator-(const BasicDecimal128& operand) {
+ BasicDecimal128 result(operand.high_bits(), operand.low_bits());
+ return result.Negate();
+}
+
+BasicDecimal128 operator~(const BasicDecimal128& operand) {
+ BasicDecimal128 result(~operand.high_bits(), ~operand.low_bits());
+ return result;
+}
+
+BasicDecimal128 operator+(const BasicDecimal128& left, const BasicDecimal128&
right) {
+ BasicDecimal128 result(left.high_bits(), left.low_bits());
+ result += right;
+ return result;
+}
+
+BasicDecimal128 operator-(const BasicDecimal128& left, const BasicDecimal128&
right) {
+ BasicDecimal128 result(left.high_bits(), left.low_bits());
+ result -= right;
+ return result;
+}
+
+BasicDecimal128 operator*(const BasicDecimal128& left, const BasicDecimal128&
right) {
+ BasicDecimal128 result(left.high_bits(), left.low_bits());
+ result *= right;
+ return result;
+}
+
+BasicDecimal128 operator/(const BasicDecimal128& left, const BasicDecimal128&
right) {
+ BasicDecimal128 remainder;
+ BasicDecimal128 result;
+ auto s = left.Divide(right, &result, &remainder);
+ DCHECK_EQ(s, DecimalStatus::kSuccess);
+ return result;
+}
+
+BasicDecimal128 operator%(const BasicDecimal128& left, const BasicDecimal128&
right) {
+ BasicDecimal128 remainder;
+ BasicDecimal128 result;
+ auto s = left.Divide(right, &result, &remainder);
+ DCHECK_EQ(s, DecimalStatus::kSuccess);
+ return remainder;
+}
+
+static bool RescaleWouldCauseDataLoss(const BasicDecimal128& value, int32_t
delta_scale,
+ int32_t abs_delta_scale,
BasicDecimal128* result) {
+ BasicDecimal128 multiplier(ScaleMultipliers[abs_delta_scale]);
+
+ if (delta_scale < 0) {
+ DCHECK_NE(multiplier, 0);
+ BasicDecimal128 remainder;
+ auto status = value.Divide(multiplier, result, &remainder);
+ DCHECK_EQ(status, DecimalStatus::kSuccess);
+ return remainder != 0;
+ }
+
+ *result = value * multiplier;
+ return (value < 0) ? *result > value : *result < value;
+}
+
+DecimalStatus BasicDecimal128::Rescale(int32_t original_scale, int32_t
new_scale,
+ BasicDecimal128* out) const {
+ DCHECK_NE(out, nullptr);
+ DCHECK_NE(original_scale, new_scale);
+
+ const int32_t delta_scale = new_scale - original_scale;
+ const int32_t abs_delta_scale = std::abs(delta_scale);
+
+ DCHECK_GE(abs_delta_scale, 1);
+ DCHECK_LE(abs_delta_scale, 38);
+
+ BasicDecimal128 result(*this);
+ const bool rescale_would_cause_data_loss =
+ RescaleWouldCauseDataLoss(result, delta_scale, abs_delta_scale, out);
+
+ // Fail if we overflow or truncate
+ if (ARROW_PREDICT_FALSE(rescale_would_cause_data_loss)) {
+ return DecimalStatus::kRescaleDataLoss;
+ }
+
+ return DecimalStatus::kSuccess;
+}
+
+void BasicDecimal128::GetWholeAndFraction(int scale, BasicDecimal128* whole,
+ BasicDecimal128* fraction) const {
+ DCHECK_GE(scale, 0);
+ DCHECK_LE(scale, 38);
+
+ BasicDecimal128 multiplier(ScaleMultipliers[scale]);
+ DCHECK_EQ(Divide(multiplier, whole, fraction), DecimalStatus::kSuccess);
+}
+
+const BasicDecimal128& BasicDecimal128::GetScaleMultiplier(int32_t scale) {
+ DCHECK_GE(scale, 0);
+ DCHECK_LE(scale, 38);
+
+ return ScaleMultipliers[scale];
+}
+
+BasicDecimal128 BasicDecimal128::IncreaseScaleBy(int32_t increase_by) const {
+ DCHECK_GE(increase_by, 0);
+ DCHECK_LE(increase_by, 38);
+
+ return (*this) * ScaleMultipliers[increase_by];
+}
+
+BasicDecimal128 BasicDecimal128::ReduceScaleBy(int32_t reduce_by, bool round)
const {
+ DCHECK_GE(reduce_by, 0);
+ DCHECK_LE(reduce_by, 38);
+
+ BasicDecimal128 divisor(ScaleMultipliers[reduce_by]);
+ BasicDecimal128 result;
+ BasicDecimal128 remainder;
+ DCHECK_EQ(Divide(divisor, &result, &remainder), DecimalStatus::kSuccess);
+ if (round) {
+ auto divisor_half = ScaleMultipliersHalf[reduce_by];
+ if (remainder.Abs() >= divisor_half) {
+ if (result > 0) {
+ result += 1;
+ } else {
+ result -= 1;
+ }
+ }
+ }
+ return result;
+}
+
+int32_t BasicDecimal128::CountLeadingBinaryZeros() const {
+ DCHECK_GE(*this, BasicDecimal128(0));
+
+ if (high_bits_ == 0) {
+ return BitUtil::CountLeadingZeros(low_bits_) + 64;
+ } else {
+ return BitUtil::CountLeadingZeros(static_cast<uint64_t>(high_bits_));
+ }
+}
+
+} // namespace arrow
diff --git a/cpp/src/arrow/util/basic_decimal.h
b/cpp/src/arrow/util/basic_decimal.h
new file mode 100644
index 0000000..e19cb14
--- /dev/null
+++ b/cpp/src/arrow/util/basic_decimal.h
@@ -0,0 +1,166 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#pragma once
+
+#include <array>
+#include <cstdint>
+#include <limits>
+#include <string>
+#include <type_traits>
+
+#include "arrow/util/macros.h"
+#include "arrow/util/type_traits.h"
+#include "arrow/util/visibility.h"
+
+namespace arrow {
+
+enum class DecimalStatus {
+ kSuccess,
+ kDivideByZero,
+ kOverflow,
+ kRescaleDataLoss,
+};
+
+/// Represents a signed 128-bit integer in two's complement.
+///
+/// This class is also compiled into LLVM IR - so, it should not have cpp
references like
+/// streams and boost.
+class ARROW_EXPORT BasicDecimal128 {
+ public:
+ /// \brief Create a BasicDecimal128 from the two's complement representation.
+ constexpr BasicDecimal128(int64_t high, uint64_t low) noexcept
+ : low_bits_(low), high_bits_(high) {}
+
+ /// \brief Empty constructor creates a BasicDecimal128 with a value of 0.
+ constexpr BasicDecimal128() noexcept : BasicDecimal128(0, 0) {}
+
+ /// \brief Convert any integer value into a BasicDecimal128.
+ template <typename T,
+ typename = typename std::enable_if<std::is_integral<T>::value,
T>::type>
+ constexpr BasicDecimal128(T value) noexcept
+ : BasicDecimal128(static_cast<int64_t>(value) >= 0 ? 0 : -1,
+ static_cast<uint64_t>(value)) {}
+
+ /// \brief Create a BasicDecimal128 from an array of bytes. Bytes are
assumed to be in
+ /// little-endian byte order.
+ explicit BasicDecimal128(const uint8_t* bytes);
+
+ /// \brief Negate the current value (in-place)
+ BasicDecimal128& Negate();
+
+ /// \brief Absolute value (in-place)
+ BasicDecimal128& Abs();
+
+ /// \brief Add a number to this one. The result is truncated to 128 bits.
+ BasicDecimal128& operator+=(const BasicDecimal128& right);
+
+ /// \brief Subtract a number from this one. The result is truncated to 128
bits.
+ BasicDecimal128& operator-=(const BasicDecimal128& right);
+
+ /// \brief Multiply this number by another number. The result is truncated
to 128 bits.
+ BasicDecimal128& operator*=(const BasicDecimal128& right);
+
+ /// Divide this number by right and return the result.
+ ///
+ /// This operation is not destructive.
+ /// The answer rounds to zero. Signs work like:
+ /// 21 / 5 -> 4, 1
+ /// -21 / 5 -> -4, -1
+ /// 21 / -5 -> -4, 1
+ /// -21 / -5 -> 4, -1
+ /// \param[in] divisor the number to divide by
+ /// \param[out] result the quotient
+ /// \param[out] remainder the remainder after the division
+ DecimalStatus Divide(const BasicDecimal128& divisor, BasicDecimal128* result,
+ BasicDecimal128* remainder) const;
+
+ /// \brief In-place division.
+ BasicDecimal128& operator/=(const BasicDecimal128& right);
+
+ /// \brief Bitwise "or" between two BasicDecimal128.
+ BasicDecimal128& operator|=(const BasicDecimal128& right);
+
+ /// \brief Bitwise "and" between two BasicDecimal128.
+ BasicDecimal128& operator&=(const BasicDecimal128& right);
+
+ /// \brief Shift left by the given number of bits.
+ BasicDecimal128& operator<<=(uint32_t bits);
+
+ /// \brief Shift right by the given number of bits. Negative values will
+ BasicDecimal128& operator>>=(uint32_t bits);
+
+ /// \brief Get the high bits of the two's complement representation of the
number.
+ inline int64_t high_bits() const { return high_bits_; }
+
+ /// \brief Get the low bits of the two's complement representation of the
number.
+ inline uint64_t low_bits() const { return low_bits_; }
+
+ /// \brief Return the raw bytes of the value in little-endian byte order.
+ std::array<uint8_t, 16> ToBytes() const;
+ void ToBytes(uint8_t* out) const;
+
+ /// \brief seperate the integer and fractional parts for the given scale.
+ void GetWholeAndFraction(int32_t scale, BasicDecimal128* whole,
+ BasicDecimal128* fraction) const;
+
+ /// \brief Scale multiplier for given scale value.
+ static const BasicDecimal128& GetScaleMultiplier(int32_t scale);
+
+ /// \brief Convert BasicDecimal128 from one scale to another
+ DecimalStatus Rescale(int32_t original_scale, int32_t new_scale,
+ BasicDecimal128* out) const;
+
+ /// \brief Scale up.
+ BasicDecimal128 IncreaseScaleBy(int32_t increase_by) const;
+
+ /// \brief Scale down.
+ /// - If 'round' is true, the right-most digits are dropped and the result
value is
+ /// rounded up (+1 for +ve, -1 for -ve) based on the value of the dropped
digits
+ /// (>= 10^reduce_by / 2).
+ /// - If 'round' is false, the right-most digits are simply dropped.
+ BasicDecimal128 ReduceScaleBy(int32_t reduce_by, bool round = true) const;
+
+ /// \brief count the number of leading binary zeroes.
+ int32_t CountLeadingBinaryZeros() const;
+
+ private:
+ uint64_t low_bits_;
+ int64_t high_bits_;
+};
+
+ARROW_EXPORT bool operator==(const BasicDecimal128& left, const
BasicDecimal128& right);
+ARROW_EXPORT bool operator!=(const BasicDecimal128& left, const
BasicDecimal128& right);
+ARROW_EXPORT bool operator<(const BasicDecimal128& left, const
BasicDecimal128& right);
+ARROW_EXPORT bool operator<=(const BasicDecimal128& left, const
BasicDecimal128& right);
+ARROW_EXPORT bool operator>(const BasicDecimal128& left, const
BasicDecimal128& right);
+ARROW_EXPORT bool operator>=(const BasicDecimal128& left, const
BasicDecimal128& right);
+
+ARROW_EXPORT BasicDecimal128 operator-(const BasicDecimal128& operand);
+ARROW_EXPORT BasicDecimal128 operator~(const BasicDecimal128& operand);
+ARROW_EXPORT BasicDecimal128 operator+(const BasicDecimal128& left,
+ const BasicDecimal128& right);
+ARROW_EXPORT BasicDecimal128 operator-(const BasicDecimal128& left,
+ const BasicDecimal128& right);
+ARROW_EXPORT BasicDecimal128 operator*(const BasicDecimal128& left,
+ const BasicDecimal128& right);
+ARROW_EXPORT BasicDecimal128 operator/(const BasicDecimal128& left,
+ const BasicDecimal128& right);
+ARROW_EXPORT BasicDecimal128 operator%(const BasicDecimal128& left,
+ const BasicDecimal128& right);
+
+} // namespace arrow
diff --git a/cpp/src/arrow/util/decimal.cc b/cpp/src/arrow/util/decimal.cc
index 8d6c069..347a07d 100644
--- a/cpp/src/arrow/util/decimal.cc
+++ b/cpp/src/arrow/util/decimal.cc
@@ -38,116 +38,14 @@ namespace arrow {
using internal::SafeLeftShift;
using internal::SafeSignedAdd;
-static const Decimal128 ScaleMultipliers[] = {
- Decimal128(1LL),
- Decimal128(10LL),
- Decimal128(100LL),
- Decimal128(1000LL),
- Decimal128(10000LL),
- Decimal128(100000LL),
- Decimal128(1000000LL),
- Decimal128(10000000LL),
- Decimal128(100000000LL),
- Decimal128(1000000000LL),
- Decimal128(10000000000LL),
- Decimal128(100000000000LL),
- Decimal128(1000000000000LL),
- Decimal128(10000000000000LL),
- Decimal128(100000000000000LL),
- Decimal128(1000000000000000LL),
- Decimal128(10000000000000000LL),
- Decimal128(100000000000000000LL),
- Decimal128(1000000000000000000LL),
- Decimal128(0LL, 10000000000000000000ULL),
- Decimal128(5LL, 7766279631452241920ULL),
- Decimal128(54LL, 3875820019684212736ULL),
- Decimal128(542LL, 1864712049423024128ULL),
- Decimal128(5421LL, 200376420520689664ULL),
- Decimal128(54210LL, 2003764205206896640ULL),
- Decimal128(542101LL, 1590897978359414784ULL),
- Decimal128(5421010LL, 15908979783594147840ULL),
- Decimal128(54210108LL, 11515845246265065472ULL),
- Decimal128(542101086LL, 4477988020393345024ULL),
- Decimal128(5421010862LL, 7886392056514347008ULL),
- Decimal128(54210108624LL, 5076944270305263616ULL),
- Decimal128(542101086242LL, 13875954555633532928ULL),
- Decimal128(5421010862427LL, 9632337040368467968ULL),
- Decimal128(54210108624275LL, 4089650035136921600ULL),
- Decimal128(542101086242752LL, 4003012203950112768ULL),
- Decimal128(5421010862427522LL, 3136633892082024448ULL),
- Decimal128(54210108624275221LL, 12919594847110692864ULL),
- Decimal128(542101086242752217LL, 68739955140067328ULL),
- Decimal128(5421010862427522170LL, 687399551400673280ULL)};
-
-static const Decimal128 ScaleMultipliersHalf[] = {
- Decimal128(0ULL),
- Decimal128(5ULL),
- Decimal128(50ULL),
- Decimal128(500ULL),
- Decimal128(5000ULL),
- Decimal128(50000ULL),
- Decimal128(500000ULL),
- Decimal128(5000000ULL),
- Decimal128(50000000ULL),
- Decimal128(500000000ULL),
- Decimal128(5000000000ULL),
- Decimal128(50000000000ULL),
- Decimal128(500000000000ULL),
- Decimal128(5000000000000ULL),
- Decimal128(50000000000000ULL),
- Decimal128(500000000000000ULL),
- Decimal128(5000000000000000ULL),
- Decimal128(50000000000000000ULL),
- Decimal128(500000000000000000ULL),
- Decimal128(5000000000000000000ULL),
- Decimal128(2LL, 13106511852580896768ULL),
- Decimal128(27LL, 1937910009842106368ULL),
- Decimal128(271LL, 932356024711512064ULL),
- Decimal128(2710LL, 9323560247115120640ULL),
- Decimal128(27105LL, 1001882102603448320ULL),
- Decimal128(271050LL, 10018821026034483200ULL),
- Decimal128(2710505LL, 7954489891797073920ULL),
- Decimal128(27105054LL, 5757922623132532736ULL),
- Decimal128(271050543LL, 2238994010196672512ULL),
- Decimal128(2710505431LL, 3943196028257173504ULL),
- Decimal128(27105054312LL, 2538472135152631808ULL),
- Decimal128(271050543121LL, 6937977277816766464ULL),
- Decimal128(2710505431213LL, 14039540557039009792ULL),
- Decimal128(27105054312137LL, 11268197054423236608ULL),
- Decimal128(271050543121376LL, 2001506101975056384ULL),
- Decimal128(2710505431213761LL, 1568316946041012224ULL),
- Decimal128(27105054312137610LL, 15683169460410122240ULL),
- Decimal128(271050543121376108LL, 9257742014424809472ULL),
- Decimal128(2710505431213761085LL, 343699775700336640ULL)};
-
-static constexpr uint64_t kIntMask = 0xFFFFFFFF;
-static constexpr auto kCarryBit = static_cast<uint64_t>(1) <<
static_cast<uint64_t>(32);
-
Decimal128::Decimal128(const std::string& str) : Decimal128() {
Status status(Decimal128::FromString(str, this));
DCHECK(status.ok()) << status.message();
}
-Decimal128::Decimal128(const uint8_t* bytes)
- : Decimal128(BitUtil::FromLittleEndian(reinterpret_cast<const
int64_t*>(bytes)[1]),
- BitUtil::FromLittleEndian(reinterpret_cast<const
uint64_t*>(bytes)[0])) {
-}
-
-std::array<uint8_t, 16> Decimal128::ToBytes() const {
- std::array<uint8_t, 16> out{{0}};
- ToBytes(out.data());
- return out;
-}
-
-void Decimal128::ToBytes(uint8_t* out) const {
- DCHECK_NE(out, nullptr);
- reinterpret_cast<uint64_t*>(out)[0] = BitUtil::ToLittleEndian(low_bits_);
- reinterpret_cast<int64_t*>(out)[1] = BitUtil::ToLittleEndian(high_bits_);
-}
-
-static constexpr Decimal128 kTenTo36(static_cast<int64_t>(0xC097CE7BC90715),
- 0xB34B9F1000000000);
-static constexpr Decimal128 kTenTo18(0xDE0B6B3A7640000);
+static const Decimal128 kTenTo36(static_cast<int64_t>(0xC097CE7BC90715),
+ 0xB34B9F1000000000);
+static const Decimal128 kTenTo18(0xDE0B6B3A7640000);
std::string Decimal128::ToIntegerString() const {
Decimal128 remainder;
@@ -156,8 +54,7 @@ std::string Decimal128::ToIntegerString() const {
// get anything above 10 ** 36 and print it
Decimal128 top;
- Status s = Divide(kTenTo36, &top, &remainder);
- DCHECK(s.ok()) << s.message();
+ DCHECK_OK(Divide(kTenTo36, &top, &remainder));
if (top != 0) {
buf << static_cast<int64_t>(top);
@@ -167,7 +64,7 @@ std::string Decimal128::ToIntegerString() const {
// now get anything above 10 ** 18 and print it
Decimal128 tail;
- s = remainder.Divide(kTenTo18, &top, &tail);
+ auto s = remainder.Divide(kTenTo18, &top, &tail);
if (need_fill || top != 0) {
if (need_fill) {
@@ -189,11 +86,11 @@ std::string Decimal128::ToIntegerString() const {
}
Decimal128::operator int64_t() const {
- DCHECK(high_bits_ == 0 || high_bits_ == -1)
+ DCHECK(high_bits() == 0 || high_bits() == -1)
<< "Trying to cast an Decimal128 greater than the value range of a "
"int64_t. high_bits_ must be equal to 0 or -1, got: "
- << high_bits_;
- return static_cast<int64_t>(low_bits_);
+ << high_bits();
+ return static_cast<int64_t>(low_bits());
}
static std::string ToStringNegativeScale(const std::string& str,
@@ -424,7 +321,7 @@ Status Decimal128::FromString(const util::string_view& s,
Decimal128* out,
if (scale != nullptr && *scale < 0) {
const int32_t abs_scale = std::abs(*scale);
- *out *= ScaleMultipliers[abs_scale];
+ *out *= GetScaleMultiplier(abs_scale);
if (precision != nullptr) {
*precision += abs_scale;
@@ -446,543 +343,6 @@ Status Decimal128::FromString(const char* s, Decimal128*
out, int32_t* precision
return FromString(util::string_view(s), out, precision, scale);
}
-Decimal128& Decimal128::Negate() {
- low_bits_ = ~low_bits_ + 1;
- high_bits_ = ~high_bits_;
- if (low_bits_ == 0) {
- high_bits_ = SafeSignedAdd<int64_t>(high_bits_, 1);
- }
- return *this;
-}
-
-Decimal128& Decimal128::Abs() { return *this < 0 ? Negate() : *this; }
-
-Decimal128& Decimal128::operator+=(const Decimal128& right) {
- const uint64_t sum = low_bits_ + right.low_bits_;
- high_bits_ = SafeSignedAdd<int64_t>(high_bits_, right.high_bits_);
- if (sum < low_bits_) {
- high_bits_ = SafeSignedAdd<int64_t>(high_bits_, 1);
- }
- low_bits_ = sum;
- return *this;
-}
-
-Decimal128& Decimal128::operator-=(const Decimal128& right) {
- const uint64_t diff = low_bits_ - right.low_bits_;
- high_bits_ -= right.high_bits_;
- if (diff > low_bits_) {
- --high_bits_;
- }
- low_bits_ = diff;
- return *this;
-}
-
-Decimal128& Decimal128::operator/=(const Decimal128& right) {
- Decimal128 remainder;
- Status s = Divide(right, this, &remainder);
- DCHECK(s.ok());
- return *this;
-}
-
-Decimal128& Decimal128::operator|=(const Decimal128& right) {
- low_bits_ |= right.low_bits_;
- high_bits_ |= right.high_bits_;
- return *this;
-}
-
-Decimal128& Decimal128::operator&=(const Decimal128& right) {
- low_bits_ &= right.low_bits_;
- high_bits_ &= right.high_bits_;
- return *this;
-}
-
-Decimal128& Decimal128::operator<<=(uint32_t bits) {
- if (bits != 0) {
- if (bits < 64) {
- high_bits_ = SafeLeftShift(high_bits_, bits);
- high_bits_ |= (low_bits_ >> (64 - bits));
- low_bits_ <<= bits;
- } else if (bits < 128) {
- high_bits_ = static_cast<int64_t>(low_bits_) << (bits - 64);
- low_bits_ = 0;
- } else {
- high_bits_ = 0;
- low_bits_ = 0;
- }
- }
- return *this;
-}
-
-Decimal128& Decimal128::operator>>=(uint32_t bits) {
- if (bits != 0) {
- if (bits < 64) {
- low_bits_ >>= bits;
- low_bits_ |= static_cast<uint64_t>(high_bits_ << (64 - bits));
- high_bits_ = static_cast<int64_t>(static_cast<uint64_t>(high_bits_) >>
bits);
- } else if (bits < 128) {
- low_bits_ = static_cast<uint64_t>(high_bits_ >> (bits - 64));
- high_bits_ = static_cast<int64_t>(high_bits_ >= 0L ? 0L : -1L);
- } else {
- high_bits_ = static_cast<int64_t>(high_bits_ >= 0L ? 0L : -1L);
- low_bits_ = static_cast<uint64_t>(high_bits_);
- }
- }
- return *this;
-}
-
-Decimal128& Decimal128::operator*=(const Decimal128& right) {
- // Break the left and right numbers into 32 bit chunks
- // so that we can multiply them without overflow.
- const uint64_t L0 = static_cast<uint64_t>(high_bits_) >> 32;
- const uint64_t L1 = static_cast<uint64_t>(high_bits_) & kIntMask;
- const uint64_t L2 = low_bits_ >> 32;
- const uint64_t L3 = low_bits_ & kIntMask;
-
- const uint64_t R0 = static_cast<uint64_t>(right.high_bits_) >> 32;
- const uint64_t R1 = static_cast<uint64_t>(right.high_bits_) & kIntMask;
- const uint64_t R2 = right.low_bits_ >> 32;
- const uint64_t R3 = right.low_bits_ & kIntMask;
-
- uint64_t product = L3 * R3;
- low_bits_ = product & kIntMask;
-
- uint64_t sum = product >> 32;
-
- product = L2 * R3;
- sum += product;
-
- product = L3 * R2;
- sum += product;
-
- low_bits_ += sum << 32;
-
- high_bits_ = static_cast<int64_t>(sum < product ? kCarryBit : 0);
- if (sum < product) {
- high_bits_ += kCarryBit;
- }
-
- high_bits_ += static_cast<int64_t>(sum >> 32);
- high_bits_ += L1 * R3 + L2 * R2 + L3 * R1;
- high_bits_ += (L0 * R3 + L1 * R2 + L2 * R1 + L3 * R0) << 32;
- return *this;
-}
-
-/// Expands the given value into an array of ints so that we can work on
-/// it. The array will be converted to an absolute value and the wasNegative
-/// flag will be set appropriately. The array will remove leading zeros from
-/// the value.
-/// \param array an array of length 4 to set with the value
-/// \param was_negative a flag for whether the value was original negative
-/// \result the output length of the array
-static int64_t FillInArray(const Decimal128& value, uint32_t* array, bool&
was_negative) {
- uint64_t high;
- uint64_t low;
- const int64_t highbits = value.high_bits();
- const uint64_t lowbits = value.low_bits();
-
- if (highbits < 0) {
- low = ~lowbits + 1;
- high = static_cast<uint64_t>(~highbits);
- if (low == 0) {
- ++high;
- }
- was_negative = true;
- } else {
- low = lowbits;
- high = static_cast<uint64_t>(highbits);
- was_negative = false;
- }
-
- if (high != 0) {
- if (high > std::numeric_limits<uint32_t>::max()) {
- array[0] = static_cast<uint32_t>(high >> 32);
- array[1] = static_cast<uint32_t>(high);
- array[2] = static_cast<uint32_t>(low >> 32);
- array[3] = static_cast<uint32_t>(low);
- return 4;
- }
-
- array[0] = static_cast<uint32_t>(high);
- array[1] = static_cast<uint32_t>(low >> 32);
- array[2] = static_cast<uint32_t>(low);
- return 3;
- }
-
- if (low >= std::numeric_limits<uint32_t>::max()) {
- array[0] = static_cast<uint32_t>(low >> 32);
- array[1] = static_cast<uint32_t>(low);
- return 2;
- }
-
- if (low == 0) {
- return 0;
- }
-
- array[0] = static_cast<uint32_t>(low);
- return 1;
-}
-
-/// Shift the number in the array left by bits positions.
-/// \param array the number to shift, must have length elements
-/// \param length the number of entries in the array
-/// \param bits the number of bits to shift (0 <= bits < 32)
-static void ShiftArrayLeft(uint32_t* array, int64_t length, int64_t bits) {
- if (length > 0 && bits != 0) {
- for (int64_t i = 0; i < length - 1; ++i) {
- array[i] = (array[i] << bits) | (array[i + 1] >> (32 - bits));
- }
- array[length - 1] <<= bits;
- }
-}
-
-/// Shift the number in the array right by bits positions.
-/// \param array the number to shift, must have length elements
-/// \param length the number of entries in the array
-/// \param bits the number of bits to shift (0 <= bits < 32)
-static void ShiftArrayRight(uint32_t* array, int64_t length, int64_t bits) {
- if (length > 0 && bits != 0) {
- for (int64_t i = length - 1; i > 0; --i) {
- array[i] = (array[i] >> bits) | (array[i - 1] << (32 - bits));
- }
- array[0] >>= bits;
- }
-}
-
-/// \brief Fix the signs of the result and remainder at the end of the
division based on
-/// the signs of the dividend and divisor.
-static void FixDivisionSigns(Decimal128* result, Decimal128* remainder,
- bool dividend_was_negative, bool
divisor_was_negative) {
- if (dividend_was_negative != divisor_was_negative) {
- result->Negate();
- }
-
- if (dividend_was_negative) {
- remainder->Negate();
- }
-}
-
-/// \brief Build a Decimal128 from a list of ints.
-static Status BuildFromArray(Decimal128* value, uint32_t* array, int64_t
length) {
- switch (length) {
- case 0:
- *value = {static_cast<int64_t>(0)};
- break;
- case 1:
- *value = {static_cast<int64_t>(array[0])};
- break;
- case 2:
- *value = {static_cast<int64_t>(0),
- (static_cast<uint64_t>(array[0]) << 32) + array[1]};
- break;
- case 3:
- *value = {static_cast<int64_t>(array[0]),
- (static_cast<uint64_t>(array[1]) << 32) + array[2]};
- break;
- case 4:
- *value = {(static_cast<int64_t>(array[0]) << 32) + array[1],
- (static_cast<uint64_t>(array[2]) << 32) + array[3]};
- break;
- case 5:
- if (array[0] != 0) {
- return Status::Invalid("Can't build Decimal128 with 5 ints.");
- }
- *value = {(static_cast<int64_t>(array[1]) << 32) + array[2],
- (static_cast<uint64_t>(array[3]) << 32) + array[4]};
- break;
- default:
- return Status::Invalid("Unsupported length for building Decimal128");
- }
-
- return Status::OK();
-}
-
-/// \brief Do a division where the divisor fits into a single 32 bit value.
-static Status SingleDivide(const uint32_t* dividend, int64_t dividend_length,
- uint32_t divisor, Decimal128* remainder,
- bool dividend_was_negative, bool
divisor_was_negative,
- Decimal128* result) {
- uint64_t r = 0;
- uint32_t result_array[5];
- for (int64_t j = 0; j < dividend_length; j++) {
- r <<= 32;
- r += dividend[j];
- result_array[j] = static_cast<uint32_t>(r / divisor);
- r %= divisor;
- }
- RETURN_NOT_OK(BuildFromArray(result, result_array, dividend_length));
- *remainder = static_cast<int64_t>(r);
- FixDivisionSigns(result, remainder, dividend_was_negative,
divisor_was_negative);
- return Status::OK();
-}
-
-Status Decimal128::Divide(const Decimal128& divisor, Decimal128* result,
- Decimal128* remainder) const {
- // Split the dividend and divisor into integer pieces so that we can
- // work on them.
- uint32_t dividend_array[5];
- uint32_t divisor_array[4];
- bool dividend_was_negative;
- bool divisor_was_negative;
- // leave an extra zero before the dividend
- dividend_array[0] = 0;
- int64_t dividend_length =
- FillInArray(*this, dividend_array + 1, dividend_was_negative) + 1;
- int64_t divisor_length = FillInArray(divisor, divisor_array,
divisor_was_negative);
-
- // Handle some of the easy cases.
- if (dividend_length <= divisor_length) {
- *remainder = *this;
- *result = 0;
- return Status::OK();
- }
-
- if (divisor_length == 0) {
- return Status::Invalid("Division by 0 in Decimal128");
- }
-
- if (divisor_length == 1) {
- return SingleDivide(dividend_array, dividend_length, divisor_array[0],
remainder,
- dividend_was_negative, divisor_was_negative, result);
- }
-
- int64_t result_length = dividend_length - divisor_length;
- uint32_t result_array[4];
-
- // Normalize by shifting both by a multiple of 2 so that
- // the digit guessing is better. The requirement is that
- // divisor_array[0] is greater than 2**31.
- int64_t normalize_bits = BitUtil::CountLeadingZeros(divisor_array[0]);
- ShiftArrayLeft(divisor_array, divisor_length, normalize_bits);
- ShiftArrayLeft(dividend_array, dividend_length, normalize_bits);
-
- // compute each digit in the result
- for (int64_t j = 0; j < result_length; ++j) {
- // Guess the next digit. At worst it is two too large
- uint32_t guess = std::numeric_limits<uint32_t>::max();
- const auto high_dividend =
- static_cast<uint64_t>(dividend_array[j]) << 32 | dividend_array[j + 1];
- if (dividend_array[j] != divisor_array[0]) {
- guess = static_cast<uint32_t>(high_dividend / divisor_array[0]);
- }
-
- // catch all of the cases where guess is two too large and most of the
- // cases where it is one too large
- auto rhat = static_cast<uint32_t>(high_dividend -
- guess *
static_cast<uint64_t>(divisor_array[0]));
- while (static_cast<uint64_t>(divisor_array[1]) * guess >
- (static_cast<uint64_t>(rhat) << 32) + dividend_array[j + 2]) {
- --guess;
- rhat += divisor_array[0];
- if (static_cast<uint64_t>(rhat) < divisor_array[0]) {
- break;
- }
- }
-
- // subtract off the guess * divisor from the dividend
- uint64_t mult = 0;
- for (int64_t i = divisor_length - 1; i >= 0; --i) {
- mult += static_cast<uint64_t>(guess) * divisor_array[i];
- uint32_t prev = dividend_array[j + i + 1];
- dividend_array[j + i + 1] -= static_cast<uint32_t>(mult);
- mult >>= 32;
- if (dividend_array[j + i + 1] > prev) {
- ++mult;
- }
- }
- uint32_t prev = dividend_array[j];
- dividend_array[j] -= static_cast<uint32_t>(mult);
-
- // if guess was too big, we add back divisor
- if (dividend_array[j] > prev) {
- --guess;
- uint32_t carry = 0;
- for (int64_t i = divisor_length - 1; i >= 0; --i) {
- const auto sum =
- static_cast<uint64_t>(divisor_array[i]) + dividend_array[j + i +
1] + carry;
- dividend_array[j + i + 1] = static_cast<uint32_t>(sum);
- carry = static_cast<uint32_t>(sum >> 32);
- }
- dividend_array[j] += carry;
- }
-
- result_array[j] = guess;
- }
-
- // denormalize the remainder
- ShiftArrayRight(dividend_array, dividend_length, normalize_bits);
-
- // return result and remainder
- RETURN_NOT_OK(BuildFromArray(result, result_array, result_length));
- RETURN_NOT_OK(BuildFromArray(remainder, dividend_array, dividend_length));
-
- FixDivisionSigns(result, remainder, dividend_was_negative,
divisor_was_negative);
- return Status::OK();
-}
-
-bool operator==(const Decimal128& left, const Decimal128& right) {
- return left.high_bits() == right.high_bits() && left.low_bits() ==
right.low_bits();
-}
-
-bool operator!=(const Decimal128& left, const Decimal128& right) {
- return !operator==(left, right);
-}
-
-bool operator<(const Decimal128& left, const Decimal128& right) {
- return left.high_bits() < right.high_bits() ||
- (left.high_bits() == right.high_bits() && left.low_bits() <
right.low_bits());
-}
-
-bool operator<=(const Decimal128& left, const Decimal128& right) {
- return !operator>(left, right);
-}
-
-bool operator>(const Decimal128& left, const Decimal128& right) {
- return operator<(right, left);
-}
-
-bool operator>=(const Decimal128& left, const Decimal128& right) {
- return !operator<(left, right);
-}
-
-Decimal128 operator-(const Decimal128& operand) {
- Decimal128 result(operand.high_bits(), operand.low_bits());
- return result.Negate();
-}
-
-Decimal128 operator~(const Decimal128& operand) {
- Decimal128 result(~operand.high_bits(), ~operand.low_bits());
- return result;
-}
-
-Decimal128 operator+(const Decimal128& left, const Decimal128& right) {
- Decimal128 result(left.high_bits(), left.low_bits());
- result += right;
- return result;
-}
-
-Decimal128 operator-(const Decimal128& left, const Decimal128& right) {
- Decimal128 result(left.high_bits(), left.low_bits());
- result -= right;
- return result;
-}
-
-Decimal128 operator*(const Decimal128& left, const Decimal128& right) {
- Decimal128 result(left.high_bits(), left.low_bits());
- result *= right;
- return result;
-}
-
-Decimal128 operator/(const Decimal128& left, const Decimal128& right) {
- Decimal128 remainder;
- Decimal128 result;
- Status s = left.Divide(right, &result, &remainder);
- DCHECK(s.ok());
- return result;
-}
-
-Decimal128 operator%(const Decimal128& left, const Decimal128& right) {
- Decimal128 remainder;
- Decimal128 result;
- Status s = left.Divide(right, &result, &remainder);
- DCHECK(s.ok());
- return remainder;
-}
-
-static bool RescaleWouldCauseDataLoss(const Decimal128& value, int32_t
delta_scale,
- int32_t abs_delta_scale, Decimal128*
result) {
- Decimal128 multiplier(ScaleMultipliers[abs_delta_scale]);
-
- if (delta_scale < 0) {
- DCHECK_NE(multiplier, 0);
- Decimal128 remainder;
- Status status = value.Divide(multiplier, result, &remainder);
- DCHECK(status.ok()) << status.message();
- return remainder != 0;
- }
-
- *result = value * multiplier;
- return (value < 0) ? *result > value : *result < value;
-}
-
-Status Decimal128::Rescale(int32_t original_scale, int32_t new_scale,
- Decimal128* out) const {
- DCHECK_NE(out, nullptr) << "out is nullptr";
- DCHECK_NE(original_scale, new_scale) << "original_scale != new_scale";
-
- const int32_t delta_scale = new_scale - original_scale;
- const int32_t abs_delta_scale = std::abs(delta_scale);
-
- DCHECK_GE(abs_delta_scale, 1);
- DCHECK_LE(abs_delta_scale, 38);
-
- Decimal128 result(*this);
- const bool rescale_would_cause_data_loss =
- RescaleWouldCauseDataLoss(result, delta_scale, abs_delta_scale, out);
-
- // Fail if we overflow or truncate
- if (ARROW_PREDICT_FALSE(rescale_would_cause_data_loss)) {
- return Status::Invalid("Rescaling decimal value ",
ToString(original_scale),
- " from original scale of ", original_scale,
- " to new scale of ", new_scale, " would cause data
loss");
- }
-
- return Status::OK();
-}
-
-void Decimal128::GetWholeAndFraction(int scale, Decimal128* whole,
- Decimal128* fraction) const {
- DCHECK_GE(scale, 0);
- DCHECK_LE(scale, 38);
-
- Decimal128 multiplier(ScaleMultipliers[scale]);
- DCHECK_OK(Divide(multiplier, whole, fraction));
-}
-
-const Decimal128& Decimal128::GetScaleMultiplier(int32_t scale) {
- DCHECK_GE(scale, 0);
- DCHECK_LE(scale, 38);
-
- return ScaleMultipliers[scale];
-}
-
-Decimal128 Decimal128::IncreaseScaleBy(int32_t increase_by) const {
- DCHECK_GE(increase_by, 0);
- DCHECK_LE(increase_by, 38);
-
- return (*this) * ScaleMultipliers[increase_by];
-}
-
-Decimal128 Decimal128::ReduceScaleBy(int32_t reduce_by, bool round) const {
- DCHECK_GE(reduce_by, 0);
- DCHECK_LE(reduce_by, 38);
-
- Decimal128 divisor(ScaleMultipliers[reduce_by]);
- Decimal128 result;
- Decimal128 remainder;
- DCHECK_OK(Divide(divisor, &result, &remainder));
- if (round) {
- auto divisor_half = ScaleMultipliersHalf[reduce_by];
- if (remainder.Abs() >= divisor_half) {
- if (result > 0) {
- result += 1;
- } else {
- result -= 1;
- }
- }
- }
- return result;
-}
-
-int32_t Decimal128::CountLeadingBinaryZeros() const {
- DCHECK_GE(*this, Decimal128(0));
-
- if (high_bits_ == 0) {
- return BitUtil::CountLeadingZeros(low_bits_) + 64;
- } else {
- return BitUtil::CountLeadingZeros(static_cast<uint64_t>(high_bits_));
- }
-}
-
// Helper function used by Decimal128::FromBigEndian
static inline uint64_t UInt64FromBigEndian(const uint8_t* bytes, int32_t
length) {
// We don't bounds check the length here because this is called by
@@ -1051,4 +411,27 @@ Status Decimal128::FromBigEndian(const uint8_t* bytes,
int32_t length, Decimal12
return Status::OK();
}
+Status Decimal128::ToArrowStatus(DecimalStatus dstatus) const {
+ Status status;
+
+ switch (dstatus) {
+ case DecimalStatus::kSuccess:
+ status = Status::OK();
+ break;
+
+ case DecimalStatus::kDivideByZero:
+ status = Status::Invalid("Division by 0 in Decimal128");
+ break;
+
+ case DecimalStatus::kOverflow:
+ status = Status::Invalid("Overflow occurred during Decimal128
operation.");
+ break;
+
+ case DecimalStatus::kRescaleDataLoss:
+ status = Status::Invalid("Rescaling decimal value would cause data
loss");
+ break;
+ }
+ return status;
+}
+
} // namespace arrow
diff --git a/cpp/src/arrow/util/decimal.h b/cpp/src/arrow/util/decimal.h
index fdc8892..4c61a17 100644
--- a/cpp/src/arrow/util/decimal.h
+++ b/cpp/src/arrow/util/decimal.h
@@ -15,8 +15,7 @@
// specific language governing permissions and limitations
// under the License.
-#ifndef ARROW_DECIMAL_H
-#define ARROW_DECIMAL_H
+#pragma once
#include <array>
#include <cstdint>
@@ -26,10 +25,8 @@
#include <type_traits>
#include "arrow/status.h"
-#include "arrow/util/macros.h"
+#include "arrow/util/basic_decimal.h"
#include "arrow/util/string_view.h"
-#include "arrow/util/type_traits.h"
-#include "arrow/util/visibility.h"
namespace arrow {
@@ -40,43 +37,30 @@ namespace arrow {
/// Semi-numerical Algorithms section 4.3.1.
///
/// Adapted from the Apache ORC C++ implementation
-class ARROW_EXPORT Decimal128 {
+///
+/// The implementation is split into two parts :
+///
+/// 1. BasicDecimal128
+/// - can be safely compiled to IR without references to libstdc++.
+/// 2. Decimal128
+/// - has additional functionality on top of BasicDecimal128 to deal with
+/// strings and streams.
+class ARROW_EXPORT Decimal128 : public BasicDecimal128 {
public:
- /// \brief Create a Decimal128 from the two's complement representation.
- constexpr Decimal128(int64_t high, uint64_t low) noexcept
- : low_bits_(low), high_bits_(high) {}
-
- /// \brief Empty constructor creates a Decimal128 with a value of 0.
- constexpr Decimal128() noexcept : Decimal128(0, 0) {}
+ /// \cond FALSE
+ // (need to avoid a duplicate definition in Sphinx)
+ using BasicDecimal128::BasicDecimal128;
+ /// \endcond
- /// \brief Convert any integer value into a Decimal128.
- template <typename T,
- typename = typename std::enable_if<std::is_integral<T>::value,
T>::type>
- constexpr Decimal128(T value) noexcept
- : Decimal128(static_cast<int64_t>(value) >= 0 ? 0 : -1,
- static_cast<uint64_t>(value)) {}
+ /// \brief constructor creates a Decimal128 from a BasicDecimal128.
+ constexpr Decimal128(const BasicDecimal128& value) noexcept :
BasicDecimal128(value) {}
/// \brief Parse the number from a base 10 string representation.
explicit Decimal128(const std::string& value);
- /// \brief Create a Decimal128 from an array of bytes. Bytes are assumed to
be in
- /// little-endian byte order.
- explicit Decimal128(const uint8_t* bytes);
-
- /// \brief Negate the current value (in-place)
- Decimal128& Negate();
-
- /// \brief Absolute value (in-place)
- Decimal128& Abs();
-
- /// \brief Add a number to this one. The result is truncated to 128 bits.
- Decimal128& operator+=(const Decimal128& right);
-
- /// \brief Subtract a number from this one. The result is truncated to 128
bits.
- Decimal128& operator-=(const Decimal128& right);
-
- /// \brief Multiply this number by another number. The result is truncated
to 128 bits.
- Decimal128& operator*=(const Decimal128& right);
+ /// \brief Empty constructor creates a Decimal128 with a value of 0.
+ // This is required on some older compilers.
+ constexpr Decimal128() noexcept : BasicDecimal128() {}
/// Divide this number by right and return the result.
///
@@ -90,32 +74,10 @@ class ARROW_EXPORT Decimal128 {
/// \param[out] result the quotient
/// \param[out] remainder the remainder after the division
Status Divide(const Decimal128& divisor, Decimal128* result,
- Decimal128* remainder) const;
-
- /// \brief In-place division.
- Decimal128& operator/=(const Decimal128& right);
-
- /// \brief Bitwise "or" between two Decimal128.
- Decimal128& operator|=(const Decimal128& right);
-
- /// \brief Bitwise "and" between two Decimal128.
- Decimal128& operator&=(const Decimal128& right);
-
- /// \brief Shift left by the given number of bits.
- Decimal128& operator<<=(uint32_t bits);
-
- /// \brief Shift right by the given number of bits. Negative values will
- Decimal128& operator>>=(uint32_t bits);
-
- /// \brief Get the high bits of the two's complement representation of the
number.
- inline int64_t high_bits() const { return high_bits_; }
-
- /// \brief Get the low bits of the two's complement representation of the
number.
- inline uint64_t low_bits() const { return low_bits_; }
-
- /// \brief Return the raw bytes of the value in little-endian byte order.
- std::array<uint8_t, 16> ToBytes() const;
- void ToBytes(uint8_t* out) const;
+ Decimal128* remainder) const {
+ auto dstatus = BasicDecimal128::Divide(divisor, result, remainder);
+ return ToArrowStatus(dstatus);
+ }
/// \brief Convert the Decimal128 value to a base 10 decimal string with the
given
/// scale.
@@ -129,10 +91,10 @@ class ARROW_EXPORT Decimal128 {
/// \brief Convert a decimal string to a Decimal128 value, optionally
including
/// precision and scale if they're passed in and not null.
- static Status FromString(const std::string& s, Decimal128* out,
- int32_t* precision = NULLPTR, int32_t* scale =
NULLPTR);
static Status FromString(const util::string_view& s, Decimal128* out,
int32_t* precision = NULLPTR, int32_t* scale =
NULLPTR);
+ static Status FromString(const std::string& s, Decimal128* out,
+ int32_t* precision = NULLPTR, int32_t* scale =
NULLPTR);
static Status FromString(const char* s, Decimal128* out, int32_t* precision
= NULLPTR,
int32_t* scale = NULLPTR);
@@ -141,27 +103,11 @@ class ARROW_EXPORT Decimal128 {
/// \return error status if the length is an invalid value
static Status FromBigEndian(const uint8_t* data, int32_t length, Decimal128*
out);
- /// \brief seperate the integer and fractional parts for the given scale.
- void GetWholeAndFraction(int32_t scale, Decimal128* whole, Decimal128*
fraction) const;
-
- /// \brief Scale multiplier for given scale value.
- static const Decimal128& GetScaleMultiplier(int32_t scale);
-
/// \brief Convert Decimal128 from one scale to another
- Status Rescale(int32_t original_scale, int32_t new_scale, Decimal128* out)
const;
-
- /// \brief Scale up.
- Decimal128 IncreaseScaleBy(int32_t increase_by) const;
-
- /// \brief Scale down.
- /// - If 'round' is true, the right-most digits are dropped and the result
value is
- /// rounded up (+1 for +ve, -1 for -ve) based on the value of the dropped
digits
- /// (>= 10^reduce_by / 2).
- /// - If 'round' is false, the right-most digits are simply dropped.
- Decimal128 ReduceScaleBy(int32_t reduce_by, bool round = true) const;
-
- /// \brief count the number of leading binary zeroes.
- int32_t CountLeadingBinaryZeros() const;
+ Status Rescale(int32_t original_scale, int32_t new_scale, Decimal128* out)
const {
+ auto dstatus = BasicDecimal128::Rescale(original_scale, new_scale, out);
+ return ToArrowStatus(dstatus);
+ }
/// \brief Convert to a signed integer
template <typename T, typename = internal::EnableIfIsOneOf<T, int32_t,
int64_t>>
@@ -173,30 +119,13 @@ class ARROW_EXPORT Decimal128 {
return Status::Invalid("Invalid cast from Decimal128 to ", sizeof(T),
" byte integer");
}
- *out = static_cast<T>(low_bits_);
+ *out = static_cast<T>(low_bits());
return Status::OK();
}
private:
- uint64_t low_bits_;
- int64_t high_bits_;
+ /// Converts internal error code to Status
+ Status ToArrowStatus(DecimalStatus dstatus) const;
};
-ARROW_EXPORT bool operator==(const Decimal128& left, const Decimal128& right);
-ARROW_EXPORT bool operator!=(const Decimal128& left, const Decimal128& right);
-ARROW_EXPORT bool operator<(const Decimal128& left, const Decimal128& right);
-ARROW_EXPORT bool operator<=(const Decimal128& left, const Decimal128& right);
-ARROW_EXPORT bool operator>(const Decimal128& left, const Decimal128& right);
-ARROW_EXPORT bool operator>=(const Decimal128& left, const Decimal128& right);
-
-ARROW_EXPORT Decimal128 operator-(const Decimal128& operand);
-ARROW_EXPORT Decimal128 operator~(const Decimal128& operand);
-ARROW_EXPORT Decimal128 operator+(const Decimal128& left, const Decimal128&
right);
-ARROW_EXPORT Decimal128 operator-(const Decimal128& left, const Decimal128&
right);
-ARROW_EXPORT Decimal128 operator*(const Decimal128& left, const Decimal128&
right);
-ARROW_EXPORT Decimal128 operator/(const Decimal128& left, const Decimal128&
right);
-ARROW_EXPORT Decimal128 operator%(const Decimal128& left, const Decimal128&
right);
-
} // namespace arrow
-
-#endif // ARROW_DECIMAL_H
diff --git a/cpp/src/arrow/util/logging.h b/cpp/src/arrow/util/logging.h
index 42ab18e..5ea7820 100644
--- a/cpp/src/arrow/util/logging.h
+++ b/cpp/src/arrow/util/logging.h
@@ -18,6 +18,24 @@
#ifndef ARROW_UTIL_LOGGING_H
#define ARROW_UTIL_LOGGING_H
+#ifdef GANDIVA_IR
+
+// The LLVM IR code doesn't have an NDEBUG mode. And, it shouldn't include
references to
+// streams or stdc++. So, making the DCHECK calls void in that case.
+
+#define ARROW_IGNORE_EXPR(expr) ((void)(expr))
+
+#define DCHECK(condition) ARROW_IGNORE_EXPR(condition)
+#define DCHECK_OK(status) ARROW_IGNORE_EXPR(status)
+#define DCHECK_EQ(val1, val2) ARROW_IGNORE_EXPR(val1)
+#define DCHECK_NE(val1, val2) ARROW_IGNORE_EXPR(val1)
+#define DCHECK_LE(val1, val2) ARROW_IGNORE_EXPR(val1)
+#define DCHECK_LT(val1, val2) ARROW_IGNORE_EXPR(val1)
+#define DCHECK_GE(val1, val2) ARROW_IGNORE_EXPR(val1)
+#define DCHECK_GT(val1, val2) ARROW_IGNORE_EXPR(val1)
+
+#else // !GANDIVA_IR
+
#include <iostream>
#include <memory>
#include <string>
@@ -185,5 +203,6 @@ class ARROW_EXPORT Voidify {
} // namespace util
} // namespace arrow
+#endif // GANDIVA_IR
#endif // ARROW_UTIL_LOGGING_H
diff --git a/cpp/src/gandiva/decimal_full.h
b/cpp/src/gandiva/basic_decimal_scalar.h
similarity index 52%
rename from cpp/src/gandiva/decimal_full.h
rename to cpp/src/gandiva/basic_decimal_scalar.h
index 3b84da1..fab8227 100644
--- a/cpp/src/gandiva/decimal_full.h
+++ b/cpp/src/gandiva/basic_decimal_scalar.h
@@ -15,61 +15,44 @@
// specific language governing permissions and limitations
// under the License.
-#ifndef DECIMAL_FULL_H
-#define DECIMAL_FULL_H
+#pragma once
#include <cstdint>
-#include <iostream>
-#include <string>
-#include "arrow/util/decimal.h"
+#include "arrow/util/basic_decimal.h"
namespace gandiva {
-using Decimal128 = arrow::Decimal128;
+using arrow::BasicDecimal128;
/// Represents a 128-bit decimal value along with its precision and scale.
-class Decimal128Full {
+class BasicDecimalScalar128 {
public:
- Decimal128Full(int64_t high_bits, uint64_t low_bits, int32_t precision,
int32_t scale)
+ BasicDecimalScalar128(int64_t high_bits, uint64_t low_bits, int32_t
precision,
+ int32_t scale)
: value_(high_bits, low_bits), precision_(precision), scale_(scale) {}
- Decimal128Full(std::string value, int32_t precision, int32_t scale)
+ BasicDecimalScalar128(const BasicDecimal128& value, int32_t precision,
int32_t scale)
: value_(value), precision_(precision), scale_(scale) {}
- Decimal128Full(const Decimal128& value, int32_t precision, int32_t scale)
- : value_(value), precision_(precision), scale_(scale) {}
-
- Decimal128Full(int32_t precision, int32_t scale)
- : value_(0), precision_(precision), scale_(scale) {}
-
- uint32_t scale() const { return scale_; }
+ BasicDecimalScalar128(int32_t precision, int32_t scale)
+ : precision_(precision), scale_(scale) {}
- uint32_t precision() const { return precision_; }
+ int32_t scale() const { return scale_; }
- const arrow::Decimal128& value() const { return value_; }
+ int32_t precision() const { return precision_; }
- inline std::string ToString() const {
- return value_.ToString(0) + "," + std::to_string(precision_) + "," +
- std::to_string(scale_);
- }
-
- friend std::ostream& operator<<(std::ostream& os, const Decimal128Full& dec)
{
- os << dec.ToString();
- return os;
- }
+ const BasicDecimal128& value() const { return value_; }
private:
- Decimal128 value_;
-
+ BasicDecimal128 value_;
int32_t precision_;
int32_t scale_;
};
-inline bool operator==(const Decimal128Full& left, const Decimal128Full&
right) {
+inline bool operator==(const BasicDecimalScalar128& left,
+ const BasicDecimalScalar128& right) {
return left.value() == right.value() && left.precision() ==
right.precision() &&
left.scale() == right.scale();
}
} // namespace gandiva
-
-#endif // DECIMAL_FULL_H
diff --git a/cpp/src/gandiva/decimal_scalar.h b/cpp/src/gandiva/decimal_scalar.h
new file mode 100644
index 0000000..5b38770
--- /dev/null
+++ b/cpp/src/gandiva/decimal_scalar.h
@@ -0,0 +1,54 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements. See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership. The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License. You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations
+// under the License
+
+#pragma once
+
+#include <cstdint>
+#include <iostream>
+#include <string>
+#include "arrow/util/decimal.h"
+#include "gandiva/basic_decimal_scalar.h"
+
+namespace gandiva {
+
+using Decimal128 = arrow::Decimal128;
+
+/// Represents a 128-bit decimal value along with its precision and scale.
+///
+/// BasicDecimalScalar128 can be safely compiled to IR without references to
libstdc++.
+/// This class has additional functionality on top of BasicDecimalScalar128 to
deal with
+/// strings and streams.
+class DecimalScalar128 : public BasicDecimalScalar128 {
+ public:
+ using BasicDecimalScalar128::BasicDecimalScalar128;
+
+ DecimalScalar128(const std::string& value, int32_t precision, int32_t scale)
+ : BasicDecimalScalar128(Decimal128(value), precision, scale) {}
+
+ inline std::string ToString() const {
+ Decimal128 dvalue(value());
+ return dvalue.ToString(0) + "," + std::to_string(precision()) + "," +
+ std::to_string(scale());
+ }
+
+ friend std::ostream& operator<<(std::ostream& os, const DecimalScalar128&
dec) {
+ os << dec.ToString();
+ return os;
+ }
+};
+
+} // namespace gandiva
diff --git a/cpp/src/gandiva/decimal_type_util.cc
b/cpp/src/gandiva/decimal_type_util.cc
index 0ebfe66..2795e91 100644
--- a/cpp/src/gandiva/decimal_type_util.cc
+++ b/cpp/src/gandiva/decimal_type_util.cc
@@ -48,8 +48,8 @@ Status DecimalTypeUtil::GetResultType(Op op, const
Decimal128TypeVector& in_type
int32_t s2 = t2->scale();
int32_t p1 = t1->precision();
int32_t p2 = t2->precision();
- int32_t result_scale;
- int32_t result_precision;
+ int32_t result_scale = 0;
+ int32_t result_precision = 0;
switch (op) {
case kOpAdd:
diff --git a/cpp/src/gandiva/jni/CMakeLists.txt
b/cpp/src/gandiva/jni/CMakeLists.txt
index afc7fad..a07d390 100644
--- a/cpp/src/gandiva/jni/CMakeLists.txt
+++ b/cpp/src/gandiva/jni/CMakeLists.txt
@@ -78,5 +78,5 @@ add_dependencies(gandiva ${GANDIVA_JNI_LIBRARIES})
# statically linked stdc++ has conflicts with stdc++ loaded by other libraries.
if (NOT APPLE)
set_target_properties(gandiva_jni_shared PROPERTIES
- LINK_FLAGS "-Wl,--no-as-needed
-Wl,--version-script=${CMAKE_SOURCE_DIR}/src/gandiva/jni/symbols.map")
+ LINK_FLAGS
"-Wl,--version-script=${CMAKE_SOURCE_DIR}/src/gandiva/jni/symbols.map")
endif()
diff --git a/cpp/src/gandiva/jni/jni_common.cc
b/cpp/src/gandiva/jni/jni_common.cc
index 7ad0d6d..339b0cd 100644
--- a/cpp/src/gandiva/jni/jni_common.cc
+++ b/cpp/src/gandiva/jni/jni_common.cc
@@ -383,8 +383,8 @@ NodePtr ProtoTypeToNode(const types::TreeNode& node) {
if (node.has_decimalnode()) {
std::string value = node.decimalnode().value();
- gandiva::Decimal128Full literal(value, node.decimalnode().precision(),
- node.decimalnode().scale());
+ gandiva::DecimalScalar128 literal(value, node.decimalnode().precision(),
+ node.decimalnode().scale());
return TreeExprBuilder::MakeDecimalLiteral(literal);
}
std::cerr << "Unknown node type in protobuf\n";
diff --git a/cpp/src/gandiva/literal_holder.h b/cpp/src/gandiva/literal_holder.h
index 17f3799..36afdd3 100644
--- a/cpp/src/gandiva/literal_holder.h
+++ b/cpp/src/gandiva/literal_holder.h
@@ -23,14 +23,13 @@
#include <arrow/util/variant.h>
#include <arrow/type.h>
-#include "gandiva/decimal_full.h"
+#include "gandiva/decimal_scalar.h"
namespace gandiva {
using LiteralHolder =
arrow::util::variant<bool, float, double, int8_t, int16_t, int32_t,
int64_t, uint8_t,
- uint16_t, uint32_t, uint64_t, std::string,
Decimal128Full>;
-
+ uint16_t, uint32_t, uint64_t, std::string,
DecimalScalar128>;
} // namespace gandiva
#endif // GANDIVA_LITERAL_HOLDER
diff --git a/cpp/src/gandiva/llvm_generator.cc
b/cpp/src/gandiva/llvm_generator.cc
index 17e0224..5d8e85a 100644
--- a/cpp/src/gandiva/llvm_generator.cc
+++ b/cpp/src/gandiva/llvm_generator.cc
@@ -598,12 +598,14 @@ void LLVMGenerator::Visitor::Visit(const LiteralDex& dex)
{
case arrow::Type::DECIMAL: {
// build code for struct
- auto decimal_value = dex.holder().get<Decimal128Full>();
- auto int_value =
+ auto scalar = dex.holder().get<DecimalScalar128>();
+ // ConstantInt doesn't have a get method that takes int128 or a pair of
int64. so,
+ // passing the string representation instead.
+ auto int128_value =
llvm::ConstantInt::get(llvm::Type::getInt128Ty(*generator_->context()),
- decimal_value.value().ToIntegerString(), 10);
- auto type = arrow::decimal(decimal_value.precision(),
decimal_value.scale());
- auto lvalue = generator_->BuildDecimalLValue(int_value, type);
+ Decimal128(scalar.value()).ToIntegerString(),
10);
+ auto type = arrow::decimal(scalar.precision(), scalar.scale());
+ auto lvalue = generator_->BuildDecimalLValue(int128_value, type);
// set it as the l-value and return.
result_ = lvalue;
return;
diff --git a/cpp/src/gandiva/precompiled/CMakeLists.txt
b/cpp/src/gandiva/precompiled/CMakeLists.txt
index ba87e05..6e0a092 100644
--- a/cpp/src/gandiva/precompiled/CMakeLists.txt
+++ b/cpp/src/gandiva/precompiled/CMakeLists.txt
@@ -28,8 +28,7 @@ set(PRECOMPILED_SRCS
string_ops.cc
time.cc
timestamp_arithmetic.cc
- ../../arrow/status.cc
- ../../arrow/util/decimal.cc)
+ ../../arrow/util/basic_decimal.cc)
# Create bitcode for each of the source files.
foreach(SRC_FILE ${PRECOMPILED_SRCS})
@@ -39,8 +38,8 @@ foreach(SRC_FILE ${PRECOMPILED_SRCS})
add_custom_command(
OUTPUT ${BC_FILE}
COMMAND ${CLANG_EXECUTABLE}
+ -DGANDIVA_IR
-std=c++11 -emit-llvm
- -DNDEBUG # DCHECK macros not implemented in precompiled code
-fno-use-cxa-atexit # Workaround for unresolved __dso_handle
-O3 -c ${ABSOLUTE_SRC} -o ${BC_FILE}
${ARROW_GANDIVA_PC_CXX_FLAGS}
diff --git a/cpp/src/gandiva/precompiled/decimal_ops.cc
b/cpp/src/gandiva/precompiled/decimal_ops.cc
index 57cb83e..99231fe 100644
--- a/cpp/src/gandiva/precompiled/decimal_ops.cc
+++ b/cpp/src/gandiva/precompiled/decimal_ops.cc
@@ -27,17 +27,19 @@
namespace gandiva {
namespace decimalops {
-static Decimal128 CheckAndIncreaseScale(Decimal128 in, int32_t delta) {
+using arrow::BasicDecimal128;
+
+static BasicDecimal128 CheckAndIncreaseScale(const BasicDecimal128& in,
int32_t delta) {
return (delta <= 0) ? in : in.IncreaseScaleBy(delta);
}
-static Decimal128 CheckAndReduceScale(Decimal128 in, int32_t delta) {
+static BasicDecimal128 CheckAndReduceScale(const BasicDecimal128& in, int32_t
delta) {
return (delta <= 0) ? in : in.ReduceScaleBy(delta);
}
/// Adjust x and y to the same scale, and add them.
-static Decimal128 AddFastPath(const Decimal128Full& x, const Decimal128Full& y,
- int32_t out_scale) {
+static BasicDecimal128 AddFastPath(const BasicDecimalScalar128& x,
+ const BasicDecimalScalar128& y, int32_t
out_scale) {
auto higher_scale = std::max(x.scale(), y.scale());
auto x_scaled = CheckAndIncreaseScale(x.value(), higher_scale - x.scale());
@@ -46,21 +48,22 @@ static Decimal128 AddFastPath(const Decimal128Full& x,
const Decimal128Full& y,
}
/// Add x and y, caller has ensured there can be no overflow.
-static Decimal128 AddNoOverflow(const Decimal128Full& x, const Decimal128Full&
y,
- int32_t out_scale) {
+static BasicDecimal128 AddNoOverflow(const BasicDecimalScalar128& x,
+ const BasicDecimalScalar128& y, int32_t
out_scale) {
auto higher_scale = std::max(x.scale(), y.scale());
auto sum = AddFastPath(x, y, out_scale);
return CheckAndReduceScale(sum, higher_scale - out_scale);
}
/// Both x_value and y_value must be >= 0
-static Decimal128 AddLargePositive(const Decimal128Full& x, const
Decimal128Full& y,
- int32_t out_scale) {
+static BasicDecimal128 AddLargePositive(const BasicDecimalScalar128& x,
+ const BasicDecimalScalar128& y,
+ int32_t out_scale) {
DCHECK_GE(x.value(), 0);
DCHECK_GE(y.value(), 0);
// separate out whole/fractions.
- Decimal128 x_left, x_right, y_left, y_right;
+ BasicDecimal128 x_left, x_right, y_left, y_right;
x.value().GetWholeAndFraction(x.scale(), &x_left, &x_right);
y.value().GetWholeAndFraction(y.scale(), &y_left, &y_right);
@@ -69,9 +72,9 @@ static Decimal128 AddLargePositive(const Decimal128Full& x,
const Decimal128Full
auto x_right_scaled = CheckAndIncreaseScale(x_right, higher_scale -
x.scale());
auto y_right_scaled = CheckAndIncreaseScale(y_right, higher_scale -
y.scale());
- Decimal128 right;
- Decimal128 carry_to_left;
- auto multiplier = Decimal128::GetScaleMultiplier(higher_scale);
+ BasicDecimal128 right;
+ BasicDecimal128 carry_to_left;
+ auto multiplier = BasicDecimal128::GetScaleMultiplier(higher_scale);
if (x_right_scaled >= multiplier - y_right_scaled) {
right = x_right_scaled - (multiplier - y_right_scaled);
carry_to_left = 1;
@@ -82,18 +85,19 @@ static Decimal128 AddLargePositive(const Decimal128Full& x,
const Decimal128Full
right = CheckAndReduceScale(right, higher_scale - out_scale);
auto left = x_left + y_left + carry_to_left;
- return (left * Decimal128::GetScaleMultiplier(out_scale)) + right;
+ return (left * BasicDecimal128::GetScaleMultiplier(out_scale)) + right;
}
/// x_value and y_value cannot be 0, and one must be positive and the other
negative.
-static Decimal128 AddLargeNegative(const Decimal128Full& x, const
Decimal128Full& y,
- int32_t out_scale) {
+static BasicDecimal128 AddLargeNegative(const BasicDecimalScalar128& x,
+ const BasicDecimalScalar128& y,
+ int32_t out_scale) {
DCHECK_NE(x.value(), 0);
DCHECK_NE(y.value(), 0);
DCHECK((x.value() < 0 && y.value() > 0) || (x.value() > 0 && y.value() < 0));
// separate out whole/fractions.
- Decimal128 x_left, x_right, y_left, y_right;
+ BasicDecimal128 x_left, x_right, y_left, y_right;
x.value().GetWholeAndFraction(x.scale(), &x_left, &x_right);
y.value().GetWholeAndFraction(y.scale(), &y_left, &y_right);
@@ -111,24 +115,24 @@ static Decimal128 AddLargeNegative(const Decimal128Full&
x, const Decimal128Full
// zero, then nothing needs to be done.
if (left < 0 && right > 0) {
left += 1;
- right -= Decimal128::GetScaleMultiplier(higher_scale);
+ right -= BasicDecimal128::GetScaleMultiplier(higher_scale);
} else if (left > 0 && right < 0) {
left -= 1;
- right += Decimal128::GetScaleMultiplier(higher_scale);
+ right += BasicDecimal128::GetScaleMultiplier(higher_scale);
}
right = CheckAndReduceScale(right, higher_scale - out_scale);
- return (left * Decimal128::GetScaleMultiplier(out_scale)) + right;
+ return (left * BasicDecimal128::GetScaleMultiplier(out_scale)) + right;
}
-static Decimal128 AddLarge(const Decimal128Full& x, const Decimal128Full& y,
- int32_t out_scale) {
+static BasicDecimal128 AddLarge(const BasicDecimalScalar128& x,
+ const BasicDecimalScalar128& y, int32_t
out_scale) {
if (x.value() >= 0 && y.value() >= 0) {
// both positive or 0
return AddLargePositive(x, y, out_scale);
} else if (x.value() <= 0 && y.value() <= 0) {
// both negative or 0
- Decimal128Full x_neg(-x.value(), x.precision(), x.scale());
- Decimal128Full y_neg(-y.value(), y.precision(), y.scale());
+ BasicDecimalScalar128 x_neg(-x.value(), x.precision(), x.scale());
+ BasicDecimalScalar128 y_neg(-y.value(), y.precision(), y.scale());
return -AddLargePositive(x_neg, y_neg, out_scale);
} else {
// one positive and the other negative
@@ -164,7 +168,8 @@ inline int32_t MinLeadingZerosAfterScaling(int32_t num_lz,
int32_t scale_by) {
}
// Returns the maximum possible number of bits required to represent num *
10^scale_by.
-inline int32_t MaxBitsRequiredAfterScaling(const Decimal128Full& num, int32_t
scale_by) {
+inline int32_t MaxBitsRequiredAfterScaling(const BasicDecimalScalar128& num,
+ int32_t scale_by) {
auto value = num.value();
auto value_abs = value.Abs();
@@ -176,7 +181,8 @@ inline int32_t MaxBitsRequiredAfterScaling(const
Decimal128Full& num, int32_t sc
// Returns the minimum number of leading zero x or y would have after one of
them gets
// scaled up to match the scale of the other one.
-inline int32_t MinLeadingZeros(const Decimal128Full& x, const Decimal128Full&
y) {
+inline int32_t MinLeadingZeros(const BasicDecimalScalar128& x,
+ const BasicDecimalScalar128& y) {
auto x_value = x.value();
auto x_value_abs = x_value.Abs();
@@ -193,8 +199,8 @@ inline int32_t MinLeadingZeros(const Decimal128Full& x,
const Decimal128Full& y)
return std::min(x_lz, y_lz);
}
-Decimal128 Add(const Decimal128Full& x, const Decimal128Full& y, int32_t
out_precision,
- int32_t out_scale) {
+BasicDecimal128 Add(const BasicDecimalScalar128& x, const
BasicDecimalScalar128& y,
+ int32_t out_precision, int32_t out_scale) {
if (out_precision < DecimalTypeUtil::kMaxPrecision) {
// fast-path add
return AddFastPath(x, y, out_scale);
diff --git a/cpp/src/gandiva/precompiled/decimal_ops.h
b/cpp/src/gandiva/precompiled/decimal_ops.h
index 25f094e..1e202b8 100644
--- a/cpp/src/gandiva/precompiled/decimal_ops.h
+++ b/cpp/src/gandiva/precompiled/decimal_ops.h
@@ -15,12 +15,11 @@
// specific language governing permissions and limitations
// under the License.
-#ifndef DECIMAL_SQL_H
-#define DECIMAL_SQL_H
+#pragma once
#include <cstdint>
#include <string>
-#include "gandiva/decimal_full.h"
+#include "gandiva/basic_decimal_scalar.h"
namespace gandiva {
namespace decimalops {
@@ -28,10 +27,8 @@ namespace decimalops {
/// Return the sum of 'x' and 'y'.
/// out_precision and out_scale are passed along for efficiency, they must
match
/// the rules in DecimalTypeSql::GetResultType.
-Decimal128 Add(const Decimal128Full& x, const Decimal128Full& y, int32_t
out_precision,
- int32_t out_scale);
+arrow::BasicDecimal128 Add(const BasicDecimalScalar128& x, const
BasicDecimalScalar128& y,
+ int32_t out_precision, int32_t out_scale);
} // namespace decimalops
} // namespace gandiva
-
-#endif // DECIMAL_SQL_H
diff --git a/cpp/src/gandiva/precompiled/decimal_ops_test.cc
b/cpp/src/gandiva/precompiled/decimal_ops_test.cc
index 7daf734..6e58106 100644
--- a/cpp/src/gandiva/precompiled/decimal_ops_test.cc
+++ b/cpp/src/gandiva/precompiled/decimal_ops_test.cc
@@ -20,6 +20,7 @@
#include <memory>
#include "arrow/test-util.h"
+#include "gandiva/decimal_scalar.h"
#include "gandiva/decimal_type_util.h"
#include "gandiva/precompiled/decimal_ops.h"
#include "gandiva/precompiled/types.h"
@@ -28,8 +29,8 @@ namespace gandiva {
class TestDecimalSql : public ::testing::Test {
protected:
- static void AddAndVerify(const Decimal128Full& x, const Decimal128Full& y,
- const Decimal128Full& expected);
+ static void AddAndVerify(const DecimalScalar128& x, const DecimalScalar128&
y,
+ const DecimalScalar128& expected);
};
#define EXPECT_DECIMAL_EQ(x, y, expected, actual)
\
@@ -37,8 +38,8 @@ class TestDecimalSql : public ::testing::Test {
<< " expected : " << expected.ToString() << "
actual " \
<< actual.ToString()
-void TestDecimalSql::AddAndVerify(const Decimal128Full& x, const
Decimal128Full& y,
- const Decimal128Full& expected) {
+void TestDecimalSql::AddAndVerify(const DecimalScalar128& x, const
DecimalScalar128& y,
+ const DecimalScalar128& expected) {
auto t1 = std::make_shared<arrow::Decimal128Type>(x.precision(), x.scale());
auto t2 = std::make_shared<arrow::Decimal128Type>(y.precision(), y.scale());
@@ -46,30 +47,31 @@ void TestDecimalSql::AddAndVerify(const Decimal128Full& x,
const Decimal128Full&
EXPECT_OK(DecimalTypeUtil::GetResultType(DecimalTypeUtil::kOpAdd, {t1, t2},
&out_type));
auto out_value = decimalops::Add(x, y, out_type->precision(),
out_type->scale());
- EXPECT_DECIMAL_EQ(x, y, expected,
- Decimal128Full(out_value, out_type->precision(),
out_type->scale()));
+ EXPECT_DECIMAL_EQ(
+ x, y, expected,
+ DecimalScalar128(out_value, out_type->precision(), out_type->scale()));
}
TEST_F(TestDecimalSql, Add) {
// fast-path
- AddAndVerify(Decimal128Full{"201", 30, 3}, // x
- Decimal128Full{"301", 30, 3}, // y
- Decimal128Full{"502", 31, 3}); // expected
+ AddAndVerify(DecimalScalar128{"201", 30, 3}, // x
+ DecimalScalar128{"301", 30, 3}, // y
+ DecimalScalar128{"502", 31, 3}); // expected
// max precision
- AddAndVerify(Decimal128Full{"09999999999999999999999999999999000000", 38,
5}, // x
- Decimal128Full{"100", 38, 7},
// y
- Decimal128Full{"99999999999999999999999999999990000010", 38,
6});
+ AddAndVerify(DecimalScalar128{"09999999999999999999999999999999000000", 38,
5}, // x
+ DecimalScalar128{"100", 38, 7},
// y
+ DecimalScalar128{"99999999999999999999999999999990000010", 38,
6});
// Both -ve
- AddAndVerify(Decimal128Full{"-201", 30, 3}, // x
- Decimal128Full{"-301", 30, 2}, // y
- Decimal128Full{"-3211", 32, 3}); // expected
+ AddAndVerify(DecimalScalar128{"-201", 30, 3}, // x
+ DecimalScalar128{"-301", 30, 2}, // y
+ DecimalScalar128{"-3211", 32, 3}); // expected
// -ve and max precision
- AddAndVerify(Decimal128Full{"-09999999999999999999999999999999000000", 38,
5}, // x
- Decimal128Full{"-100", 38, 7},
// y
- Decimal128Full{"-99999999999999999999999999999990000010", 38,
6});
+ AddAndVerify(DecimalScalar128{"-09999999999999999999999999999999000000", 38,
5}, // x
+ DecimalScalar128{"-100", 38, 7},
// y
+ DecimalScalar128{"-99999999999999999999999999999990000010", 38,
6});
}
} // namespace gandiva
diff --git a/cpp/src/gandiva/precompiled/decimal_wrapper.cc
b/cpp/src/gandiva/precompiled/decimal_wrapper.cc
index 0118100..f327a50 100644
--- a/cpp/src/gandiva/precompiled/decimal_wrapper.cc
+++ b/cpp/src/gandiva/precompiled/decimal_wrapper.cc
@@ -26,10 +26,10 @@ void add_large_decimal128_decimal128(int64_t x_high,
uint64_t x_low, int32_t x_p
int32_t y_precision, int32_t y_scale,
int32_t out_precision, int32_t out_scale,
int64_t* out_high, uint64_t* out_low) {
- gandiva::Decimal128Full x(x_high, x_low, x_precision, x_scale);
- gandiva::Decimal128Full y(y_high, y_low, y_precision, y_scale);
+ gandiva::BasicDecimalScalar128 x(x_high, x_low, x_precision, x_scale);
+ gandiva::BasicDecimalScalar128 y(y_high, y_low, y_precision, y_scale);
- arrow::Decimal128 out = gandiva::decimalops::Add(x, y, out_precision,
out_scale);
+ arrow::BasicDecimal128 out = gandiva::decimalops::Add(x, y, out_precision,
out_scale);
*out_high = out.high_bits();
*out_low = out.low_bits();
}
diff --git a/cpp/src/gandiva/tests/decimal_single_test.cc
b/cpp/src/gandiva/tests/decimal_single_test.cc
index 728ccb7..776ef6e 100644
--- a/cpp/src/gandiva/tests/decimal_single_test.cc
+++ b/cpp/src/gandiva/tests/decimal_single_test.cc
@@ -21,7 +21,7 @@
#include "arrow/memory_pool.h"
#include "arrow/status.h"
-#include "gandiva/decimal_full.h"
+#include "gandiva/decimal_scalar.h"
#include "gandiva/decimal_type_util.h"
#include "gandiva/projector.h"
#include "gandiva/tests/test_util.h"
@@ -36,24 +36,24 @@ namespace gandiva {
<< " expected : " << (expected).ToString() \
<< " actual : " << (actual).ToString();
-Decimal128Full decimal_literal(const char* value, int precision, int scale) {
+DecimalScalar128 decimal_literal(const char* value, int precision, int scale) {
std::string value_string = std::string(value);
- return Decimal128Full(value_string, precision, scale);
+ return DecimalScalar128(value_string, precision, scale);
}
class TestDecimalOps : public ::testing::Test {
public:
void SetUp() { pool_ = arrow::default_memory_pool(); }
- ArrayPtr MakeDecimalVector(const Decimal128Full& in);
- void AddAndVerify(const Decimal128Full& x, const Decimal128Full& y,
- const Decimal128Full& expected);
+ ArrayPtr MakeDecimalVector(const DecimalScalar128& in);
+ void AddAndVerify(const DecimalScalar128& x, const DecimalScalar128& y,
+ const DecimalScalar128& expected);
protected:
arrow::MemoryPool* pool_;
};
-ArrayPtr TestDecimalOps::MakeDecimalVector(const Decimal128Full& in) {
+ArrayPtr TestDecimalOps::MakeDecimalVector(const DecimalScalar128& in) {
std::vector<arrow::Decimal128> ret;
Decimal128 decimal_value = in.value();
@@ -62,8 +62,8 @@ ArrayPtr TestDecimalOps::MakeDecimalVector(const
Decimal128Full& in) {
return MakeArrowArrayDecimal(decimal_type, {decimal_value}, {true});
}
-void TestDecimalOps::AddAndVerify(const Decimal128Full& x, const
Decimal128Full& y,
- const Decimal128Full& expected) {
+void TestDecimalOps::AddAndVerify(const DecimalScalar128& x, const
DecimalScalar128& y,
+ const DecimalScalar128& expected) {
auto x_type = std::make_shared<arrow::Decimal128Type>(x.precision(),
x.scale());
auto y_type = std::make_shared<arrow::Decimal128Type>(y.precision(),
y.scale());
auto field_x = field("x", x_type);
@@ -104,7 +104,7 @@ void TestDecimalOps::AddAndVerify(const Decimal128Full& x,
const Decimal128Full&
auto dtype = dynamic_cast<arrow::Decimal128Type*>(out_array->type().get());
std::string value_string = out_value.ToString(0);
- Decimal128Full actual{value_string, dtype->precision(), dtype->scale()};
+ DecimalScalar128 actual{value_string, dtype->precision(), dtype->scale()};
EXPECT_DECIMAL_SUM_EQUALS(x, y, expected, actual);
}
diff --git a/cpp/src/gandiva/tests/decimal_test.cc
b/cpp/src/gandiva/tests/decimal_test.cc
index f048fd2..da93b0e 100644
--- a/cpp/src/gandiva/tests/decimal_test.cc
+++ b/cpp/src/gandiva/tests/decimal_test.cc
@@ -143,7 +143,7 @@ TEST_F(TestDecimal, TestLiteral) {
// build expression : a + b + c
auto node_a = TreeExprBuilder::MakeField(field_a);
static std::string decimal_point_six = "6";
- Decimal128Full literal(decimal_point_six, 2, 1);
+ DecimalScalar128 literal(decimal_point_six, 2, 1);
auto node_b = TreeExprBuilder::MakeDecimalLiteral(literal);
auto add2 = TreeExprBuilder::MakeFunction("add", {node_a, node_b},
add2_type);
auto expr = TreeExprBuilder::MakeExpression(add2, res);
diff --git a/cpp/src/gandiva/tree_expr_builder.cc
b/cpp/src/gandiva/tree_expr_builder.cc
index 23a49e2..a63b700 100644
--- a/cpp/src/gandiva/tree_expr_builder.cc
+++ b/cpp/src/gandiva/tree_expr_builder.cc
@@ -50,7 +50,7 @@ NodePtr TreeExprBuilder::MakeBinaryLiteral(const std::string&
value) {
return std::make_shared<LiteralNode>(arrow::binary(), LiteralHolder(value),
false);
}
-NodePtr TreeExprBuilder::MakeDecimalLiteral(const Decimal128Full& value) {
+NodePtr TreeExprBuilder::MakeDecimalLiteral(const DecimalScalar128& value) {
return std::make_shared<LiteralNode>(arrow::decimal(value.precision(),
value.scale()),
LiteralHolder(value), false);
}
@@ -99,7 +99,7 @@ NodePtr TreeExprBuilder::MakeNull(DataTypePtr data_type) {
case arrow::Type::TIMESTAMP:
return std::make_shared<LiteralNode>(data_type,
LiteralHolder((int64_t)0), true);
case arrow::Type::DECIMAL: {
- Decimal128Full literal(0, 0);
+ DecimalScalar128 literal(0, 0);
return std::make_shared<LiteralNode>(data_type, LiteralHolder(literal),
true);
}
default:
diff --git a/cpp/src/gandiva/tree_expr_builder.h
b/cpp/src/gandiva/tree_expr_builder.h
index ae5f7fb..3d60b5b 100644
--- a/cpp/src/gandiva/tree_expr_builder.h
+++ b/cpp/src/gandiva/tree_expr_builder.h
@@ -25,7 +25,7 @@
#include "arrow/type.h"
#include "gandiva/condition.h"
-#include "gandiva/decimal_full.h"
+#include "gandiva/decimal_scalar.h"
#include "gandiva/expression.h"
namespace gandiva {
@@ -47,7 +47,7 @@ class TreeExprBuilder {
static NodePtr MakeLiteral(double value);
static NodePtr MakeStringLiteral(const std::string& value);
static NodePtr MakeBinaryLiteral(const std::string& value);
- static NodePtr MakeDecimalLiteral(const Decimal128Full& value);
+ static NodePtr MakeDecimalLiteral(const DecimalScalar128& value);
/// \brief create a node on a null literal.
/// returns null if data_type is null or if it's not a supported datatype.
diff --git a/dev/tasks/gandiva-jars/travis.linux.yml
b/dev/tasks/gandiva-jars/travis.linux.yml
index 8b311ca..0ea9383 100644
--- a/dev/tasks/gandiva-jars/travis.linux.yml
+++ b/dev/tasks/gandiva-jars/travis.linux.yml
@@ -32,7 +32,6 @@ env:
- ARROW_TRAVIS_USE_TOOLCHAIN=1
before_install:
- - export CC="gcc-4.9" CXX="g++-4.9"
- ulimit -c unlimited -S
- |
sudo bash -c "echo -e 'Acquire::Retries 10; Acquire::http::Timeout
\"20\";' > /etc/apt/apt.conf.d/99-travis-retry"
diff --git a/docs/requirements.txt b/docs/requirements.txt
index 7e33455..77ca657 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -1,6 +1,5 @@
breathe
ipython
-matplotlib
numpydoc
sphinx
sphinx_rtd_theme
diff --git a/java/gandiva/pom.xml b/java/gandiva/pom.xml
index 93b8161..a090153 100644
--- a/java/gandiva/pom.xml
+++ b/java/gandiva/pom.xml
@@ -68,11 +68,6 @@
<version>2.10</version>
<scope>test</scope>
</dependency>
- <dependency>
- <groupId>net.java.dev.jna</groupId>
- <artifactId>jna</artifactId>
- <version>4.5.0</version>
- </dependency>
</dependencies>
<profiles>
<profile>
diff --git
a/java/gandiva/src/main/java/org/apache/arrow/gandiva/evaluator/JniLoader.java
b/java/gandiva/src/main/java/org/apache/arrow/gandiva/evaluator/JniLoader.java
index 3491b28..ccb5307 100644
---
a/java/gandiva/src/main/java/org/apache/arrow/gandiva/evaluator/JniLoader.java
+++
b/java/gandiva/src/main/java/org/apache/arrow/gandiva/evaluator/JniLoader.java
@@ -27,8 +27,6 @@ import java.nio.file.StandardCopyOption;
import org.apache.arrow.gandiva.exceptions.GandivaException;
-import com.sun.jna.NativeLibrary;
-
/**
* This class handles loading of the jni library, and acts as a bridge for the
native functions.
*/
@@ -73,9 +71,6 @@ class JniLoader {
throws IOException, GandivaException {
final String libraryToLoad = System.mapLibraryName(LIBRARY_NAME);
final File libraryFile = moveFileFromJarToTemp(tmpDir, libraryToLoad);
- // This is required to load the library with RT_GLOBAL flags. Otherwise,
the symbols in the
- // libgandiva.so aren't visible to the JIT.
- NativeLibrary.getInstance(libraryFile.getAbsolutePath());
System.load(libraryFile.getAbsolutePath());
}
diff --git a/python/pyarrow/gandiva.pyx b/python/pyarrow/gandiva.pyx
index 715ff9d..76e55d6 100644
--- a/python/pyarrow/gandiva.pyx
+++ b/python/pyarrow/gandiva.pyx
@@ -19,8 +19,6 @@
# distutils: language = c++
# cython: embedsignature = True
-import os
-
from libcpp cimport bool as c_bool, nullptr
from libcpp.memory cimport shared_ptr, unique_ptr, make_shared
from libcpp.string cimport string as c_string
@@ -75,14 +73,6 @@ from pyarrow.includes.libgandiva cimport (
CFunctionSignature,
GetRegisteredFunctionSignatures)
-if os.name == 'posix':
- # Expose self with RTLD_GLOBAL so that symbols from gandiva.so and child
- # libs (such as libstdc++) can be reached during JIT code execution.
- # Another workaround is to use
- # sys.setdlopenflags(os.RTLD_GLOBAL | os.RTLD_NOW)
- # but it would affect all C extensions loaded in the process.
- import ctypes
- _dll = ctypes.CDLL(__file__, ctypes.RTLD_GLOBAL)
cdef class Node:
cdef: