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 <cstdint>
21 #include <iosfwd>
22 #include <limits>
23 #include <string>
24 #include <utility>
25 
26 #include "arrow/result.h"
27 #include "arrow/status.h"
28 #include "arrow/type_fwd.h"
29 #include "arrow/util/basic_decimal.h"
30 #include "arrow/util/string_view.h"
31 
32 namespace arrow {
33 
34 /// Represents a signed 128-bit integer in two's complement.
35 /// Calculations wrap around and overflow is ignored.
36 /// The max decimal precision that can be safely represented is
37 /// 38 significant digits.
38 ///
39 /// For a discussion of the algorithms, look at Knuth's volume 2,
40 /// Semi-numerical Algorithms section 4.3.1.
41 ///
42 /// Adapted from the Apache ORC C++ implementation
43 ///
44 /// The implementation is split into two parts :
45 ///
46 /// 1. BasicDecimal128
47 ///    - can be safely compiled to IR without references to libstdc++.
48 /// 2. Decimal128
49 ///    - has additional functionality on top of BasicDecimal128 to deal with
50 ///      strings and streams.
51 class ARROW_EXPORT Decimal128 : public BasicDecimal128 {
52  public:
53   /// \cond FALSE
54   // (need to avoid a duplicate definition in Sphinx)
55   using BasicDecimal128::BasicDecimal128;
56   /// \endcond
57 
58   /// \brief constructor creates a Decimal128 from a BasicDecimal128.
Decimal128(const BasicDecimal128 & value)59   constexpr Decimal128(const BasicDecimal128& value) noexcept  // NOLINT runtime/explicit
60       : BasicDecimal128(value) {}
61 
62   /// \brief Parse the number from a base 10 string representation.
63   explicit Decimal128(const std::string& value);
64 
65   /// \brief Empty constructor creates a Decimal128 with a value of 0.
66   // This is required on some older compilers.
Decimal128()67   constexpr Decimal128() noexcept : BasicDecimal128() {}
68 
69   /// Divide this number by right and return the result.
70   ///
71   /// This operation is not destructive.
72   /// The answer rounds to zero. Signs work like:
73   ///   21 /  5 ->  4,  1
74   ///  -21 /  5 -> -4, -1
75   ///   21 / -5 -> -4,  1
76   ///  -21 / -5 ->  4, -1
77   /// \param[in] divisor the number to divide by
78   /// \return the pair of the quotient and the remainder
Divide(const Decimal128 & divisor)79   Result<std::pair<Decimal128, Decimal128>> Divide(const Decimal128& divisor) const {
80     std::pair<Decimal128, Decimal128> result;
81     auto dstatus = BasicDecimal128::Divide(divisor, &result.first, &result.second);
82     ARROW_RETURN_NOT_OK(ToArrowStatus(dstatus));
83     return std::move(result);
84   }
85 
86   /// \brief Convert the Decimal128 value to a base 10 decimal string with the given
87   /// scale.
88   std::string ToString(int32_t scale) const;
89 
90   /// \brief Convert the value to an integer string
91   std::string ToIntegerString() const;
92 
93   /// \brief Cast this value to an int64_t.
94   explicit operator int64_t() const;
95 
96   /// \brief Convert a decimal string to a Decimal128 value, optionally including
97   /// precision and scale if they're passed in and not null.
98   static Status FromString(const util::string_view& s, Decimal128* out,
99                            int32_t* precision, int32_t* scale = NULLPTR);
100   static Status FromString(const std::string& s, Decimal128* out, int32_t* precision,
101                            int32_t* scale = NULLPTR);
102   static Status FromString(const char* s, Decimal128* out, int32_t* precision,
103                            int32_t* scale = NULLPTR);
104   static Result<Decimal128> FromString(const util::string_view& s);
105   static Result<Decimal128> FromString(const std::string& s);
106   static Result<Decimal128> FromString(const char* s);
107 
108   static Result<Decimal128> FromReal(double real, int32_t precision, int32_t scale);
109   static Result<Decimal128> FromReal(float real, int32_t precision, int32_t scale);
110 
111   /// \brief Convert from a big-endian byte representation. The length must be
112   ///        between 1 and 16.
113   /// \return error status if the length is an invalid value
114   static Result<Decimal128> FromBigEndian(const uint8_t* data, int32_t length);
115 
116   /// \brief Convert Decimal128 from one scale to another
Rescale(int32_t original_scale,int32_t new_scale)117   Result<Decimal128> Rescale(int32_t original_scale, int32_t new_scale) const {
118     Decimal128 out;
119     auto dstatus = BasicDecimal128::Rescale(original_scale, new_scale, &out);
120     ARROW_RETURN_NOT_OK(ToArrowStatus(dstatus));
121     return std::move(out);
122   }
123 
124   /// \brief Convert to a signed integer
125   template <typename T, typename = internal::EnableIfIsOneOf<T, int32_t, int64_t>>
ToInteger()126   Result<T> ToInteger() const {
127     constexpr auto min_value = std::numeric_limits<T>::min();
128     constexpr auto max_value = std::numeric_limits<T>::max();
129     const auto& self = *this;
130     if (self < min_value || self > max_value) {
131       return Status::Invalid("Invalid cast from Decimal128 to ", sizeof(T),
132                              " byte integer");
133     }
134     return static_cast<T>(low_bits());
135   }
136 
137   /// \brief Convert to a signed integer
138   template <typename T, typename = internal::EnableIfIsOneOf<T, int32_t, int64_t>>
ToInteger(T * out)139   Status ToInteger(T* out) const {
140     return ToInteger<T>().Value(out);
141   }
142 
143   /// \brief Convert to a floating-point number (scaled)
144   float ToFloat(int32_t scale) const;
145   /// \brief Convert to a floating-point number (scaled)
146   double ToDouble(int32_t scale) const;
147 
148   /// \brief Convert to a floating-point number (scaled)
149   template <typename T>
ToReal(int32_t scale)150   T ToReal(int32_t scale) const {
151     return ToRealConversion<T>::ToReal(*this, scale);
152   }
153 
154   friend ARROW_EXPORT std::ostream& operator<<(std::ostream& os,
155                                                const Decimal128& decimal);
156 
157  private:
158   /// Converts internal error code to Status
159   Status ToArrowStatus(DecimalStatus dstatus) const;
160 
161   template <typename T>
162   struct ToRealConversion {};
163 };
164 
165 template <>
166 struct Decimal128::ToRealConversion<float> {
167   static float ToReal(const Decimal128& dec, int32_t scale) { return dec.ToFloat(scale); }
168 };
169 
170 template <>
171 struct Decimal128::ToRealConversion<double> {
172   static double ToReal(const Decimal128& dec, int32_t scale) {
173     return dec.ToDouble(scale);
174   }
175 };
176 
177 /// Represents a signed 256-bit integer in two's complement.
178 /// The max decimal precision that can be safely represented is
179 /// 76 significant digits.
180 ///
181 /// The implementation is split into two parts :
182 ///
183 /// 1. BasicDecimal256
184 ///    - can be safely compiled to IR without references to libstdc++.
185 /// 2. Decimal256
186 ///    - (TODO) has additional functionality on top of BasicDecimal256 to deal with
187 ///      strings and streams.
188 class ARROW_EXPORT Decimal256 : public BasicDecimal256 {
189  public:
190   /// \cond FALSE
191   // (need to avoid a duplicate definition in Sphinx)
192   using BasicDecimal256::BasicDecimal256;
193   /// \endcond
194 
195   /// \brief constructor creates a Decimal256 from a BasicDecimal256.
196   constexpr Decimal256(const BasicDecimal256& value) noexcept : BasicDecimal256(value) {}
197 
198   /// \brief Parse the number from a base 10 string representation.
199   explicit Decimal256(const std::string& value);
200 
201   /// \brief Empty constructor creates a Decimal256 with a value of 0.
202   // This is required on some older compilers.
203   constexpr Decimal256() noexcept : BasicDecimal256() {}
204 
205   /// \brief Convert the Decimal256 value to a base 10 decimal string with the given
206   /// scale.
207   std::string ToString(int32_t scale) const;
208 
209   /// \brief Convert the value to an integer string
210   std::string ToIntegerString() const;
211 
212   /// \brief Convert a decimal string to a Decimal256 value, optionally including
213   /// precision and scale if they're passed in and not null.
214   static Status FromString(const util::string_view& s, Decimal256* out,
215                            int32_t* precision, int32_t* scale = NULLPTR);
216   static Status FromString(const std::string& s, Decimal256* out, int32_t* precision,
217                            int32_t* scale = NULLPTR);
218   static Status FromString(const char* s, Decimal256* out, int32_t* precision,
219                            int32_t* scale = NULLPTR);
220   static Result<Decimal256> FromString(const util::string_view& s);
221   static Result<Decimal256> FromString(const std::string& s);
222   static Result<Decimal256> FromString(const char* s);
223 
224   /// \brief Convert Decimal256 from one scale to another
225   Result<Decimal256> Rescale(int32_t original_scale, int32_t new_scale) const {
226     Decimal256 out;
227     auto dstatus = BasicDecimal256::Rescale(original_scale, new_scale, &out);
228     ARROW_RETURN_NOT_OK(ToArrowStatus(dstatus));
229     return std::move(out);
230   }
231 
232   /// Divide this number by right and return the result.
233   ///
234   /// This operation is not destructive.
235   /// The answer rounds to zero. Signs work like:
236   ///   21 /  5 ->  4,  1
237   ///  -21 /  5 -> -4, -1
238   ///   21 / -5 -> -4,  1
239   ///  -21 / -5 ->  4, -1
240   /// \param[in] divisor the number to divide by
241   /// \return the pair of the quotient and the remainder
242   Result<std::pair<Decimal256, Decimal256>> Divide(const Decimal256& divisor) const {
243     std::pair<Decimal256, Decimal256> result;
244     auto dstatus = BasicDecimal256::Divide(divisor, &result.first, &result.second);
245     ARROW_RETURN_NOT_OK(ToArrowStatus(dstatus));
246     return std::move(result);
247   }
248 
249   /// \brief Convert from a big-endian byte representation. The length must be
250   ///        between 1 and 32.
251   /// \return error status if the length is an invalid value
252   static Result<Decimal256> FromBigEndian(const uint8_t* data, int32_t length);
253 
254   static Result<Decimal256> FromReal(double real, int32_t precision, int32_t scale);
255   static Result<Decimal256> FromReal(float real, int32_t precision, int32_t scale);
256 
257   /// \brief Convert to a floating-point number (scaled).
258   /// May return infinity in case of overflow.
259   float ToFloat(int32_t scale) const;
260   /// \brief Convert to a floating-point number (scaled)
261   double ToDouble(int32_t scale) const;
262 
263   /// \brief Convert to a floating-point number (scaled)
264   template <typename T>
265   T ToReal(int32_t scale) const {
266     return ToRealConversion<T>::ToReal(*this, scale);
267   }
268 
269   friend ARROW_EXPORT std::ostream& operator<<(std::ostream& os,
270                                                const Decimal256& decimal);
271 
272  private:
273   /// Converts internal error code to Status
274   Status ToArrowStatus(DecimalStatus dstatus) const;
275 
276   template <typename T>
277   struct ToRealConversion {};
278 };
279 
280 template <>
281 struct Decimal256::ToRealConversion<float> {
282   static float ToReal(const Decimal256& dec, int32_t scale) { return dec.ToFloat(scale); }
283 };
284 
285 template <>
286 struct Decimal256::ToRealConversion<double> {
287   static double ToReal(const Decimal256& dec, int32_t scale) {
288     return dec.ToDouble(scale);
289   }
290 };
291 
292 /// For an integer type, return the max number of decimal digits
293 /// (=minimal decimal precision) it can represent.
294 inline Result<int32_t> MaxDecimalDigitsForInteger(Type::type type_id) {
295   switch (type_id) {
296     case Type::INT8:
297     case Type::UINT8:
298       return 3;
299     case Type::INT16:
300     case Type::UINT16:
301       return 5;
302     case Type::INT32:
303     case Type::UINT32:
304       return 10;
305     case Type::INT64:
306     case Type::UINT64:
307       return 19;
308     default:
309       break;
310   }
311   return Status::Invalid("Not an integer type: ", type_id);
312 }
313 
314 }  // namespace arrow
315