1#ifndef SOURCEMETA_CORE_NUMERIC_DECIMAL_H_
2#define SOURCEMETA_CORE_NUMERIC_DECIMAL_H_
4#ifndef SOURCEMETA_CORE_NUMERIC_EXPORT
5#include <sourcemeta/core/numeric_export.h>
8#include <sourcemeta/core/preprocessor.h>
17namespace sourcemeta::core {
21class SOURCEMETA_CORE_NUMERIC_EXPORT
Decimal {
37 requires std::integral<T> && std::is_signed_v<T> &&
38 (!std::same_as<T, std::int64_t>)
46 requires std::integral<T> && std::is_unsigned_v<T> &&
47 (!std::same_as<T, std::uint64_t>)
60 explicit Decimal(
const char *
const value);
63 explicit Decimal(
const std::string &value);
66 explicit Decimal(
const std::string_view value);
75 [[nodiscard]]
static auto nan(std::uint64_t payload = 0) ->
Decimal;
78 [[nodiscard]]
static auto snan(std::uint64_t payload = 0) ->
Decimal;
98 [[nodiscard]] auto
to_string() const -> std::
string;
101 [[nodiscard]] auto
to_int64() const -> std::int64_t;
104 [[nodiscard]] auto
to_int32() const -> std::int32_t;
134 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto
is_integer() const ->
bool {
135 return (this->flags_ & FLAG_INTEGER_LITERAL) != 0;
139 [[nodiscard]] SOURCEMETA_FORCEINLINE
inline auto is_finite() const ->
bool {
140 return !(this->flags_ & (FLAG_NAN | FLAG_SNAN | FLAG_INFINITE));
144 [[nodiscard]] SOURCEMETA_FORCEINLINE
inline auto is_real() const ->
bool {
170 [[nodiscard]] SOURCEMETA_FORCEINLINE inline auto
is_nan() const ->
bool {
171 return (this->flags_ & FLAG_NAN) != 0;
175 [[nodiscard]] SOURCEMETA_FORCEINLINE
inline auto is_snan() const ->
bool {
176 return (this->flags_ & FLAG_SNAN) != 0;
180 [[nodiscard]] SOURCEMETA_FORCEINLINE
inline auto is_qnan() const ->
bool {
181 return (this->flags_ & FLAG_NAN) != 0 && !(this->flags_ & FLAG_SNAN);
185 [[nodiscard]] SOURCEMETA_FORCEINLINE
inline auto nan_payload() const
188 return static_cast<std::uint64_t
>(this->coefficient_);
192 [[nodiscard]] SOURCEMETA_FORCEINLINE
inline auto is_infinite() const ->
bool {
193 return (this->flags_ & FLAG_INFINITE) != 0;
197 [[nodiscard]] SOURCEMETA_FORCEINLINE
inline auto is_signed() const ->
bool {
198 return (this->flags_ & FLAG_SIGN) != 0;
241 [[nodiscard]] auto operator+(const
Decimal &other) const ->
Decimal;
244 [[nodiscard]] auto operator-(const
Decimal &other) const ->
Decimal;
247 [[nodiscard]] auto operator*(const
Decimal &other) const ->
Decimal;
250 [[nodiscard]] auto operator/(const
Decimal &other) const ->
Decimal;
253 [[nodiscard]] auto operator%(const
Decimal &other) const ->
Decimal;
256 [[nodiscard]] auto operator-() const ->
Decimal;
259 [[nodiscard]] auto operator+() const ->
Decimal;
262 auto operator++() ->
Decimal &;
265 auto operator++(
int) ->
Decimal;
268 auto operator--() ->
Decimal &;
271 auto operator--(
int) ->
Decimal;
274 [[nodiscard]] auto operator==(const
Decimal &other) const ->
bool;
277 [[nodiscard]] auto operator!=(const
Decimal &other) const ->
bool;
280 [[nodiscard]] auto operator<(const
Decimal &other) const ->
bool;
283 [[nodiscard]] auto operator<=(const
Decimal &other) const ->
bool;
286 [[nodiscard]] auto operator>(const
Decimal &other) const ->
bool;
289 [[nodiscard]] auto operator>=(const
Decimal &other) const ->
bool;
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;
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};
305 requires std::integral<T>
306inline auto operator+(
const T left,
const Decimal &right) ->
Decimal {
311 requires std::integral<T>
312inline auto operator-(
const T left,
const Decimal &right) ->
Decimal {
317 requires std::integral<T>
318inline auto operator*(
const T left,
const Decimal &right) ->
Decimal {
323 requires std::integral<T>
324inline auto operator/(
const T left,
const Decimal &right) ->
Decimal {
329 requires std::integral<T>
330inline auto operator%(
const T left,
const Decimal &right) ->
Decimal {
335 requires std::integral<T>
336inline auto operator==(
const T left,
const Decimal &right) ->
bool {
341 requires std::integral<T>
342inline auto operator!=(
const T left,
const Decimal &right) ->
bool {
347 requires std::integral<T>
348inline auto operator<(
const T left,
const Decimal &right) ->
bool {
353 requires std::integral<T>
354inline auto operator<=(
const T left,
const Decimal &right) ->
bool {
359 requires std::integral<T>
360inline auto operator>(
const T left,
const Decimal &right) ->
bool {
365 requires std::integral<T>
366inline auto operator>=(
const T left,
const Decimal &right) ->
bool {
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.