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. |
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. |
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> |
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 | /// little-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 Add a number to this one. The result is truncated to 128 bits. |
70 | BasicDecimal128& operator+=(const BasicDecimal128& right); |
71 | |
72 | /// \brief Subtract a number from this one. The result is truncated to 128 bits. |
73 | BasicDecimal128& operator-=(const BasicDecimal128& right); |
74 | |
75 | /// \brief Multiply this number by another number. The result is truncated to 128 bits. |
76 | BasicDecimal128& operator*=(const BasicDecimal128& right); |
77 | |
78 | /// Divide this number by right and return the result. |
79 | /// |
80 | /// This operation is not destructive. |
81 | /// The answer rounds to zero. Signs work like: |
82 | /// 21 / 5 -> 4, 1 |
83 | /// -21 / 5 -> -4, -1 |
84 | /// 21 / -5 -> -4, 1 |
85 | /// -21 / -5 -> 4, -1 |
86 | /// \param[in] divisor the number to divide by |
87 | /// \param[out] result the quotient |
88 | /// \param[out] remainder the remainder after the division |
89 | DecimalStatus Divide(const BasicDecimal128& divisor, BasicDecimal128* result, |
90 | BasicDecimal128* remainder) const; |
91 | |
92 | /// \brief In-place division. |
93 | BasicDecimal128& operator/=(const BasicDecimal128& right); |
94 | |
95 | /// \brief Bitwise "or" between two BasicDecimal128. |
96 | BasicDecimal128& operator|=(const BasicDecimal128& right); |
97 | |
98 | /// \brief Bitwise "and" between two BasicDecimal128. |
99 | BasicDecimal128& operator&=(const BasicDecimal128& right); |
100 | |
101 | /// \brief Shift left by the given number of bits. |
102 | BasicDecimal128& operator<<=(uint32_t bits); |
103 | |
104 | /// \brief Shift right by the given number of bits. Negative values will |
105 | BasicDecimal128& operator>>=(uint32_t bits); |
106 | |
107 | /// \brief Get the high bits of the two's complement representation of the number. |
108 | inline int64_t high_bits() const { return high_bits_; } |
109 | |
110 | /// \brief Get the low bits of the two's complement representation of the number. |
111 | inline uint64_t low_bits() const { return low_bits_; } |
112 | |
113 | /// \brief Return the raw bytes of the value in little-endian byte order. |
114 | std::array<uint8_t, 16> ToBytes() const; |
115 | void ToBytes(uint8_t* out) const; |
116 | |
117 | /// \brief seperate the integer and fractional parts for the given scale. |
118 | void GetWholeAndFraction(int32_t scale, BasicDecimal128* whole, |
119 | BasicDecimal128* fraction) const; |
120 | |
121 | /// \brief Scale multiplier for given scale value. |
122 | static const BasicDecimal128& GetScaleMultiplier(int32_t scale); |
123 | |
124 | /// \brief Convert BasicDecimal128 from one scale to another |
125 | DecimalStatus Rescale(int32_t original_scale, int32_t new_scale, |
126 | BasicDecimal128* out) const; |
127 | |
128 | /// \brief Scale up. |
129 | BasicDecimal128 IncreaseScaleBy(int32_t increase_by) const; |
130 | |
131 | /// \brief Scale down. |
132 | /// - If 'round' is true, the right-most digits are dropped and the result value is |
133 | /// rounded up (+1 for +ve, -1 for -ve) based on the value of the dropped digits |
134 | /// (>= 10^reduce_by / 2). |
135 | /// - If 'round' is false, the right-most digits are simply dropped. |
136 | BasicDecimal128 ReduceScaleBy(int32_t reduce_by, bool round = true) const; |
137 | |
138 | /// \brief count the number of leading binary zeroes. |
139 | int32_t CountLeadingBinaryZeros() const; |
140 | |
141 | private: |
142 | uint64_t low_bits_; |
143 | int64_t high_bits_; |
144 | }; |
145 | |
146 | ARROW_EXPORT bool operator==(const BasicDecimal128& left, const BasicDecimal128& right); |
147 | ARROW_EXPORT bool operator!=(const BasicDecimal128& left, const BasicDecimal128& right); |
148 | ARROW_EXPORT bool operator<(const BasicDecimal128& left, const BasicDecimal128& right); |
149 | ARROW_EXPORT bool operator<=(const BasicDecimal128& left, const BasicDecimal128& right); |
150 | ARROW_EXPORT bool operator>(const BasicDecimal128& left, const BasicDecimal128& right); |
151 | ARROW_EXPORT bool operator>=(const BasicDecimal128& left, const BasicDecimal128& right); |
152 | |
153 | ARROW_EXPORT BasicDecimal128 operator-(const BasicDecimal128& operand); |
154 | ARROW_EXPORT BasicDecimal128 operator~(const BasicDecimal128& operand); |
155 | ARROW_EXPORT BasicDecimal128 operator+(const BasicDecimal128& left, |
156 | const BasicDecimal128& right); |
157 | ARROW_EXPORT BasicDecimal128 operator-(const BasicDecimal128& left, |
158 | const BasicDecimal128& right); |
159 | ARROW_EXPORT BasicDecimal128 operator*(const BasicDecimal128& left, |
160 | const BasicDecimal128& right); |
161 | ARROW_EXPORT BasicDecimal128 operator/(const BasicDecimal128& left, |
162 | const BasicDecimal128& right); |
163 | ARROW_EXPORT BasicDecimal128 operator%(const BasicDecimal128& left, |
164 | const BasicDecimal128& right); |
165 | |
166 | } // namespace arrow |
167 | |