1 // Licensed to the Apache Software Foundation (ASF) under one 2 // or more contributor license agreements. See the NOTICE file 3 // distributed with this work for additional information 4 // regarding copyright ownership. The ASF licenses this file 5 // to you under the Apache License, Version 2.0 (the 6 // "License"); you may not use this file except in compliance 7 // with the License. You may obtain a copy of the License at 8 // 9 // http://www.apache.org/licenses/LICENSE-2.0 10 // 11 // Unless required by applicable law or agreed to in writing, 12 // software distributed under the License is distributed on an 13 // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 // KIND, either express or implied. See the License for the 15 // specific language governing permissions and limitations 16 // under the License. 17 18 #pragma once 19 20 #include <array> 21 #include <cstdint> 22 #include <limits> 23 #include <string> 24 #include <type_traits> 25 26 #include "arrow/util/macros.h" 27 #include "arrow/util/type_traits.h" 28 #include "arrow/util/visibility.h" 29 30 namespace arrow { 31 32 enum class DecimalStatus { 33 kSuccess, 34 kDivideByZero, 35 kOverflow, 36 kRescaleDataLoss, 37 }; 38 39 /// Represents a signed 128-bit integer in two's complement. 40 /// 41 /// This class is also compiled into LLVM IR - so, it should not have cpp references like 42 /// streams and boost. 43 class ARROW_EXPORT BasicDecimal128 { 44 public: 45 /// \brief Create a BasicDecimal128 from the two's complement representation. BasicDecimal128(int64_t high,uint64_t low)46 constexpr BasicDecimal128(int64_t high, uint64_t low) noexcept 47 : low_bits_(low), high_bits_(high) {} 48 49 /// \brief Empty constructor creates a BasicDecimal128 with a value of 0. BasicDecimal128()50 constexpr BasicDecimal128() noexcept : BasicDecimal128(0, 0) {} 51 52 /// \brief Convert any integer value into a BasicDecimal128. 53 template <typename T, 54 typename = typename std::enable_if<std::is_integral<T>::value, T>::type> BasicDecimal128(T value)55 constexpr BasicDecimal128(T value) noexcept 56 : BasicDecimal128(static_cast<int64_t>(value) >= 0 ? 0 : -1, 57 static_cast<uint64_t>(value)) {} 58 59 /// \brief Create a BasicDecimal128 from an array of bytes. Bytes are assumed to be in 60 /// native-endian byte order. 61 explicit BasicDecimal128(const uint8_t* bytes); 62 63 /// \brief Negate the current value (in-place) 64 BasicDecimal128& Negate(); 65 66 /// \brief Absolute value (in-place) 67 BasicDecimal128& Abs(); 68 69 /// \brief Absolute value 70 static BasicDecimal128 Abs(const BasicDecimal128& left); 71 72 /// \brief Add a number to this one. The result is truncated to 128 bits. 73 BasicDecimal128& operator+=(const BasicDecimal128& right); 74 75 /// \brief Subtract a number from this one. The result is truncated to 128 bits. 76 BasicDecimal128& operator-=(const BasicDecimal128& right); 77 78 /// \brief Multiply this number by another number. The result is truncated to 128 bits. 79 BasicDecimal128& operator*=(const BasicDecimal128& right); 80 81 /// Divide this number by right and return the result. 82 /// 83 /// This operation is not destructive. 84 /// The answer rounds to zero. Signs work like: 85 /// 21 / 5 -> 4, 1 86 /// -21 / 5 -> -4, -1 87 /// 21 / -5 -> -4, 1 88 /// -21 / -5 -> 4, -1 89 /// \param[in] divisor the number to divide by 90 /// \param[out] result the quotient 91 /// \param[out] remainder the remainder after the division 92 DecimalStatus Divide(const BasicDecimal128& divisor, BasicDecimal128* result, 93 BasicDecimal128* remainder) const; 94 95 /// \brief In-place division. 96 BasicDecimal128& operator/=(const BasicDecimal128& right); 97 98 /// \brief Bitwise "or" between two BasicDecimal128. 99 BasicDecimal128& operator|=(const BasicDecimal128& right); 100 101 /// \brief Bitwise "and" between two BasicDecimal128. 102 BasicDecimal128& operator&=(const BasicDecimal128& right); 103 104 /// \brief Shift left by the given number of bits. 105 BasicDecimal128& operator<<=(uint32_t bits); 106 107 /// \brief Shift right by the given number of bits. Negative values will 108 BasicDecimal128& operator>>=(uint32_t bits); 109 110 /// \brief Get the high bits of the two's complement representation of the number. high_bits()111 inline int64_t high_bits() const { return high_bits_; } 112 113 /// \brief Get the low bits of the two's complement representation of the number. low_bits()114 inline uint64_t low_bits() const { return low_bits_; } 115 116 /// \brief Return the raw bytes of the value in native-endian byte order. 117 std::array<uint8_t, 16> ToBytes() const; 118 void ToBytes(uint8_t* out) const; 119 120 /// \brief separate the integer and fractional parts for the given scale. 121 void GetWholeAndFraction(int32_t scale, BasicDecimal128* whole, 122 BasicDecimal128* fraction) const; 123 124 /// \brief Scale multiplier for given scale value. 125 static const BasicDecimal128& GetScaleMultiplier(int32_t scale); 126 127 /// \brief Convert BasicDecimal128 from one scale to another 128 DecimalStatus Rescale(int32_t original_scale, int32_t new_scale, 129 BasicDecimal128* out) const; 130 131 /// \brief Scale up. 132 BasicDecimal128 IncreaseScaleBy(int32_t increase_by) const; 133 134 /// \brief Scale down. 135 /// - If 'round' is true, the right-most digits are dropped and the result value is 136 /// rounded up (+1 for +ve, -1 for -ve) based on the value of the dropped digits 137 /// (>= 10^reduce_by / 2). 138 /// - If 'round' is false, the right-most digits are simply dropped. 139 BasicDecimal128 ReduceScaleBy(int32_t reduce_by, bool round = true) const; 140 141 // returns 1 for positive and zero decimal values, -1 for negative decimal values. Sign()142 inline int64_t Sign() const { return 1 | (high_bits_ >> 63); } 143 144 /// \brief count the number of leading binary zeroes. 145 int32_t CountLeadingBinaryZeros() const; 146 147 /// \brief Get the maximum valid unscaled decimal value. 148 static const BasicDecimal128& GetMaxValue(); 149 150 private: 151 uint64_t low_bits_; 152 int64_t high_bits_; 153 }; 154 155 ARROW_EXPORT bool operator==(const BasicDecimal128& left, const BasicDecimal128& right); 156 ARROW_EXPORT bool operator!=(const BasicDecimal128& left, const BasicDecimal128& right); 157 ARROW_EXPORT bool operator<(const BasicDecimal128& left, const BasicDecimal128& right); 158 ARROW_EXPORT bool operator<=(const BasicDecimal128& left, const BasicDecimal128& right); 159 ARROW_EXPORT bool operator>(const BasicDecimal128& left, const BasicDecimal128& right); 160 ARROW_EXPORT bool operator>=(const BasicDecimal128& left, const BasicDecimal128& right); 161 162 ARROW_EXPORT BasicDecimal128 operator-(const BasicDecimal128& operand); 163 ARROW_EXPORT BasicDecimal128 operator~(const BasicDecimal128& operand); 164 ARROW_EXPORT BasicDecimal128 operator+(const BasicDecimal128& left, 165 const BasicDecimal128& right); 166 ARROW_EXPORT BasicDecimal128 operator-(const BasicDecimal128& left, 167 const BasicDecimal128& right); 168 ARROW_EXPORT BasicDecimal128 operator*(const BasicDecimal128& left, 169 const BasicDecimal128& right); 170 ARROW_EXPORT BasicDecimal128 operator/(const BasicDecimal128& left, 171 const BasicDecimal128& right); 172 ARROW_EXPORT BasicDecimal128 operator%(const BasicDecimal128& left, 173 const BasicDecimal128& right); 174 175 } // namespace arrow 176