26 constexpr static int mantissa_bits = 56;
27 constexpr static int exponent_bits = 8;
28 constexpr static int exponent_max = 127;
29 constexpr static int exponent_min = -128;
31 constexpr decimal() noexcept : value(0) {}
32 constexpr decimal(decimal
const& other)
noexcept =
default;
33 constexpr decimal(decimal&& other)
noexcept =
default;
34 constexpr decimal& operator=(decimal
const& other)
noexcept =
default;
35 constexpr decimal& operator=(decimal&& other)
noexcept =
default;
39 constexpr decimal(
std::pair<int, long long> exponent_mantissa) : decimal(exponent_mantissa.first, exponent_mantissa.second) {}
41 decimal(std::string_view str) : decimal(to_exponent_mantissa(str)) {}
42 decimal(
double x) noexcept : decimal(to_exponent_mantissa(x)) {}
43 decimal(
float x) noexcept : decimal(to_exponent_mantissa(x)) {}
44 constexpr decimal(
signed long long x) : decimal(0, x) {}
45 constexpr decimal(
signed long x) : decimal(0,
static_cast<signed long long>(x)) {}
46 constexpr decimal(
signed int x) : decimal(0,
static_cast<signed long long>(x)) {}
47 constexpr decimal(
signed short x) : decimal(0,
static_cast<signed long long>(x)) {}
48 constexpr decimal(
signed char x) : decimal(0,
static_cast<signed long long>(x)) {}
49 constexpr decimal(
unsigned long long x) : decimal(0, x) {}
50 constexpr decimal(
unsigned long x) : decimal(0,
static_cast<signed long long>(x)) {}
51 constexpr decimal(
unsigned int x) : decimal(0,
static_cast<signed long long>(x)) {}
52 constexpr decimal(
unsigned short x) : decimal(0,
static_cast<signed long long>(x)) {}
53 constexpr decimal(
unsigned char x) : decimal(0,
static_cast<signed long long>(x)) {}
57 value = decimal::pack(other.first, other.second);
60 decimal& operator=(std::string_view str)
noexcept
62 return *
this = to_exponent_mantissa(str);
64 constexpr decimal& operator=(
double other)
noexcept
66 return *
this = to_exponent_mantissa(other);
68 constexpr decimal& operator=(
float other)
noexcept
70 return *
this = to_exponent_mantissa(other);
72 constexpr decimal& operator=(
signed long long other)
noexcept
74 value = decimal::pack(0, other);
77 constexpr decimal& operator=(
signed long other)
noexcept
81 constexpr decimal& operator=(
signed int other)
noexcept
85 constexpr decimal& operator=(
signed short other)
noexcept
89 constexpr decimal& operator=(
signed char other)
noexcept
93 constexpr decimal& operator=(
unsigned long long other)
noexcept
97 constexpr decimal& operator=(
unsigned long other)
noexcept
101 constexpr decimal& operator=(
unsigned int other)
noexcept
105 constexpr decimal& operator=(
unsigned short other)
noexcept
109 constexpr decimal& operator=(
unsigned char other)
noexcept
114 explicit operator signed long long()
const noexcept
127 if (!is_valid_mantissa(m)) {
134 explicit operator signed long()
const noexcept
138 explicit operator signed int()
const noexcept
142 explicit operator signed short()
const noexcept
146 explicit operator signed char()
const noexcept
150 explicit operator unsigned long long()
const noexcept
154 explicit operator unsigned long()
const noexcept
158 explicit operator unsigned int()
const noexcept
162 explicit operator unsigned short()
const noexcept
166 explicit operator unsigned char()
const noexcept
170 explicit operator long double()
const noexcept
174 explicit operator double()
const noexcept
176 return static_cast<double>(
static_cast<long double>(*this));
178 explicit operator float()
const noexcept
180 return static_cast<float>(
static_cast<long double>(*this));
183 explicit operator bool()
const noexcept
198 [[nodiscard]]
constexpr int exponent() const noexcept
207 [[nodiscard]]
constexpr long long mantissa() const noexcept
214 return {exponent(), mantissa()};
222 [[nodiscard]]
constexpr decimal
normalize() const noexcept
224 hilet[e, m] = exponent_mantissa();
231 hilet[e, lhs_m, rhs_m] = decimal::align(*
this, rhs);
232 value = decimal::pack(e, lhs_m + rhs_m);
236 decimal& operator-=(decimal rhs)
noexcept
238 hilet[e, lhs_m, rhs_m] = decimal::align(*
this, rhs);
239 value = decimal::pack(e, lhs_m - rhs_m);
243 decimal& operator*=(decimal rhs)
noexcept
245 return *
this = *
this * rhs;
248 decimal& operator/=(decimal rhs)
noexcept
250 return *
this = *
this / rhs;
254 [[nodiscard]]
friend bool operator==(decimal lhs, decimal rhs)
noexcept
256 hilet[e, lhs_m, rhs_m] = decimal::align(lhs, rhs);
257 return lhs_m == rhs_m;
260 [[nodiscard]]
friend auto operator<=>(decimal lhs, decimal rhs)
noexcept
262 hilet[e, lhs_m, rhs_m] = decimal::align(lhs, rhs);
263 return lhs_m <=> rhs_m;
266 [[nodiscard]]
friend constexpr decimal operator-(decimal rhs)
noexcept
268 return {rhs.exponent(), -rhs.mantissa()};
271 [[nodiscard]]
friend decimal operator+(decimal lhs, decimal rhs)
noexcept
273 hilet[e, lhs_m, rhs_m] = decimal::align(lhs, rhs);
274 return {e, lhs_m + rhs_m};
277 [[nodiscard]]
friend decimal operator-(decimal lhs, decimal rhs)
noexcept
279 hilet[e, lhs_m, rhs_m] = decimal::align(lhs, rhs);
280 return {e, lhs_m - rhs_m};
283 [[nodiscard]]
friend decimal operator*(decimal lhs, decimal rhs)
noexcept
285 auto lhs_e = lhs.exponent();
286 auto lhs_m = lhs.mantissa();
287 auto rhs_e = rhs.exponent();
288 auto rhs_m = rhs.mantissa();
292 [[likely]]
return {lhs_e + rhs_e, m};
296 std::tie(lhs_e, lhs_m) = decimal::normalize(lhs_e, lhs_m);
297 std::tie(rhs_e, rhs_m) = decimal::normalize(rhs_e, rhs_m);
310 return {lhs_e + rhs_e, m};
313 [[nodiscard]]
friend decimal operator/(decimal lhs, decimal rhs)
noexcept
315 hilet rhs_m = rhs.mantissa();
317 hilet rhs_e = rhs.exponent();
318 auto lhs_m = lhs.mantissa();
319 auto lhs_e = lhs.exponent();
321 std::tie(lhs_e, lhs_m) = decimal::denormalize(lhs_e, lhs_m);
322 return {lhs_e - rhs_e, lhs_m / rhs_m};
325 [[nodiscard]]
friend decimal operator%(decimal lhs, decimal rhs)
noexcept
327 hilet rhs_m = rhs.mantissa();
329 hilet rhs_e = rhs.exponent();
330 auto lhs_m = lhs.mantissa();
331 auto lhs_e = lhs.exponent();
333 std::tie(lhs_e, lhs_m) = decimal::denormalize(lhs_e, lhs_m);
334 return {lhs_e - rhs_e, lhs_m % rhs_m};
337 [[nodiscard]]
friend std::string
to_string(decimal x)
noexcept
339 hilet[e, m] = x.exponent_mantissa();
342 hilet decimal_position = -e;
343 hilet leading_zeros = (decimal_position - ssize(s)) + 1;
344 if (leading_zeros > 0) {
345 s.insert(0, leading_zeros,
'0');
348 hilet trailing_zeros = e;
349 if (trailing_zeros > 0) {
350 s.append(trailing_zeros,
'0');
353 if (decimal_position > 0) {
354 s.insert(s.size() - decimal_position, 1,
'.');
364 friend std::ostream& operator<<(std::ostream& lhs, decimal rhs)
372 [[nodiscard]]
constexpr static std::pair<int, long long> normalize(
int e,
long long m)
noexcept
375 while (m % 10 == 0) {
385 [[nodiscard]]
constexpr static std::pair<int, long long> denormalize(
int e,
long long m)
noexcept
391 while (is_valid_mantissa(m)) {
402 [[nodiscard]]
constexpr static bool is_valid_mantissa(
long long m)
noexcept
404 m >>= (mantissa_bits - 1);
405 return m == 0 || m == -1;
411 [[nodiscard]]
constexpr static bool is_valid_exponent(
int e)
noexcept
413 e >>= (exponent_bits - 1);
414 return e == 0 || e == -1;
417 [[nodiscard]]
static std::tuple<int, long long, long long>
align(decimal lhs, decimal rhs)
noexcept
419 auto lhs_e = lhs.exponent();
420 auto lhs_m = lhs.mantissa();
421 auto rhs_e = rhs.exponent();
422 auto rhs_m = rhs.mantissa();
424 if (lhs_e == rhs_e) {
426 }
else if (lhs_e > rhs_e) {
430 if (!is_valid_mantissa(lhs_m)) {
431 while (lhs_e > rhs_e) {
437 }
while (lhs_e > rhs_e);
442 if (!is_valid_mantissa(lhs_m)) {
443 while (lhs_e < rhs_e) {
449 }
while (lhs_e < rhs_e);
451 return {lhs_e, lhs_m, rhs_m};
456 [[nodiscard]]
constexpr static uint64_t pack(
int e,
long long m)
noexcept
459 while (!is_valid_mantissa(m)) {
460 [[unlikely]] m /= 10;
465 while (e > exponent_max) {
466 [[unlikely]]
if ((m *= 10) == 0)
477 while (e < exponent_min) {
478 [[unlikely]]
if ((m /= 10) == 0)
486 return std::bit_cast<uint64_t>(narrow_cast<int64_t>(m) << exponent_bits) | std::bit_cast<uint8_t>(narrow_cast<int8_t>(e));
489 [[nodiscard]]
static std::pair<int, long long> to_exponent_mantissa(
double x)
noexcept
494 auto e2 = narrow_cast<int>((x_ << 1) >> 53) - 1023 - 52;
495 auto m = narrow_cast<long long>((x_ << 12) >> 12);
496 if (e2 > (-1023 - 52)) {
501 if (narrow_cast<int64_t>(x_) < 0) {
511 while (is_valid_mantissa(m)) {
520 while (!is_valid_mantissa(m)) {
531 [[nodiscard]] std::pair<int, long long> to_exponent_mantissa(std::string_view str)
533 std::string mantissa_str;
536 int nr_digits_in_front_of_point = -1;
537 for (
hilet c : str) {
538 if (c >=
'0' && c <=
'9') {
541 }
else if (c ==
'.') {
542 nr_digits_in_front_of_point = nr_digits;
543 }
else if (c ==
'\'' || c ==
',') {
545 }
else if (c ==
'-') {
548 throw parse_error(std::format(
"Unexpected character in decimal number '{}'", str));
552 int exponent = (nr_digits_in_front_of_point >= 0) ? (nr_digits_in_front_of_point - nr_digits) : 0;
554 auto first = mantissa_str.
data();
555 auto last = first + mantissa_str.
size();
557 hilet result = std::from_chars(first, last, mantissa, 10);
558 if (result.ptr == first) {
559 throw parse_error(std::format(
"Could not parse mantissa '{}'", mantissa_str));
560 }
else if (result.ec == std::errc::result_out_of_range) {
561 throw parse_error(std::format(
"Mantissa '{}' out of range ", mantissa_str));
563 return {exponent, mantissa};