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