14 #ifndef SST_CORE_DECIMAL_FIXEDPOINT_H 15 #define SST_CORE_DECIMAL_FIXEDPOINT_H 17 #include "sst/core/from_string.h" 26 #include <type_traits> 43 template <
int whole_words,
int fraction_words>
48 static constexpr uint32_t storage_radix = 100000000;
49 static constexpr uint64_t storage_radix_long = 100000000l;
50 static constexpr int32_t digits_per_word = 8;
64 template <
int A,
int B>
65 friend class sst_dec_fixed;
76 uint32_t data[whole_words + fraction_words];
90 void from_string(
const std::string& init_str)
92 std::string init(init_str);
94 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
99 if ( init[0] ==
'-' ) {
101 init = init.substr(1, init.npos);
105 size_t exponent_pos = init.find_last_of(
"eE");
106 int32_t exponent = 0;
107 if ( exponent_pos != init.npos ) {
108 exponent =
static_cast<int32_t
>(SST::Core::from_string<double>(init.substr(exponent_pos + 1, init.npos)));
109 init = init.substr(0, exponent_pos);
112 int dp = init.length();
113 for (
size_t i = 0; i < init.length(); ++i ) {
114 if ( init[i] ==
'.' ) {
123 int start_of_digits = (fraction_words * digits_per_word) - (init.length() - dp) + exponent;
127 int start_pos_word = start_of_digits % digits_per_word;
129 for (
int i = 0; i < start_pos_word; i++ ) {
133 for (
int i = init.length() - 1; i >= 0; --i ) {
134 int digit = start_of_digits + (init.length() - 1 - i);
135 int word = (digit / digits_per_word);
137 data[word] += (SST::Core::from_string<uint32_t>(init.substr(i, 1)) * mult);
139 if ( mult == storage_radix ) mult = 1;
148 void from_uint64(uint64_t init)
152 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
165 for (
int i = fraction_words; i < whole_words + fraction_words; ++i ) {
166 data[i] = init % storage_radix_long;
167 init /= storage_radix_long;
176 void from_double(
double init)
180 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
185 for (
int i = 0; i < whole_words - 1; ++i ) {
186 factor *= storage_radix;
189 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
190 data[i] =
static_cast<uint32_t
>(init / factor);
191 init -= (data[i] * factor);
192 factor /= storage_radix;
205 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
236 decimal_fixedpoint(T init, std::enable_if_t<std::is_signed_v<T> && std::is_integral_v<T>>* =
nullptr)
265 negative = init.negative;
266 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
267 data[i] = init.data[i];
276 negative = v.negative;
277 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
328 void negate() { negative = negative ^ 0x1; }
338 for (
int i = 0; i < fraction_words; ++i ) {
339 factor /= storage_radix;
342 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
343 ret += (
static_cast<double>(data[i]) * factor);
344 factor *= storage_radix;
358 for (
int i = 0; i < whole_words; ++i ) {
359 ret += (
static_cast<int64_t
>(data[fraction_words + i]) * factor);
360 factor *= storage_radix;
365 if ( data[fraction_words - 1] > (storage_radix / 2) ) {
368 else if ( data[fraction_words - 1] == (storage_radix / 2) ) {
369 for (
int i = fraction_words - 2; i >= 0; --i ) {
370 if ( data[i] != 0 ) {
379 if ( ret % 2 == 1 ) round =
true;
383 if ( negative ) ret = -ret;
395 for (
int i = 0; i < whole_words; ++i ) {
396 ret += (
static_cast<int64_t
>(data[i]) * factor);
397 factor *= storage_radix;
407 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
408 if ( data[i] != 0 )
return false;
416 template <
typename T>
417 T
convert_to(std::enable_if_t<std::is_unsigned_v<T>>* =
nullptr)
const 425 template <
typename T>
426 T
convert_to(std::enable_if_t<std::is_signed_v<T> && std::is_integral_v<T>>* =
nullptr)
const 428 return static_cast<T
>(
toLong());
434 template <
typename T>
435 T
convert_to(std::enable_if_t<std::is_floating_point_v<T>>* =
nullptr)
const 449 std::stringstream stream;
450 if ( precision <= 0 || precision > ((whole_words + fraction_words) * digits_per_word) )
451 precision = (whole_words + fraction_words) * digits_per_word;
455 constexpr
int num_digits = (whole_words + fraction_words) * digits_per_word;
457 unsigned char digits[num_digits];
458 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
459 uint32_t value = data[i];
460 for (
int j = 0; j < digits_per_word; ++j ) {
461 digits[i * digits_per_word + j] = value % 10;
467 int first_non_zero = -1;
468 for (
int i = num_digits - 1; i >= 0; --i ) {
469 if ( digits[i] != 0 ) {
476 if ( first_non_zero == -1 )
return "0";
479 int round_position = first_non_zero - precision;
484 if ( round_position >= 0 ) {
485 if ( digits[round_position] > 5 )
487 else if ( digits[round_position] < 5 )
491 for (
int i = round_position - 1; i >= 0; --i ) {
492 if ( digits[i] != 0 ) {
500 if ( digits[round_position + 1] % 2 == 1 ) round =
true;
506 unsigned char carry = 1;
507 for (
int i = round_position + 1; i < num_digits; ++i ) {
509 carry = digits[i] / 10;
510 digits[i] = digits[i] % 10;
515 for (
int i = 0; i <= round_position; ++i ) {
521 if ( negative ) stream <<
'-';
525 for (
int i = num_digits - 1; i >= 0; --i ) {
526 if ( digits[i] != 0 ) {
533 if ( first_non_zero == -1 ) {
536 stream <<
"1e+" << (whole_words * digits_per_word);
543 if ( first_non_zero >= ((fraction_words * digits_per_word) + precision) ) {
545 int exponent = first_non_zero - (fraction_words * digits_per_word);
546 stream << static_cast<uint32_t>(digits[first_non_zero]) <<
".";
548 for (
int i = first_non_zero - 1; i >= first_non_zero - precision; --i ) {
552 if ( digits[i] == 0 )
555 for (
int j = 0; j < zeros; ++j ) {
558 stream << static_cast<uint32_t>(digits[i]);
562 std::string ret = stream.str();
563 if ( ret[ret.length() - 1] ==
'.' ) {
564 ret = ret.substr(0, ret.length() - 1);
565 stream.str(std::string(
""));
568 stream <<
"e+" << std::setfill(
'0') << std::setw(2) << exponent;
573 else if ( first_non_zero >= (fraction_words * digits_per_word) ) {
575 for (
int i = first_non_zero; i >= (fraction_words * digits_per_word); --i ) {
577 stream << static_cast<uint32_t>(digits[i]);
582 for (
int i = (fraction_words * digits_per_word) - 1; i >= first_non_zero - precision && (i >= 0); --i ) {
586 if ( digits[i] == 0 )
589 for (
int j = 0; j < zeros; ++j ) {
592 stream << static_cast<uint32_t>(digits[i]);
596 std::string ret = stream.str();
597 if ( ret[ret.length() - 1] ==
'.' ) {
598 ret = ret.substr(0, ret.length() - 1);
599 stream.str(std::string(
""));
607 else if ( first_non_zero > (fraction_words * digits_per_word) - 5 ) {
609 for (
int i = (fraction_words * digits_per_word) - 1; i > first_non_zero; --i ) {
613 for (
int i = first_non_zero; (i >= first_non_zero - precision) && (i >= 0); --i ) {
617 if ( digits[i] == 0 )
620 for (
int j = 0; j < zeros; ++j ) {
623 stream << static_cast<uint32_t>(digits[i]);
631 int exponent = first_non_zero - (fraction_words * digits_per_word);
632 exponent = -exponent;
633 stream << static_cast<uint32_t>(digits[first_non_zero]) <<
".";
635 for (
int i = first_non_zero - 1; (i >= first_non_zero - precision) && (i >= 0); --i ) {
639 if ( digits[i] == 0 )
642 for (
int j = 0; j < zeros; ++j ) {
645 stream << static_cast<uint32_t>(digits[i]);
649 std::string ret = stream.str();
650 if ( ret[ret.length() - 1] ==
'.' ) {
651 ret = ret.substr(0, ret.length() - 1);
652 stream.str(std::string(
""));
655 stream <<
"e-" << std::setfill(
'0') << std::setw(2) << exponent;
670 if ( (negative ^ v.negative) == 0 ) {
673 uint64_t carry_over = 0;
674 for (
int i = 0; i < whole_words + fraction_words; i++ ) {
675 uint64_t value =
static_cast<uint64_t
>(data[i]) + static_cast<uint64_t>(v.data[i]) + carry_over;
676 carry_over = value / storage_radix;
678 data[i] = value % storage_radix;
684 if (
operator>=(v) ) {
687 uint64_t carry_over = 1;
688 for (
int i = 0; i < whole_words + fraction_words; i++ ) {
689 uint64_t
negate =
static_cast<uint64_t
>(storage_radix - 1) - static_cast<uint64_t>(v.data[i]);
691 uint64_t value =
static_cast<uint64_t
>(data[i]) +
negate + carry_over;
692 carry_over = value / storage_radix;
693 data[i] =
static_cast<uint32_t
>(value % storage_radix);
700 uint64_t carry_over = 1;
701 for (
int i = 0; i < whole_words + fraction_words; i++ ) {
702 uint64_t
negate =
static_cast<uint64_t
>(storage_radix - 1) - static_cast<uint64_t>(data[i]);
704 uint64_t value =
static_cast<uint64_t
>(v.data[i]) +
negate + carry_over;
705 carry_over = value / storage_radix;
706 data[i] =
static_cast<uint32_t
>(value % storage_radix);
709 negative = v.negative;
741 uint64_t carry_over = 0;
742 for (
int i = 0; i < fraction_words; ++i ) {
743 uint64_t sum = carry_over;
744 for (
int j = 0; j <= i; ++j ) {
745 sum +=
static_cast<uint64_t
>(me.data[j]) * static_cast<uint64_t>(v.data[i - j]);
747 carry_over = sum / storage_radix_long;
751 for (
int i = fraction_words; i < whole_words + fraction_words; ++i ) {
752 uint64_t sum = carry_over;
753 for (
int j = 0; j <= i; ++j ) {
754 sum +=
static_cast<uint64_t
>(me.data[j]) * static_cast<uint64_t>(v.data[i - j]);
756 carry_over = sum / storage_radix_long;
757 data[i - fraction_words] =
static_cast<uint32_t
>(sum % storage_radix_long);
760 for (
int i = 0; i < fraction_words; ++i ) {
761 uint64_t sum = carry_over;
762 for (
int j = i + 1; j < whole_words + fraction_words; ++j ) {
763 sum +=
static_cast<uint64_t
>(me.data[j]) *
764 static_cast<uint64_t>(v.data[whole_words + fraction_words + i - j]);
766 carry_over = sum / storage_radix_long;
767 data[i + whole_words] =
static_cast<uint32_t
>(sum % storage_radix_long);
770 negative = negative ^ v.negative;
809 int digits_of_prec = std::numeric_limits<double>::digits10 / 2;
812 for (
int i = digits_of_prec; i <= (whole_words + fraction_words) * digits_per_word; i *= 2 ) {
831 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
832 if ( data[i] != v.data[i] )
return false;
844 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
845 if ( data[i] != v.data[i] )
return true;
857 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
858 if ( data[i] > v.data[i] )
return true;
859 if ( data[i] < v.data[i] )
return false;
872 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
873 if ( data[i] > v.data[i] )
return true;
874 if ( data[i] < v.data[i] )
return false;
886 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
887 if ( data[i] < v.data[i] )
return true;
888 if ( data[i] > v.data[i] )
return false;
901 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
902 if ( data[i] < v.data[i] )
return true;
903 if ( data[i] > v.data[i] )
return false;
909 template <
int whole_words,
int fraction_words>
910 decimal_fixedpoint<whole_words, fraction_words>
911 operator+(decimal_fixedpoint<whole_words, fraction_words> lhs, decimal_fixedpoint<whole_words, fraction_words> rhs)
913 decimal_fixedpoint<whole_words, fraction_words> ret(lhs);
917 template <
int whole_words,
int fraction_words>
918 decimal_fixedpoint<whole_words, fraction_words>
919 operator-(decimal_fixedpoint<whole_words, fraction_words> lhs, decimal_fixedpoint<whole_words, fraction_words> rhs)
921 decimal_fixedpoint<whole_words, fraction_words> ret(lhs);
925 template <
int whole_words,
int fraction_words>
926 decimal_fixedpoint<whole_words, fraction_words>
927 operator*(decimal_fixedpoint<whole_words, fraction_words> lhs, decimal_fixedpoint<whole_words, fraction_words> rhs)
929 decimal_fixedpoint<whole_words, fraction_words> ret(lhs);
933 template <
int whole_words,
int fraction_words>
934 decimal_fixedpoint<whole_words, fraction_words>
935 operator/(decimal_fixedpoint<whole_words, fraction_words> lhs, decimal_fixedpoint<whole_words, fraction_words> rhs)
937 decimal_fixedpoint<whole_words, fraction_words> ret(lhs);
941 template <
int whole_words,
int fraction_words,
typename T>
943 operator==(
const T& lhs,
const decimal_fixedpoint<whole_words, fraction_words>& rhs)
945 return rhs == decimal_fixedpoint<whole_words, fraction_words>(lhs);
948 template <
int whole_words,
int fraction_words,
typename T>
950 operator!=(
const T& lhs,
const decimal_fixedpoint<whole_words, fraction_words>& rhs)
952 return rhs != decimal_fixedpoint<whole_words, fraction_words>(lhs);
955 template <
int whole_words,
int fraction_words>
957 operator<<(std::ostream& os, const decimal_fixedpoint<whole_words, fraction_words>& rhs)
959 os << rhs.toString(os.precision());
965 #endif // SST_CORE_DECIMAL_FIXEDPOINT_H double toDouble() const
Return a double precision version of the decimal_fixedpoint.
Definition: decimal_fixedpoint.h:334
bool operator!=(const decimal_fixedpoint &v) const
Checks to see if two numbers are not equal.
Definition: decimal_fixedpoint.h:842
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:435
decimal_fixedpoint & operator=(uint64_t v)
Equal operator for 64-bit unsigned int.
Definition: decimal_fixedpoint.h:286
decimal_fixedpoint & operator-=(const decimal_fixedpoint &v)
Subtracts another number from this one and sets it equal to the result.
Definition: decimal_fixedpoint.h:720
std::string toString(int32_t precision=6) const
Create a string representation of this decimal_fixedpoint.
Definition: decimal_fixedpoint.h:446
decimal_fixedpoint & inverse()
Inverts the number (1 divided by this number)
Definition: decimal_fixedpoint.h:792
decimal_fixedpoint & operator/=(const decimal_fixedpoint &v)
Divides another number from this one and sets it equal to the result.
Definition: decimal_fixedpoint.h:780
decimal_fixedpoint(const decimal_fixedpoint &init)
Build a decimal_fixedpoint using another decimal_fixedpoint.
Definition: decimal_fixedpoint.h:263
bool operator==(const decimal_fixedpoint &v) const
Checks to see if two numbers are equal.
Definition: decimal_fixedpoint.h:829
decimal_fixedpoint & operator=(double v)
Equal operator for double.
Definition: decimal_fixedpoint.h:310
bool operator>(const decimal_fixedpoint &v) const
Checks to see if this number is greater than another number.
Definition: decimal_fixedpoint.h:855
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:870
constexpr int getWholeWords() const
Get the value of whole_words template parameter.
Definition: decimal_fixedpoint.h:55
T convert_to(std::enable_if_t< std::is_unsigned_v< T >> *=nullptr) const
Templated conversion function for unsigned types.
Definition: decimal_fixedpoint.h:417
decimal_fixedpoint & operator=(const std::string &v)
Equal operator for string.
Definition: decimal_fixedpoint.h:319
decimal_fixedpoint & operator=(int64_t v)
Equal operator for 64-bit signed int.
Definition: decimal_fixedpoint.h:295
decimal_fixedpoint(const std::string &init)
Build a decimal_fixedpoint using a string initializer.
Definition: decimal_fixedpoint.h:217
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:899
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:225
Class that implements a decimal fixed-point number.
Definition: decimal_fixedpoint.h:44
decimal_fixedpoint & operator*=(const decimal_fixedpoint &v)
Multiplies another number to this one and sets it equal to the result.
Definition: decimal_fixedpoint.h:733
uint64_t toUnsignedLong() const
Return a uint64_t version of the decimal_fixedpoint.
Definition: decimal_fixedpoint.h:391
bool operator<(const decimal_fixedpoint &v) const
Checks to see if this number is less than another number.
Definition: decimal_fixedpoint.h:884
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:426
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:253
decimal_fixedpoint()
Default constructor.
Definition: decimal_fixedpoint.h:202
constexpr int getFractionWords() const
Get the value of fraction_words template parameter.
Definition: decimal_fixedpoint.h:60
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:236
decimal_fixedpoint & operator=(const decimal_fixedpoint &v)
Equal operator for other decimal_fixedpoint objects.
Definition: decimal_fixedpoint.h:274
decimal_fixedpoint & operator+=(const decimal_fixedpoint &v)
Adds another number to this one and sets it equal to the result.
Definition: decimal_fixedpoint.h:667
bool isZero() const
Return true if value is zero, otherwise return false.
Definition: decimal_fixedpoint.h:405
int64_t toLong() const
Return a int64_t version of the decimal_fixedpoint.
Definition: decimal_fixedpoint.h:354
void negate()
Negate the value (change the sign bit).
Definition: decimal_fixedpoint.h:328