]>
git.proxmox.com Git - ceph.git/blob - ceph/src/arrow/cpp/src/arrow/util/decimal.h
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
9 // http://www.apache.org/licenses/LICENSE-2.0
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
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"
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.
39 /// For a discussion of the algorithms, look at Knuth's volume 2,
40 /// Semi-numerical Algorithms section 4.3.1.
42 /// Adapted from the Apache ORC C++ implementation
44 /// The implementation is split into two parts :
46 /// 1. BasicDecimal128
47 /// - can be safely compiled to IR without references to libstdc++.
49 /// - has additional functionality on top of BasicDecimal128 to deal with
50 /// strings and streams.
51 class ARROW_EXPORT Decimal128
: public BasicDecimal128
{
54 // (need to avoid a duplicate definition in Sphinx)
55 using BasicDecimal128::BasicDecimal128
;
58 /// \brief constructor creates a Decimal128 from a BasicDecimal128.
59 constexpr Decimal128(const BasicDecimal128
& value
) noexcept
// NOLINT runtime/explicit
60 : BasicDecimal128(value
) {}
62 /// \brief Parse the number from a base 10 string representation.
63 explicit Decimal128(const std::string
& value
);
65 /// \brief Empty constructor creates a Decimal128 with a value of 0.
66 // This is required on some older compilers.
67 constexpr Decimal128() noexcept
: BasicDecimal128() {}
69 /// Divide this number by right and return the result.
71 /// This operation is not destructive.
72 /// The answer rounds to zero. Signs work like:
77 /// \param[in] divisor the number to divide by
78 /// \return the pair of the quotient and the remainder
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
);
86 /// \brief Convert the Decimal128 value to a base 10 decimal string with the given
88 std::string
ToString(int32_t scale
) const;
90 /// \brief Convert the value to an integer string
91 std::string
ToIntegerString() const;
93 /// \brief Cast this value to an int64_t.
94 explicit operator int64_t() const;
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
);
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
);
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
);
116 /// \brief Convert Decimal128 from one scale to another
117 Result
<Decimal128
> Rescale(int32_t original_scale
, int32_t new_scale
) const {
119 auto dstatus
= BasicDecimal128::Rescale(original_scale
, new_scale
, &out
);
120 ARROW_RETURN_NOT_OK(ToArrowStatus(dstatus
));
121 return std::move(out
);
124 /// \brief Convert to a signed integer
125 template <typename T
, typename
= internal::EnableIfIsOneOf
<T
, int32_t, int64_t>>
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
),
134 return static_cast<T
>(low_bits());
137 /// \brief Convert to a signed integer
138 template <typename T
, typename
= internal::EnableIfIsOneOf
<T
, int32_t, int64_t>>
139 Status
ToInteger(T
* out
) const {
140 return ToInteger
<T
>().Value(out
);
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;
148 /// \brief Convert to a floating-point number (scaled)
149 template <typename T
>
150 T
ToReal(int32_t scale
) const {
151 return ToRealConversion
<T
>::ToReal(*this, scale
);
154 friend ARROW_EXPORT
std::ostream
& operator<<(std::ostream
& os
,
155 const Decimal128
& decimal
);
158 /// Converts internal error code to Status
159 Status
ToArrowStatus(DecimalStatus dstatus
) const;
161 template <typename T
>
162 struct ToRealConversion
{};
166 struct Decimal128::ToRealConversion
<float> {
167 static float ToReal(const Decimal128
& dec
, int32_t scale
) { return dec
.ToFloat(scale
); }
171 struct Decimal128::ToRealConversion
<double> {
172 static double ToReal(const Decimal128
& dec
, int32_t scale
) {
173 return dec
.ToDouble(scale
);
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.
181 /// The implementation is split into two parts :
183 /// 1. BasicDecimal256
184 /// - can be safely compiled to IR without references to libstdc++.
186 /// - (TODO) has additional functionality on top of BasicDecimal256 to deal with
187 /// strings and streams.
188 class ARROW_EXPORT Decimal256
: public BasicDecimal256
{
191 // (need to avoid a duplicate definition in Sphinx)
192 using BasicDecimal256::BasicDecimal256
;
195 /// \brief constructor creates a Decimal256 from a BasicDecimal256.
196 constexpr Decimal256(const BasicDecimal256
& value
) noexcept
: BasicDecimal256(value
) {}
198 /// \brief Parse the number from a base 10 string representation.
199 explicit Decimal256(const std::string
& value
);
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() {}
205 /// \brief Convert the Decimal256 value to a base 10 decimal string with the given
207 std::string
ToString(int32_t scale
) const;
209 /// \brief Convert the value to an integer string
210 std::string
ToIntegerString() const;
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
);
224 /// \brief Convert Decimal256 from one scale to another
225 Result
<Decimal256
> Rescale(int32_t original_scale
, int32_t new_scale
) const {
227 auto dstatus
= BasicDecimal256::Rescale(original_scale
, new_scale
, &out
);
228 ARROW_RETURN_NOT_OK(ToArrowStatus(dstatus
));
229 return std::move(out
);
232 /// Divide this number by right and return the result.
234 /// This operation is not destructive.
235 /// The answer rounds to zero. Signs work like:
237 /// -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
);
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
);
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
);
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;
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
);
269 friend ARROW_EXPORT
std::ostream
& operator<<(std::ostream
& os
,
270 const Decimal256
& decimal
);
273 /// Converts internal error code to Status
274 Status
ToArrowStatus(DecimalStatus dstatus
) const;
276 template <typename T
>
277 struct ToRealConversion
{};
281 struct Decimal256::ToRealConversion
<float> {
282 static float ToReal(const Decimal256
& dec
, int32_t scale
) { return dec
.ToFloat(scale
); }
286 struct Decimal256::ToRealConversion
<double> {
287 static double ToReal(const Decimal256
& dec
, int32_t scale
) {
288 return dec
.ToDouble(scale
);
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
) {
311 return Status::Invalid("Not an integer type: ", type_id
);