14 #ifndef SST_CORE_DECIMAL_FIXEDPOINT_H
15 #define SST_CORE_DECIMAL_FIXEDPOINT_H
19 #include <type_traits>
21 #include "sst/core/from_string.h"
38 template <
int whole_words,
int fraction_words>
42 static constexpr uint32_t storage_radix = 100000000;
43 static constexpr uint64_t storage_radix_long = 100000000l;
44 static constexpr int32_t digits_per_word = 8;
57 return fraction_words;
63 template <
int A,
int B>
64 friend class sst_dec_fixed;
75 uint32_t data[whole_words + fraction_words];
90 void from_string(
const std::string& init_str) {
91 std::string init(init_str);
93 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
98 if ( init[0] ==
'-' ) {
100 init = init.substr(1,init.npos);
104 size_t exponent_pos = init.find_last_of(
"eE");
105 int32_t exponent = 0;
106 if ( exponent_pos != init.npos ) {
107 exponent =
static_cast<int32_t
>(SST::Core::from_string<double>(init.substr(exponent_pos+1,init.npos)));
108 init = init.substr(0,exponent_pos);
111 int dp = init.length();
112 for (
size_t i = 0; i < init.length(); ++i ) {
113 if ( init[i] ==
'.' ) {
122 int start_of_digits = (fraction_words * digits_per_word) - (init.length() - dp) + exponent;
126 int start_pos_word = start_of_digits % digits_per_word;
128 for (
int i = 0; i < start_pos_word; i++ ) {
132 for (
int i = init.length() - 1; i >= 0; --i ) {
133 int digit = start_of_digits + ( init.length() - 1 - i );
134 int word = ( digit / digits_per_word );
136 data[word] += (SST::Core::from_string<uint32_t>(init.substr(i,1)) * mult);
138 if (mult == storage_radix) mult = 1;
148 void from_uint64(uint64_t init) {
151 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
164 for (
int i = fraction_words; i < whole_words + fraction_words; ++i ) {
165 data[i] = init % storage_radix_long;
166 init /= storage_radix_long;
175 void from_double(
double init) {
178 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
183 for (
int i = 0; i < whole_words - 1; ++i ) {
184 factor *= storage_radix;
187 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
188 data[i] =
static_cast<uint32_t
>(init / factor);
189 init -= (data[i] * factor);
190 factor /= storage_radix;
203 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
238 std::is_integral<T>::value >::type* =
nullptr) {
254 decimal_fixedpoint(
const T init,
typename std::enable_if<std::is_floating_point<T>::value >::type* =
nullptr) {
264 negative = init.negative;
265 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
266 data[i] = init.data[i];
274 negative = v.negative;
275 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
324 negative = negative ^ 0x1;
334 for (
int i = 0; i < fraction_words; ++i ) {
335 factor /= storage_radix;
338 for (
int i = 0; i <whole_words + fraction_words; ++i ) {
339 ret += (
static_cast<double>(data[i]) * factor );
340 factor *= storage_radix;
353 for (
int i = 0; i < whole_words; ++i ) {
354 ret += (
static_cast<int64_t
>(data[fraction_words + i]) * factor );
355 factor *= storage_radix;
360 if ( data[fraction_words - 1] > ( storage_radix / 2 ) ) {
363 else if ( data[fraction_words - 1] == ( storage_radix / 2 ) ) {
364 for (
int i = fraction_words - 2; i >= 0; --i ) {
365 if ( data[i] != 0 ) {
374 if ( ret % 2 == 1 ) round =
true;
378 if ( negative ) ret = -ret;
389 for (
int i = 0; i < whole_words; ++i ) {
390 ret += (
static_cast<int64_t
>(data[i]) * factor );
391 factor *= storage_radix;
400 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
401 if ( data[i] != 0 )
return false;
410 T
convert_to(
typename std::enable_if<std::is_unsigned<T>::value>::type* = 0)
const {
418 T
convert_to(
typename std::enable_if<std::is_signed<T>::value &&
419 std::is_integral<T>::value >::type* = 0)
const {
420 return static_cast<T
>(
toLong());
427 T
convert_to(
typename std::enable_if<std::is_floating_point<T>::value >::type* = 0)
const {
437 std::string
toString(int32_t precision = 6)
const {
439 std::stringstream stream;
440 if ( precision <= 0 || precision > ((whole_words + fraction_words) * digits_per_word ) )
441 precision = (whole_words + fraction_words) * digits_per_word;
445 constexpr
int num_digits = (whole_words + fraction_words) * digits_per_word;
447 unsigned char digits[num_digits];
448 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
449 uint32_t value = data[i];
450 for (
int j = 0; j < digits_per_word; ++j ) {
451 digits[i*digits_per_word+j] = value % 10;
457 int first_non_zero = -1;
458 for (
int i = num_digits - 1; i >= 0; --i ) {
459 if ( digits[i] != 0 ) {
466 if ( first_non_zero == -1 )
return "0";
469 int round_position = first_non_zero - precision;
474 if ( round_position >= 0 ) {
475 if ( digits[round_position] > 5 ) round =
true;
476 else if ( digits[round_position] < 5 ) round =
false;
479 for (
int i = round_position - 1; i >= 0; --i ) {
480 if ( digits[i] != 0 ) {
488 if ( digits[round_position+1] % 2 == 1 ) round =
true;
494 unsigned char carry = 1;
495 for (
int i = round_position + 1; i < num_digits; ++i ) {
497 carry = digits[i] / 10;
498 digits[i] = digits[i] % 10;
503 for (
int i = 0; i <= round_position; ++i ) {
509 if ( negative ) stream <<
'-';
514 for (
int i = num_digits - 1; i >= 0; --i ) {
515 if ( digits[i] != 0 ) {
522 if ( first_non_zero == -1 ) {
525 stream <<
"1e+" << (whole_words*digits_per_word);
532 if ( first_non_zero >= ((fraction_words*digits_per_word) + precision) ) {
534 int exponent = first_non_zero - (fraction_words * digits_per_word );
535 stream << static_cast<uint32_t>(digits[first_non_zero]) <<
".";
537 for (
int i = first_non_zero - 1; i >= first_non_zero - precision; --i ) {
541 if ( digits[i] == 0 ) zeros++;
543 for (
int j = 0; j < zeros; ++j ) {
546 stream << static_cast<uint32_t>(digits[i]);
550 std::string ret = stream.str();
551 if ( ret[ret.length()-1] ==
'.' ) {
552 ret = ret.substr(0,ret.length()-1);
553 stream.str(std::string(
""));
556 stream <<
"e+" << std::setfill(
'0') << std::setw(2) << exponent;
561 else if ( first_non_zero >= (fraction_words * digits_per_word)) {
563 for (
int i = first_non_zero; i >= (fraction_words * digits_per_word); --i ) {
565 stream << static_cast<uint32_t>(digits[i]);
570 for (
int i = (fraction_words * digits_per_word) - 1;
571 i >= first_non_zero - precision && (i >= 0);
576 if ( digits[i] == 0 ) zeros++;
578 for (
int j = 0; j < zeros; ++j ) {
581 stream << static_cast<uint32_t>(digits[i]);
585 std::string ret = stream.str();
586 if ( ret[ret.length()-1] ==
'.' ) {
587 ret = ret.substr(0,ret.length()-1);
588 stream.str(std::string(
""));
596 else if ( first_non_zero > (fraction_words * digits_per_word) - 5 ) {
598 for (
int i = (fraction_words * digits_per_word) - 1; i > first_non_zero; --i ) {
602 for (
int i = first_non_zero;
603 (i >= first_non_zero - precision) && (i >= 0);
608 if ( digits[i] == 0 ) zeros++;
610 for (
int j = 0; j < zeros; ++j ) {
613 stream << static_cast<uint32_t>(digits[i]);
621 int exponent = first_non_zero - (fraction_words * digits_per_word );
622 exponent = -exponent;
623 stream << static_cast<uint32_t>(digits[first_non_zero]) <<
".";
625 for (
int i = first_non_zero - 1;
626 (i >= first_non_zero - precision) && (i >= 0);
631 if ( digits[i] == 0 ) zeros++;
633 for (
int j = 0; j < zeros; ++j ) {
636 stream << static_cast<uint32_t>(digits[i]);
640 std::string ret = stream.str();
641 if ( ret[ret.length()-1] ==
'.' ) {
642 ret = ret.substr(0,ret.length()-1);
643 stream.str(std::string(
""));
646 stream <<
"e-" << std::setfill(
'0') << std::setw(2) << exponent;
660 if ( (negative ^ v.negative) == 0 ) {
663 uint64_t carry_over = 0;
664 for (
int i = 0; i < whole_words + fraction_words; i++ ) {
665 uint64_t value =
static_cast<uint64_t
>(data[i])
666 + static_cast<uint64_t>(v.data[i])
668 carry_over = value / storage_radix;
670 data[i] = value % storage_radix;
676 if (
operator>=(v) ) {
679 uint64_t carry_over = 1;
680 for (
int i = 0; i < whole_words + fraction_words; i++ ) {
681 uint64_t
negate =
static_cast<uint64_t
>(storage_radix - 1) - static_cast<uint64_t>(v.data[i]);
683 uint64_t value =
static_cast<uint64_t
>(data[i])
686 carry_over = value / storage_radix;
687 data[i] =
static_cast<uint32_t
>(value % storage_radix);
694 uint64_t carry_over = 1;
695 for (
int i = 0; i < whole_words + fraction_words; i++ ) {
696 uint64_t
negate =
static_cast<uint64_t
>(storage_radix - 1) - static_cast<uint64_t>(data[i]);
698 uint64_t value =
static_cast<uint64_t
>(v.data[i])
701 carry_over = value / storage_radix;
702 data[i] =
static_cast<uint32_t
>(value % storage_radix);
705 negative = v.negative;
737 uint64_t carry_over = 0;
738 for (
int i = 0; i < fraction_words; ++i ) {
739 uint64_t sum = carry_over;
740 for (
int j = 0; j <= i; ++j ) {
741 sum +=
static_cast<uint64_t
>(me.data[j]) * static_cast<uint64_t>(v.data[i-j]);
743 carry_over = sum / storage_radix_long;
747 for (
int i = fraction_words; i < whole_words + fraction_words; ++i ) {
748 uint64_t sum = carry_over;
749 for (
int j = 0; j <= i; ++j ) {
750 sum +=
static_cast<uint64_t
>(me.data[j]) * static_cast<uint64_t>(v.data[i-j]);
752 carry_over = sum / storage_radix_long;
753 data[i-fraction_words] =
static_cast<uint32_t
>(sum % storage_radix_long);
756 for (
int i = 0; i < fraction_words; ++i ) {
757 uint64_t sum = carry_over;
758 for (
int j = i+1; j < whole_words + fraction_words; ++j ) {
759 sum +=
static_cast<uint64_t
>(me.data[j])
760 * static_cast<uint64_t>(v.data[whole_words+fraction_words+i-j]);
762 carry_over = sum / storage_radix_long;
763 data[i+whole_words] =
static_cast<uint32_t
>(sum % storage_radix_long);
766 negative = negative ^ v.negative;
803 int digits_of_prec = std::numeric_limits<double>::digits10 / 2;
806 for (
int i = digits_of_prec; i <= (whole_words + fraction_words) * digits_per_word; i *= 2 ) {
824 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
825 if ( data[i] != v.data[i] )
return false;
836 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
837 if ( data[i] != v.data[i] )
return true;
848 for (
int i = whole_words +fraction_words - 1; i >= 0; --i ) {
849 if ( data[i] > v.data[i] )
return true;
850 if ( data[i] < v.data[i] )
return false;
862 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
863 if ( data[i] > v.data[i] )
return true;
864 if ( data[i] < v.data[i] )
return false;
875 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
876 if ( data[i] < v.data[i] )
return true;
877 if ( data[i] > v.data[i] )
return false;
889 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
890 if ( data[i] < v.data[i] )
return true;
891 if ( data[i] > v.data[i] )
return false;
898 template <
int whole_words,
int fraction_words>
899 decimal_fixedpoint<whole_words,fraction_words> operator+(decimal_fixedpoint<whole_words,fraction_words> lhs,
900 decimal_fixedpoint<whole_words,fraction_words> rhs) {
901 decimal_fixedpoint<whole_words,fraction_words> ret(lhs);
905 template <
int whole_words,
int fraction_words>
906 decimal_fixedpoint<whole_words,fraction_words> operator-(decimal_fixedpoint<whole_words,fraction_words> lhs,
907 decimal_fixedpoint<whole_words,fraction_words> rhs) {
908 decimal_fixedpoint<whole_words,fraction_words> ret(lhs);
912 template <
int whole_words,
int fraction_words>
913 decimal_fixedpoint<whole_words,fraction_words> operator*(decimal_fixedpoint<whole_words,fraction_words> lhs,
914 decimal_fixedpoint<whole_words,fraction_words> rhs) {
915 decimal_fixedpoint<whole_words,fraction_words> ret(lhs);
919 template <
int whole_words,
int fraction_words>
920 decimal_fixedpoint<whole_words,fraction_words> operator/(decimal_fixedpoint<whole_words,fraction_words> lhs,
921 decimal_fixedpoint<whole_words,fraction_words> rhs) {
922 decimal_fixedpoint<whole_words,fraction_words> ret(lhs);
926 template <
int whole_words,
int fraction_words,
typename T>
927 bool operator==(
const T& lhs,
const decimal_fixedpoint<whole_words,fraction_words>& rhs) {
928 return rhs == decimal_fixedpoint<whole_words,fraction_words>(lhs);
931 template <
int whole_words,
int fraction_words,
typename T>
932 bool operator!=(
const T& lhs,
const decimal_fixedpoint<whole_words,fraction_words>& rhs) {
933 return rhs != decimal_fixedpoint<whole_words,fraction_words>(lhs);
936 template <
int whole_words,
int fraction_words>
937 std::ostream& operator <<(std::ostream& os, const decimal_fixedpoint<whole_words,fraction_words>& rhs) {
938 os << rhs.toString(os.precision());
std::string toString(int32_t precision=6) const
Create a string representation of this decimal_fixedpoint.
Definition: decimal_fixedpoint.h:437
constexpr int getWholeWords() const
Get the value of whole_words template parameter.
Definition: decimal_fixedpoint.h:49
decimal_fixedpoint & operator=(uint64_t v)
Equal operator for 64-bit unsigned int.
Definition: decimal_fixedpoint.h:284
uint64_t toUnsignedLong() const
Return a uint64_t version of the decimal_fixedpoint.
Definition: decimal_fixedpoint.h:386
T convert_to(typename std::enable_if< std::is_signed< T >::value &&std::is_integral< T >::value >::type *=0) const
Templated conversion function for signed integral types.
Definition: decimal_fixedpoint.h:418
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(typename std::enable_if< std::is_floating_point< T >::value >::type *=0) const
Templated conversion function for floating point types.
Definition: decimal_fixedpoint.h:427
bool operator<(const decimal_fixedpoint &v) const
Checks to see if this number is less than another number.
Definition: decimal_fixedpoint.h:874
decimal_fixedpoint & inverse()
Inverts the number (1 divided by this number)
Definition: decimal_fixedpoint.h:787
decimal_fixedpoint & operator/=(const decimal_fixedpoint &v)
Divides another number from this one and sets it equal to the result.
Definition: decimal_fixedpoint.h:776
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 this number is greater than another number.
Definition: decimal_fixedpoint.h:847
decimal_fixedpoint & operator=(double v)
Equal operator for double.
Definition: decimal_fixedpoint.h:306
decimal_fixedpoint & operator=(const std::string &v)
Equal operator for string.
Definition: decimal_fixedpoint.h:314
decimal_fixedpoint & operator=(int64_t v)
Equal operator for 64-bit signed int.
Definition: decimal_fixedpoint.h:292
decimal_fixedpoint(const std::string &init)
Build a decimal_fixedpoint using a string initializer.
Definition: decimal_fixedpoint.h:215
decimal_fixedpoint(T init, typename std::enable_if< std::is_unsigned< T >::value >::type *=nullptr)
Build a decimal_fixedpoint using a 64-bit unsigned number.
Definition: decimal_fixedpoint.h:226
Class that implements a decimal fixed-point number.
Definition: decimal_fixedpoint.h:39
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
decimal_fixedpoint(const T init, typename std::enable_if< std::is_floating_point< T >::value >::type *=nullptr)
Build a decimal_fixedpoint using a double.
Definition: decimal_fixedpoint.h:254
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:888
T convert_to(typename std::enable_if< std::is_unsigned< T >::value >::type *=0) const
Templated conversion function for unsigned types.
Definition: decimal_fixedpoint.h:410
bool operator!=(const decimal_fixedpoint &v) const
Checks to see if two numbers are not equal.
Definition: decimal_fixedpoint.h:835
int64_t toLong() const
Return a int64_t version of the decimal_fixedpoint.
Definition: decimal_fixedpoint.h:350
constexpr int getFractionWords() const
Get the value of fraction_words template parameter.
Definition: decimal_fixedpoint.h:56
bool isZero() const
Return true if value is zero, otherwise return false.
Definition: decimal_fixedpoint.h:399
decimal_fixedpoint(T init, typename std::enable_if< std::is_signed< T >::value &&std::is_integral< T >::value >::type *=nullptr)
Build a decimal_fixedpoint using a 64-bit signed number.
Definition: decimal_fixedpoint.h:237
decimal_fixedpoint()
Default constructor.
Definition: decimal_fixedpoint.h:201
decimal_fixedpoint & operator=(const decimal_fixedpoint &v)
Equal operator for other decimal_fixedpoint objects.
Definition: decimal_fixedpoint.h:273
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:861
decimal_fixedpoint & operator+=(const decimal_fixedpoint &v)
Adds another number to this one and sets it equal to the result.
Definition: decimal_fixedpoint.h:658
void negate()
Negate the value (change the sign bit).
Definition: decimal_fixedpoint.h:323
bool operator==(const decimal_fixedpoint &v) const
Checks to see if two numbers are equal.
Definition: decimal_fixedpoint.h:823
double toDouble() const
Return a double precision version of the decimal_fixedpoint.
Definition: decimal_fixedpoint.h:331