Sourcemeta Core 0.0.0
Loading...
Searching...
No Matches
numeric_decimal.h
1#ifndef SOURCEMETA_CORE_NUMERIC_DECIMAL_H_
2#define SOURCEMETA_CORE_NUMERIC_DECIMAL_H_
3
4#ifndef SOURCEMETA_CORE_NUMERIC_EXPORT
5#include <sourcemeta/core/numeric_export.h>
6#endif
7
8#include <sourcemeta/core/preprocessor.h>
9
10#include <cassert> // assert
11#include <concepts> // std::integral
12#include <cstdint> // std::int32_t, std::int64_t, std::uint32_t, std::uint64_t
13#include <string> // std::string
14#include <string_view> // std::string_view
15#include <type_traits> // std::is_signed_v
16
17namespace sourcemeta::core {
18
21class SOURCEMETA_CORE_NUMERIC_EXPORT Decimal {
22public:
24 Decimal() noexcept;
25
28
30 Decimal(const Decimal &other);
31
33 Decimal(Decimal &&other) noexcept;
34
36 template <typename T>
37 requires std::integral<T> && std::is_signed_v<T> &&
38 (!std::same_as<T, std::int64_t>)
39 Decimal(const T value) : Decimal{static_cast<std::int64_t>(value)} {}
40
42 Decimal(std::int64_t value);
43
45 template <typename T>
46 requires std::integral<T> && std::is_unsigned_v<T> &&
47 (!std::same_as<T, std::uint64_t>)
48 Decimal(const T value) : Decimal{static_cast<std::uint64_t>(value)} {}
49
51 Decimal(std::uint64_t value);
52
54 explicit Decimal(float value);
55
57 explicit Decimal(double value);
58
60 explicit Decimal(const char *const value);
61
63 explicit Decimal(const std::string &value);
64
66 explicit Decimal(const std::string_view value);
67
69 auto operator=(const Decimal &other) -> Decimal &;
70
72 auto operator=(Decimal &&other) noexcept -> Decimal &;
73
75 [[nodiscard]] static auto nan(std::uint64_t payload = 0) -> Decimal;
76
78 [[nodiscard]] static auto snan(std::uint64_t payload = 0) -> Decimal;
79
82 [[nodiscard]] static auto strict_from(double value) -> Decimal;
83
86 [[nodiscard]] static auto exact_from(double value) -> Decimal;
87
89 [[nodiscard]] static auto infinity() -> Decimal;
90
92 [[nodiscard]] static auto negative_infinity() -> Decimal;
93
95 [[nodiscard]] auto to_scientific_string() const -> std::string;
96
98 [[nodiscard]] auto to_string() const -> std::string;
99
101 [[nodiscard]] auto to_int64() const -> std::int64_t;
102
104 [[nodiscard]] auto to_int32() const -> std::int32_t;
105
107 [[nodiscard]] auto to_uint64() const -> std::uint64_t;
108
110 [[nodiscard]] auto to_uint32() const -> std::uint32_t;
111
113 [[nodiscard]] auto to_float() const -> float;
114
116 [[nodiscard]] auto to_double() const -> double;
117
119 [[nodiscard]] auto is_zero() const -> bool;
120
125 [[nodiscard]] auto is_integral() const -> bool;
126
134 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_integer() const -> bool {
135 return (this->flags_ & FLAG_INTEGER_LITERAL) != 0;
136 }
137
139 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_finite() const -> bool {
140 return !(this->flags_ & (FLAG_NAN | FLAG_SNAN | FLAG_INFINITE));
141 }
142
144 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_real() const -> bool {
145 return this->is_finite() && !this->is_integral();
146 }
147
150 [[nodiscard]] auto is_float() const -> bool;
151
154 [[nodiscard]] auto is_double() const -> bool;
155
157 [[nodiscard]] auto is_int32() const -> bool;
158
160 [[nodiscard]] auto is_int64() const -> bool;
161
163 [[nodiscard]] auto is_uint32() const -> bool;
164
166 [[nodiscard]] auto is_uint64() const -> bool;
167
170 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_nan() const -> bool {
171 return (this->flags_ & FLAG_NAN) != 0;
172 }
173
175 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_snan() const -> bool {
176 return (this->flags_ & FLAG_SNAN) != 0;
177 }
178
180 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_qnan() const -> bool {
181 return (this->flags_ & FLAG_NAN) != 0 && !(this->flags_ & FLAG_SNAN);
182 }
183
185 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto nan_payload() const
186 -> std::uint64_t {
187 assert(this->is_nan());
188 return static_cast<std::uint64_t>(this->coefficient_);
189 }
190
192 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_infinite() const -> bool {
193 return (this->flags_ & FLAG_INFINITE) != 0;
194 }
195
197 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto is_signed() const -> bool {
198 return (this->flags_ & FLAG_SIGN) != 0;
199 }
200
202 [[nodiscard]] auto to_integral() const -> Decimal;
203
205 [[nodiscard]] auto divisible_by(const Decimal &divisor) const -> bool;
206
208 [[nodiscard]] auto reduce() const -> Decimal;
209
211 [[nodiscard]] auto logb() const -> Decimal;
212
214 [[nodiscard]] auto scale_by(const Decimal &scale) const -> Decimal;
215
217 [[nodiscard]] auto same_quantum(const Decimal &other) const -> bool;
218
220 [[nodiscard]] auto compare_total(const Decimal &other) const -> Decimal;
221
223 [[nodiscard]] auto divide_integer(const Decimal &other) const -> Decimal;
224
226 auto operator+=(const Decimal &other) -> Decimal &;
227
229 auto operator-=(const Decimal &other) -> Decimal &;
230
232 auto operator*=(const Decimal &other) -> Decimal &;
233
235 auto operator/=(const Decimal &other) -> Decimal &;
236
238 auto operator%=(const Decimal &other) -> Decimal &;
239
241 [[nodiscard]] auto operator+(const Decimal &other) const -> Decimal;
242
244 [[nodiscard]] auto operator-(const Decimal &other) const -> Decimal;
245
247 [[nodiscard]] auto operator*(const Decimal &other) const -> Decimal;
248
250 [[nodiscard]] auto operator/(const Decimal &other) const -> Decimal;
251
253 [[nodiscard]] auto operator%(const Decimal &other) const -> Decimal;
254
256 [[nodiscard]] auto operator-() const -> Decimal;
257
259 [[nodiscard]] auto operator+() const -> Decimal;
260
262 auto operator++() -> Decimal &;
263
265 auto operator++(int) -> Decimal;
266
268 auto operator--() -> Decimal &;
269
271 auto operator--(int) -> Decimal;
272
274 [[nodiscard]] auto operator==(const Decimal &other) const -> bool;
275
277 [[nodiscard]] auto operator!=(const Decimal &other) const -> bool;
278
280 [[nodiscard]] auto operator<(const Decimal &other) const -> bool;
281
283 [[nodiscard]] auto operator<=(const Decimal &other) const -> bool;
284
286 [[nodiscard]] auto operator>(const Decimal &other) const -> bool;
287
289 [[nodiscard]] auto operator>=(const Decimal &other) const -> bool;
290
291private:
292 static constexpr std::uint8_t FLAG_SIGN = 0x01;
293 static constexpr std::uint8_t FLAG_NAN = 0x02;
294 static constexpr std::uint8_t FLAG_SNAN = 0x04;
295 static constexpr std::uint8_t FLAG_INFINITE = 0x08;
296 static constexpr std::uint8_t FLAG_INTEGER_LITERAL = 0x40;
297
298 std::int64_t coefficient_{0};
299 std::uint64_t coefficient_high_{0};
300 std::int32_t exponent_{0};
301 std::uint8_t flags_{0};
302};
303
304template <typename T>
305 requires std::integral<T>
306inline auto operator+(const T left, const Decimal &right) -> Decimal {
307 return Decimal{left} + right;
308}
309
310template <typename T>
311 requires std::integral<T>
312inline auto operator-(const T left, const Decimal &right) -> Decimal {
313 return Decimal{left} - right;
314}
315
316template <typename T>
317 requires std::integral<T>
318inline auto operator*(const T left, const Decimal &right) -> Decimal {
319 return Decimal{left} * right;
320}
321
322template <typename T>
323 requires std::integral<T>
324inline auto operator/(const T left, const Decimal &right) -> Decimal {
325 return Decimal{left} / right;
326}
327
328template <typename T>
329 requires std::integral<T>
330inline auto operator%(const T left, const Decimal &right) -> Decimal {
331 return Decimal{left} % right;
332}
333
334template <typename T>
335 requires std::integral<T>
336inline auto operator==(const T left, const Decimal &right) -> bool {
337 return Decimal{left} == right;
338}
339
340template <typename T>
341 requires std::integral<T>
342inline auto operator!=(const T left, const Decimal &right) -> bool {
343 return Decimal{left} != right;
344}
345
346template <typename T>
347 requires std::integral<T>
348inline auto operator<(const T left, const Decimal &right) -> bool {
349 return Decimal{left} < right;
350}
351
352template <typename T>
353 requires std::integral<T>
354inline auto operator<=(const T left, const Decimal &right) -> bool {
355 return Decimal{left} <= right;
356}
357
358template <typename T>
359 requires std::integral<T>
360inline auto operator>(const T left, const Decimal &right) -> bool {
361 return Decimal{left} > right;
362}
363
364template <typename T>
365 requires std::integral<T>
366inline auto operator>=(const T left, const Decimal &right) -> bool {
367 return Decimal{left} >= right;
368}
369
370} // namespace sourcemeta::core
371
372#endif
auto is_double() const -> bool
Decimal(const T value)
Construct a decimal number from an unsigned integral type.
Definition numeric_decimal.h:48
SOURCEMETA_FORCEINLINE auto is_snan() const -> bool
Check if the decimal number is a signaling NaN.
Definition numeric_decimal.h:175
auto to_double() const -> double
Convert the decimal number to a 64-bit double.
Decimal(const std::string &value)
Construct a decimal number from a C++ string.
Decimal(const char *const value)
Construct a decimal number from a C-string.
auto divide_integer(const Decimal &other) const -> Decimal
Integer division (truncate toward zero).
Decimal(float value)
Construct a decimal number from a 32-bit float.
auto to_uint32() const -> std::uint32_t
Convert the decimal number to a 32-bit unsigned integer.
auto is_uint64() const -> bool
Check if the decimal number fits in a 64-bit unsigned integer.
auto is_uint32() const -> bool
Check if the decimal number fits in a 32-bit unsigned integer.
auto to_string() const -> std::string
Convert the decimal number to a plain string representation.
auto reduce() const -> Decimal
Strip trailing zeros from the coefficient.
SOURCEMETA_FORCEINLINE auto is_signed() const -> bool
Check if the decimal number is signed (negative, including -0).
Definition numeric_decimal.h:197
auto is_int32() const -> bool
Check if the decimal number fits in a 32-bit signed integer.
SOURCEMETA_FORCEINLINE auto is_finite() const -> bool
Check if the decimal number is finite.
Definition numeric_decimal.h:139
SOURCEMETA_FORCEINLINE auto is_real() const -> bool
Check if the decimal number is a real number (finite and not NaN).
Definition numeric_decimal.h:144
SOURCEMETA_FORCEINLINE auto is_qnan() const -> bool
Check if the decimal number is a quiet NaN.
Definition numeric_decimal.h:180
auto is_integral() const -> bool
auto is_zero() const -> bool
Check if the decimal number is zero.
SOURCEMETA_FORCEINLINE auto is_integer() const -> bool
Definition numeric_decimal.h:134
auto to_scientific_string() const -> std::string
Convert the decimal number to scientific notation string.
auto is_float() const -> bool
Decimal(const std::string_view value)
Construct a decimal number from a string view.
auto logb() const -> Decimal
Return the adjusted exponent (floor of base-10 logarithm).
static auto exact_from(double value) -> Decimal
auto divisible_by(const Decimal &divisor) const -> bool
Check if this decimal number is divisible by another.
Decimal() noexcept
Construct a decimal number initialized to zero.
static auto nan(std::uint64_t payload=0) -> Decimal
Create a quiet NaN (Not a Number) value with an optional payload.
auto to_uint64() const -> std::uint64_t
Convert the decimal number to a 64-bit unsigned integer.
static auto strict_from(double value) -> Decimal
auto same_quantum(const Decimal &other) const -> bool
Check if two numbers have the same quantum (exponent).
SOURCEMETA_FORCEINLINE auto is_nan() const -> bool
Definition numeric_decimal.h:170
SOURCEMETA_FORCEINLINE auto nan_payload() const -> std::uint64_t
Get the payload of a NaN value (0 if no payload).
Definition numeric_decimal.h:185
Decimal(std::int64_t value)
Construct a decimal number from a 64-bit signed integer.
Decimal(double value)
Construct a decimal number from a 64-bit double.
auto to_integral() const -> Decimal
Round the decimal number to an integral value.
auto to_int32() const -> std::int32_t
Convert the decimal number to a 32-bit signed integer.
Decimal(std::uint64_t value)
Construct a decimal number from a 64-bit unsigned integer.
auto compare_total(const Decimal &other) const -> Decimal
IEEE 754 total ordering comparison returning -1, 0, or 1.
static auto negative_infinity() -> Decimal
Create a negative infinity value.
SOURCEMETA_FORCEINLINE auto is_infinite() const -> bool
Check if the decimal number is infinite.
Definition numeric_decimal.h:192
auto scale_by(const Decimal &scale) const -> Decimal
Scale the number by a power of 10.
static auto infinity() -> Decimal
Create a positive infinity value.
auto to_int64() const -> std::int64_t
Convert the decimal number to a 64-bit signed integer.
static auto snan(std::uint64_t payload=0) -> Decimal
Create a signaling NaN value with an optional payload.
auto to_float() const -> float
Convert the decimal number to a 32-bit float.
auto is_int64() const -> bool
Check if the decimal number fits in a 64-bit signed integer.
Definition numeric_decimal.h:21