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:

Reply via email to