14#ifndef SST_CORE_DECIMAL_FIXEDPOINT_H
15#define SST_CORE_DECIMAL_FIXEDPOINT_H
17#include "sst/core/from_string.h"
40template <
int whole_words,
int fraction_words>
45 static constexpr uint32_t storage_radix = 100000000;
46 static constexpr uint64_t storage_radix_long = 100000000l;
47 static constexpr int32_t digits_per_word = 8;
61 template <
int A,
int B>
62 friend class sst_dec_fixed;
73 uint32_t data[whole_words + fraction_words];
87 void from_string(
const std::string& init_str)
89 std::string init(init_str);
91 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
96 if ( init[0] ==
'-' ) {
98 init = init.substr(1, init.npos);
102 size_t exponent_pos = init.find_last_of(
"eE");
103 int32_t exponent = 0;
104 if ( exponent_pos != init.npos ) {
105 exponent =
static_cast<int32_t
>(SST::Core::from_string<double>(init.substr(exponent_pos + 1, init.npos)));
106 init = init.substr(0, exponent_pos);
109 int dp = init.length();
110 for (
size_t i = 0; i < init.length(); ++i ) {
111 if ( init[i] ==
'.' ) {
120 int start_of_digits = (fraction_words * digits_per_word) - (init.length() - dp) + exponent;
124 int start_pos_word = start_of_digits % digits_per_word;
126 for (
int i = 0; i < start_pos_word; i++ ) {
130 for (
int i = init.length() - 1; i >= 0; --i ) {
131 int digit = start_of_digits + (init.length() - 1 - i);
132 int word = (digit / digits_per_word);
134 data[word] += (SST::Core::from_string<uint32_t>(init.substr(i, 1)) * mult);
136 if ( mult == storage_radix ) mult = 1;
145 void from_uint64(uint64_t init)
149 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
162 for (
int i = fraction_words; i < whole_words + fraction_words; ++i ) {
163 data[i] = init % storage_radix_long;
164 init /= storage_radix_long;
173 void from_double(
double init)
177 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
182 for (
int i = 0; i < whole_words - 1; ++i ) {
183 factor *= storage_radix;
186 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
187 data[i] =
static_cast<uint32_t
>(init / factor);
188 init -= (data[i] * factor);
189 factor /= storage_radix;
202 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
233 decimal_fixedpoint(T init, std::enable_if_t<std::is_signed_v<T> && std::is_integral_v<T>>* =
nullptr)
262 negative = init.negative;
263 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
264 data[i] = init.data[i];
273 negative = v.negative;
274 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
325 void negate() { negative = negative ^ 0x1; }
335 for (
int i = 0; i < fraction_words; ++i ) {
336 factor /= storage_radix;
339 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
340 ret += (
static_cast<double>(data[i]) * factor);
341 factor *= storage_radix;
355 for (
int i = 0; i < whole_words; ++i ) {
356 ret += (
static_cast<int64_t
>(data[fraction_words + i]) * factor);
357 factor *= storage_radix;
362 if ( data[fraction_words - 1] > (storage_radix / 2) ) {
365 else if ( data[fraction_words - 1] == (storage_radix / 2) ) {
366 for (
int i = fraction_words - 2; i >= 0; --i ) {
367 if ( data[i] != 0 ) {
376 if ( ret % 2 == 1 ) round =
true;
380 if ( negative ) ret = -ret;
392 for (
int i = 0; i < whole_words; ++i ) {
393 ret += (
static_cast<int64_t
>(data[i]) * factor);
394 factor *= storage_radix;
404 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
405 if ( data[i] != 0 )
return false;
413 template <
typename T>
414 T
convert_to(std::enable_if_t<std::is_unsigned_v<T>>* =
nullptr)
const
422 template <
typename T>
423 T
convert_to(std::enable_if_t<std::is_signed_v<T> && std::is_integral_v<T>>* =
nullptr)
const
425 return static_cast<T
>(
toLong());
431 template <
typename T>
432 T
convert_to(std::enable_if_t<std::is_floating_point_v<T>>* =
nullptr)
const
446 std::stringstream stream;
447 if ( precision <= 0 || precision > ((whole_words + fraction_words) * digits_per_word) )
448 precision = (whole_words + fraction_words) * digits_per_word;
452 constexpr int num_digits = (whole_words + fraction_words) * digits_per_word;
454 unsigned char digits[num_digits];
455 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
456 uint32_t value = data[i];
457 for (
int j = 0; j < digits_per_word; ++j ) {
458 digits[i * digits_per_word + j] = value % 10;
464 int first_non_zero = -1;
465 for (
int i = num_digits - 1; i >= 0; --i ) {
466 if ( digits[i] != 0 ) {
473 if ( first_non_zero == -1 )
return "0";
476 int round_position = first_non_zero - precision;
481 if ( round_position >= 0 ) {
482 if ( digits[round_position] > 5 )
484 else if ( digits[round_position] < 5 )
488 for (
int i = round_position - 1; i >= 0; --i ) {
489 if ( digits[i] != 0 ) {
497 if ( digits[round_position + 1] % 2 == 1 ) round =
true;
503 unsigned char carry = 1;
504 for (
int i = round_position + 1; i < num_digits; ++i ) {
506 carry = digits[i] / 10;
507 digits[i] = digits[i] % 10;
512 for (
int i = 0; i <= round_position; ++i ) {
518 if ( negative ) stream <<
'-';
522 for (
int i = num_digits - 1; i >= 0; --i ) {
523 if ( digits[i] != 0 ) {
530 if ( first_non_zero == -1 ) {
533 stream <<
"1e+" << (whole_words * digits_per_word);
540 if ( first_non_zero >= ((fraction_words * digits_per_word) + precision) ) {
542 int exponent = first_non_zero - (fraction_words * digits_per_word);
543 stream << static_cast<uint32_t>(digits[first_non_zero]) <<
".";
545 for (
int i = first_non_zero - 1; i >= first_non_zero - precision; --i ) {
549 if ( digits[i] == 0 )
552 for (
int j = 0; j < zeros; ++j ) {
555 stream << static_cast<uint32_t>(digits[i]);
559 std::string ret = stream.str();
560 if ( ret[ret.length() - 1] ==
'.' ) {
561 ret = ret.substr(0, ret.length() - 1);
562 stream.str(std::string(
""));
565 stream <<
"e+" << std::setfill(
'0') << std::setw(2) << exponent;
570 else if ( first_non_zero >= (fraction_words * digits_per_word) ) {
572 for (
int i = first_non_zero; i >= (fraction_words * digits_per_word); --i ) {
574 stream << static_cast<uint32_t>(digits[i]);
579 for (
int i = (fraction_words * digits_per_word) - 1; i >= first_non_zero - precision && (i >= 0); --i ) {
583 if ( digits[i] == 0 )
586 for (
int j = 0; j < zeros; ++j ) {
589 stream << static_cast<uint32_t>(digits[i]);
593 std::string ret = stream.str();
594 if ( ret[ret.length() - 1] ==
'.' ) {
595 ret = ret.substr(0, ret.length() - 1);
596 stream.str(std::string(
""));
604 else if ( first_non_zero > (fraction_words * digits_per_word) - 5 ) {
606 for (
int i = (fraction_words * digits_per_word) - 1; i > first_non_zero; --i ) {
610 for (
int i = first_non_zero; (i >= first_non_zero - precision) && (i >= 0); --i ) {
614 if ( digits[i] == 0 )
617 for (
int j = 0; j < zeros; ++j ) {
620 stream << static_cast<uint32_t>(digits[i]);
628 int exponent = first_non_zero - (fraction_words * digits_per_word);
629 exponent = -exponent;
630 stream << static_cast<uint32_t>(digits[first_non_zero]) <<
".";
632 for (
int i = first_non_zero - 1; (i >= first_non_zero - precision) && (i >= 0); --i ) {
636 if ( digits[i] == 0 )
639 for (
int j = 0; j < zeros; ++j ) {
642 stream << static_cast<uint32_t>(digits[i]);
646 std::string ret = stream.str();
647 if ( ret[ret.length() - 1] ==
'.' ) {
648 ret = ret.substr(0, ret.length() - 1);
649 stream.str(std::string(
""));
652 stream <<
"e-" << std::setfill(
'0') << std::setw(2) << exponent;
667 if ( (negative ^ v.negative) == 0 ) {
670 uint64_t carry_over = 0;
671 for (
int i = 0; i < whole_words + fraction_words; i++ ) {
672 uint64_t value =
static_cast<uint64_t
>(data[i]) +
static_cast<uint64_t
>(v.data[i]) + carry_over;
673 carry_over = value / storage_radix;
675 data[i] = value % storage_radix;
681 if (
operator>=(v) ) {
684 uint64_t carry_over = 1;
685 for (
int i = 0; i < whole_words + fraction_words; i++ ) {
686 uint64_t
negate =
static_cast<uint64_t
>(storage_radix - 1) -
static_cast<uint64_t
>(v.data[i]);
688 uint64_t value =
static_cast<uint64_t
>(data[i]) +
negate + carry_over;
689 carry_over = value / storage_radix;
690 data[i] =
static_cast<uint32_t
>(value % storage_radix);
697 uint64_t carry_over = 1;
698 for (
int i = 0; i < whole_words + fraction_words; i++ ) {
699 uint64_t
negate =
static_cast<uint64_t
>(storage_radix - 1) -
static_cast<uint64_t
>(data[i]);
701 uint64_t value =
static_cast<uint64_t
>(v.data[i]) +
negate + carry_over;
702 carry_over = value / storage_radix;
703 data[i] =
static_cast<uint32_t
>(value % storage_radix);
706 negative = v.negative;
738 uint64_t carry_over = 0;
739 for (
int i = 0; i < fraction_words; ++i ) {
740 uint64_t sum = carry_over;
741 for (
int j = 0; j <= i; ++j ) {
742 sum +=
static_cast<uint64_t
>(me.data[j]) *
static_cast<uint64_t
>(v.data[i - j]);
744 carry_over = sum / storage_radix_long;
748 for (
int i = fraction_words; i < whole_words + fraction_words; ++i ) {
749 uint64_t sum = carry_over;
750 for (
int j = 0; j <= i; ++j ) {
751 sum +=
static_cast<uint64_t
>(me.data[j]) *
static_cast<uint64_t
>(v.data[i - j]);
753 carry_over = sum / storage_radix_long;
754 data[i - fraction_words] =
static_cast<uint32_t
>(sum % storage_radix_long);
757 for (
int i = 0; i < fraction_words; ++i ) {
758 uint64_t sum = carry_over;
759 for (
int j = i + 1; j < whole_words + fraction_words; ++j ) {
760 sum +=
static_cast<uint64_t
>(me.data[j]) *
761 static_cast<uint64_t
>(v.data[whole_words + fraction_words + i - j]);
763 carry_over = sum / storage_radix_long;
764 data[i + whole_words] =
static_cast<uint32_t
>(sum % storage_radix_long);
767 negative = negative ^ v.negative;
806 int digits_of_prec = std::numeric_limits<double>::digits10 / 2;
809 for (
int i = digits_of_prec; i <= (whole_words + fraction_words) * digits_per_word; i *= 2 ) {
828 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
829 if ( data[i] != v.data[i] )
return false;
841 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
842 if ( data[i] != v.data[i] )
return true;
854 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
855 if ( data[i] > v.data[i] )
return true;
856 if ( data[i] < v.data[i] )
return false;
869 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
870 if ( data[i] > v.data[i] )
return true;
871 if ( data[i] < v.data[i] )
return false;
883 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
884 if ( data[i] < v.data[i] )
return true;
885 if ( data[i] > v.data[i] )
return false;
898 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
899 if ( data[i] < v.data[i] )
return true;
900 if ( data[i] > v.data[i] )
return false;
906template <
int whole_words,
int fraction_words>
907decimal_fixedpoint<whole_words, fraction_words>
908operator+(decimal_fixedpoint<whole_words, fraction_words> lhs, decimal_fixedpoint<whole_words, fraction_words> rhs)
910 decimal_fixedpoint<whole_words, fraction_words> ret(lhs);
914template <
int whole_words,
int fraction_words>
922template <
int whole_words,
int fraction_words>
930template <
int whole_words,
int fraction_words>
938template <
int whole_words,
int fraction_words,
typename T>
945template <
int whole_words,
int fraction_words,
typename T>
952template <
int whole_words,
int fraction_words>
956 os << rhs.toString(os.precision());
Class that implements a decimal fixed-point number.
Definition decimal_fixedpoint.h:42
decimal_fixedpoint(const std::string &init)
Build a decimal_fixedpoint using a string initializer.
Definition decimal_fixedpoint.h:214
std::string toString(int32_t precision=6) const
Create a string representation of this decimal_fixedpoint.
Definition decimal_fixedpoint.h:443
decimal_fixedpoint & inverse()
Inverts the number (1 divided by this number)
Definition decimal_fixedpoint.h:789
bool operator>(const decimal_fixedpoint &v) const
Checks to see if this number is greater than another number.
Definition decimal_fixedpoint.h:852
decimal_fixedpoint(T init, std::enable_if_t< std::is_signed_v< T > &&std::is_integral_v< T > > *=nullptr)
Build a decimal_fixedpoint using a 64-bit signed number.
Definition decimal_fixedpoint.h:233
decimal_fixedpoint & operator=(const std::string &v)
Equal operator for string.
Definition decimal_fixedpoint.h:316
decimal_fixedpoint & operator=(const decimal_fixedpoint &v)
Equal operator for other decimal_fixedpoint objects.
Definition decimal_fixedpoint.h:271
decimal_fixedpoint(const decimal_fixedpoint &init)
Build a decimal_fixedpoint using another decimal_fixedpoint.
Definition decimal_fixedpoint.h:260
T convert_to(std::enable_if_t< std::is_signed_v< T > &&std::is_integral_v< T > > *=nullptr) const
Templated conversion function for signed integral types.
Definition decimal_fixedpoint.h:423
bool operator!=(const decimal_fixedpoint &v) const
Checks to see if two numbers are not equal.
Definition decimal_fixedpoint.h:839
constexpr int getWholeWords() const
Get the value of whole_words template parameter.
Definition decimal_fixedpoint.h:52
int64_t toLong() const
Return a int64_t version of the decimal_fixedpoint.
Definition decimal_fixedpoint.h:351
T convert_to(std::enable_if_t< std::is_unsigned_v< T > > *=nullptr) const
Templated conversion function for unsigned types.
Definition decimal_fixedpoint.h:414
decimal_fixedpoint & operator=(int64_t v)
Equal operator for 64-bit signed int.
Definition decimal_fixedpoint.h:292
double toDouble() const
Return a double precision version of the decimal_fixedpoint.
Definition decimal_fixedpoint.h:331
decimal_fixedpoint & operator+=(const decimal_fixedpoint &v)
Adds another number to this one and sets it equal to the result.
Definition decimal_fixedpoint.h:664
decimal_fixedpoint(T init, std::enable_if_t< std::is_unsigned_v< T > > *=nullptr)
Build a decimal_fixedpoint using a 64-bit unsigned number.
Definition decimal_fixedpoint.h:222
decimal_fixedpoint & operator=(double v)
Equal operator for double.
Definition decimal_fixedpoint.h:307
bool isZero() const
Return true if value is zero, otherwise return false.
Definition decimal_fixedpoint.h:402
decimal_fixedpoint()
Default constructor.
Definition decimal_fixedpoint.h:199
uint64_t toUnsignedLong() const
Return a uint64_t version of the decimal_fixedpoint.
Definition decimal_fixedpoint.h:388
decimal_fixedpoint & operator/=(const decimal_fixedpoint &v)
Divides another number from this one and sets it equal to the result.
Definition decimal_fixedpoint.h:777
bool operator<(const decimal_fixedpoint &v) const
Checks to see if this number is less than another number.
Definition decimal_fixedpoint.h:881
bool operator==(const decimal_fixedpoint &v) const
Checks to see if two numbers are equal.
Definition decimal_fixedpoint.h:826
void negate()
Negate the value (change the sign bit).
Definition decimal_fixedpoint.h:325
decimal_fixedpoint(const T init, std::enable_if_t< std::is_floating_point_v< T > > *=nullptr)
Build a decimal_fixedpoint using a double.
Definition decimal_fixedpoint.h:250
decimal_fixedpoint & operator=(uint64_t v)
Equal operator for 64-bit unsigned int.
Definition decimal_fixedpoint.h:283
decimal_fixedpoint & operator-=(const decimal_fixedpoint &v)
Subtracts another number from this one and sets it equal to the result.
Definition decimal_fixedpoint.h:717
T convert_to(std::enable_if_t< std::is_floating_point_v< T > > *=nullptr) const
Templated conversion function for floating point types.
Definition decimal_fixedpoint.h:432
bool operator<=(const decimal_fixedpoint &v) const
Checks to see if this number is less than or equal to another number.
Definition decimal_fixedpoint.h:896
bool operator>=(const decimal_fixedpoint &v) const
Checks to see if this number is greater than or equal to another number.
Definition decimal_fixedpoint.h:867
constexpr int getFractionWords() const
Get the value of fraction_words template parameter.
Definition decimal_fixedpoint.h:57
decimal_fixedpoint & operator*=(const decimal_fixedpoint &v)
Multiplies another number to this one and sets it equal to the result.
Definition decimal_fixedpoint.h:730