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) {}
34 constexpr decimal &operator=(
decimal const &other)
noexcept =
default;
41 decimal(exponent_mantissa.first, exponent_mantissa.second) {}
43 decimal(std::string_view str) :
decimal(to_exponent_mantissa(str)) {}
47 constexpr decimal(
signed long x) :
decimal(0,
static_cast<signed long long>(x)) {}
48 constexpr decimal(
signed int x) :
decimal(0,
static_cast<signed long long>(x)) {}
49 constexpr decimal(
signed short x) :
decimal(0,
static_cast<signed long long>(x)) {}
50 constexpr decimal(
signed char x) :
decimal(0,
static_cast<signed long long>(x)) {}
52 constexpr decimal(
unsigned long x) :
decimal(0,
static_cast<signed long long>(x)) {}
53 constexpr decimal(
unsigned int x) :
decimal(0,
static_cast<signed long long>(x)) {}
54 constexpr decimal(
unsigned short x) :
decimal(0,
static_cast<signed long long>(x)) {}
55 constexpr decimal(
unsigned char x) :
decimal(0,
static_cast<signed long long>(x)) {}
58 decimal &operator=(std::string_view str)
noexcept {
return *
this = to_exponent_mantissa(str); }
59 constexpr decimal &operator=(
double other)
noexcept {
return *
this = to_exponent_mantissa(other); }
60 constexpr decimal &operator=(
float other)
noexcept {
return *
this = to_exponent_mantissa(other); }
61 constexpr decimal &operator=(
signed long long other)
noexcept { value = decimal::pack(0, other);
return *
this; }
62 constexpr decimal &operator=(
signed long other)
noexcept {
return *
this =
static_cast<signed long long>(other); }
63 constexpr decimal &operator=(
signed int other)
noexcept {
return *
this =
static_cast<signed long long>(other); }
64 constexpr decimal &operator=(
signed short other)
noexcept {
return *
this =
static_cast<signed long long>(other); }
65 constexpr decimal &operator=(
signed char other)
noexcept {
return *
this =
static_cast<signed long long>(other); }
66 constexpr decimal &operator=(
unsigned long long other)
noexcept {
return *
this =
static_cast<signed long long>(other); }
67 constexpr decimal &operator=(
unsigned long other)
noexcept {
return *
this =
static_cast<signed long long>(other); }
68 constexpr decimal &operator=(
unsigned int other)
noexcept {
return *
this =
static_cast<signed long long>(other); }
69 constexpr decimal &operator=(
unsigned short other)
noexcept {
return *
this =
static_cast<signed long long>(other); }
70 constexpr decimal &operator=(
unsigned char other)
noexcept {
return *
this =
static_cast<signed long long>(other); }
72 explicit operator signed long long () {
84 if (!is_valid_mantissa(m)) {
91 explicit operator signed long () {
return numeric_cast<signed long>(
static_cast<signed long long>(*
this)); }
92 explicit operator signed int () {
return numeric_cast<signed int>(
static_cast<signed long long>(*
this)); }
93 explicit operator signed short () {
return numeric_cast<signed short>(
static_cast<signed long long>(*
this)); }
94 explicit operator signed char () {
return numeric_cast<signed char>(
static_cast<signed long long>(*
this)); }
95 explicit operator unsigned long long () {
return numeric_cast<unsigned int>(
static_cast<signed long long>(*
this)); }
96 explicit operator unsigned long () {
return numeric_cast<unsigned long>(
static_cast<signed long long>(*
this)); }
97 explicit operator unsigned int () {
return numeric_cast<unsigned int>(
static_cast<signed long long>(*
this)); }
98 explicit operator unsigned short () {
return numeric_cast<unsigned short>(
static_cast<signed long long>(*
this)); }
99 explicit operator unsigned char () {
return numeric_cast<unsigned char>(
static_cast<signed long long>(*
this)); }
100 explicit operator long double () {
return static_cast<long double>(
mantissa()) * powl(10.0,
exponent()); }
101 explicit operator double () {
return static_cast<double>(
static_cast<long double>(*this)); }
102 explicit operator float () {
return static_cast<float>(
static_cast<long double>(*this)); }
104 size_t hash()
const noexcept {
113 [[nodiscard]]
constexpr int exponent() const noexcept {
114 return static_cast<int8_t
>(value);
121 [[nodiscard]]
constexpr long long mantissa() const noexcept {
122 return static_cast<int64_t
>(value) >> 8;
135 ttlet [e, m] = exponent_mantissa();
141 ttlet [e, lhs_m, rhs_m] = decimal::align(*
this, rhs);
142 value = decimal::pack(e, lhs_m + rhs_m);
146 decimal &operator-=(decimal rhs)
noexcept {
147 ttlet [e, lhs_m, rhs_m] = decimal::align(*
this, rhs);
148 value = decimal::pack(e, lhs_m - rhs_m);
152 decimal &operator*=(decimal rhs)
noexcept {
153 return *
this = *
this * rhs;
156 decimal &operator/=(decimal rhs)
noexcept {
157 return *
this = *
this / rhs;
161 [[nodiscard]]
friend bool operator==(decimal lhs, decimal rhs)
noexcept {
162 ttlet [e, lhs_m, rhs_m] = decimal::align(lhs, rhs);
163 return lhs_m == rhs_m;
166 [[nodiscard]]
friend bool operator<(decimal lhs, decimal rhs)
noexcept {
167 ttlet [e, lhs_m, rhs_m] = decimal::align(lhs, rhs);
168 return lhs_m < rhs_m;
171 [[nodiscard]]
friend bool operator!=(decimal lhs, decimal rhs)
noexcept {
return !(lhs == rhs); }
172 [[nodiscard]]
friend bool operator>(decimal lhs, decimal rhs)
noexcept {
return rhs < lhs; }
173 [[nodiscard]]
friend bool operator<=(decimal lhs, decimal rhs)
noexcept {
return !(lhs > rhs); }
174 [[nodiscard]]
friend bool operator>=(decimal lhs, decimal rhs)
noexcept {
return !(lhs < rhs); }
176 [[nodiscard]]
friend constexpr decimal operator-(decimal rhs)
noexcept {
177 return {rhs.exponent(), -rhs.mantissa()};
180 [[nodiscard]]
friend decimal operator+(decimal lhs, decimal rhs)
noexcept {
181 ttlet [e, lhs_m, rhs_m] = decimal::align(lhs, rhs);
182 return {e, lhs_m + rhs_m};
185 [[nodiscard]]
friend decimal operator-(decimal lhs, decimal rhs)
noexcept {
186 ttlet [e, lhs_m, rhs_m] = decimal::align(lhs, rhs);
187 return {e, lhs_m - rhs_m};
190 [[nodiscard]]
friend decimal operator*(decimal lhs, decimal rhs)
noexcept {
191 auto lhs_e = lhs.exponent();
192 auto lhs_m = lhs.mantissa();
193 auto rhs_e = rhs.exponent();
194 auto rhs_m = rhs.mantissa();
197 if (tt_likely(!mul_overflow(lhs_m, rhs_m, &m))) {
198 return {lhs_e + rhs_e, m};
204 while (mul_overflow(lhs_m, rhs_m, &m)) {
216 return {lhs_e + rhs_e, m};
219 [[nodiscard]]
friend decimal operator/(decimal lhs, decimal rhs)
noexcept {
220 auto rhs_m = rhs.mantissa();
221 tt_assume(rhs_m != 0);
222 auto rhs_e = rhs.exponent();
223 auto lhs_m = lhs.mantissa();
224 auto lhs_e = lhs.exponent();
226 std::tie(lhs_e, lhs_m) = decimal::denormalize(lhs_e, lhs_m);
227 return { lhs_e - rhs_e, lhs_m / rhs_m };
230 [[nodiscard]]
friend decimal operator%(decimal lhs, decimal rhs)
noexcept {
231 auto rhs_m = rhs.mantissa();
232 tt_assume(rhs_m != 0);
233 auto rhs_e = rhs.exponent();
234 auto lhs_m = lhs.mantissa();
235 auto lhs_e = lhs.exponent();
237 std::tie(lhs_e, lhs_m) = decimal::denormalize(lhs_e, lhs_m);
238 return { lhs_e - rhs_e, lhs_m % rhs_m };
241 [[nodiscard]]
friend std::string to_string(decimal x)
noexcept {
242 auto [e, m] = x.exponent_mantissa();
245 auto decimal_position = -e;
246 auto leading_zeros = (decimal_position - ssize(s)) + 1;
247 if (leading_zeros > 0) {
248 s.insert(0, leading_zeros,
'0');
251 auto trailing_zeros = e;
252 if (trailing_zeros > 0) {
253 s.append(trailing_zeros,
'0');
256 if (decimal_position > 0) {
257 s.insert(s.size() - decimal_position, 1,
'.');
268 return lhs << to_string(rhs);
278 while (m % 10 == 0) {
293 while (is_valid_mantissa(m)) {
304 [[nodiscard]]
constexpr static bool is_valid_mantissa(
long long m)
noexcept {
305 m >>= (mantissa_bits - 1);
306 return m == 0 || m == -1;
312 [[nodiscard]]
constexpr static bool is_valid_exponent(
int e)
noexcept {
313 e >>= (exponent_bits - 1);
314 return e == 0 || e == -1;
319 auto lhs_e = lhs.exponent();
320 auto lhs_m = lhs.mantissa();
321 auto rhs_e = rhs.exponent();
322 auto rhs_m = rhs.mantissa();
324 if (lhs_e == rhs_e) {
326 }
else if (lhs_e > rhs_e) {
330 if (!is_valid_mantissa(lhs_m)) {
331 while (lhs_e > rhs_e) {
337 }
while (lhs_e > rhs_e);
342 if (!is_valid_mantissa(lhs_m)) {
343 while (lhs_e < rhs_e) {
349 }
while (lhs_e < rhs_e);
351 return {lhs_e, lhs_m, rhs_m};
356 [[nodiscard]]
constexpr static uint64_t pack(
int e,
long long m)
noexcept {
358 while (tt_unlikely(!is_valid_mantissa(m))) {
361 tt_assert(e <= exponent_max);
364 while (tt_unlikely(e > exponent_max)) {
365 if ((m *= 10) == 0) {
372 tt_assert(is_valid_mantissa(m));
375 while (tt_unlikely(e < exponent_min)) {
376 if ((m /= 10) == 0) {
384 static_cast<uint64_t
>(m) << exponent_bits |
385 static_cast<uint8_t
>(e);
392 auto e2 =
static_cast<int>((x_ << 1) >> 53) - 1023 - 52;
393 auto m =
static_cast<long long>((x_ << 12) >> 12);
394 if (e2 > (-1023 - 52)) {
399 if (
static_cast<int64_t
>(x_) < 0) {
409 while (is_valid_mantissa(m)) {
418 while (!is_valid_mantissa(m)) {
433 int nr_digits_in_front_of_point = -1;
435 if (c >=
'0' && c <=
'9') {
438 }
else if (c ==
'.') {
439 nr_digits_in_front_of_point = nr_digits;
440 }
else if (c ==
'\'' || c ==
',') {
442 }
else if (c ==
'-') {
445 TTAURI_THROW_PARSE_ERROR(
"Unexpected character in decimal number '{}'", str);
449 int exponent = (nr_digits_in_front_of_point >= 0) ? (nr_digits_in_front_of_point - nr_digits) : 0;
451 auto first = mantissa_str.
data();
452 auto last = first + mantissa_str.
size();
454 auto result = std::from_chars(first, last,
mantissa, 10);
455 if (result.ptr == first) {
456 TTAURI_THROW_PARSE_ERROR(
"Could not parse mantissa '{}'", mantissa_str);
457 }
else if (result.ec == std::errc::result_out_of_range) {
458 TTAURI_THROW_PARSE_ERROR(
"Mantissa '{}' out of range ", mantissa_str);