14#ifndef SST_CORE_DECIMAL_FIXEDPOINT_H
15#define SST_CORE_DECIMAL_FIXEDPOINT_H
17#include "sst/core/from_string.h"
39template <
int whole_words,
int fraction_words>
44 static constexpr uint32_t storage_radix = 100000000;
45 static constexpr uint64_t storage_radix_long = 100000000l;
46 static constexpr int32_t digits_per_word = 8;
60 template <
int A,
int B>
61 friend class sst_dec_fixed;
72 uint32_t data[whole_words + fraction_words];
86 void from_string(
const std::string& init_str)
88 std::string init(init_str);
90 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
95 if ( init[0] ==
'-' ) {
97 init = init.substr(1, init.npos);
101 size_t exponent_pos = init.find_last_of(
"eE");
102 int32_t exponent = 0;
103 if ( exponent_pos != init.npos ) {
104 exponent =
static_cast<int32_t
>(SST::Core::from_string<double>(init.substr(exponent_pos + 1, init.npos)));
105 init = init.substr(0, exponent_pos);
108 int dp = init.length();
109 for (
size_t i = 0; i < init.length(); ++i ) {
110 if ( init[i] ==
'.' ) { dp = i; }
117 int start_of_digits = (fraction_words * digits_per_word) - (init.length() - dp) + exponent;
121 int start_pos_word = start_of_digits % digits_per_word;
123 for (
int i = 0; i < start_pos_word; i++ ) {
127 for (
int i = init.length() - 1; i >= 0; --i ) {
128 int digit = start_of_digits + (init.length() - 1 - i);
129 int word = (digit / digits_per_word);
131 data[word] += (SST::Core::from_string<uint32_t>(init.substr(i, 1)) * mult);
133 if ( mult == storage_radix ) mult = 1;
142 void from_uint64(uint64_t init)
146 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
159 for (
int i = fraction_words; i < whole_words + fraction_words; ++i ) {
160 data[i] = init % storage_radix_long;
161 init /= storage_radix_long;
170 void from_double(
double init)
174 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
179 for (
int i = 0; i < whole_words - 1; ++i ) {
180 factor *= storage_radix;
183 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
184 data[i] =
static_cast<uint32_t
>(init / factor);
185 init -= (data[i] * factor);
186 factor /= storage_radix;
199 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
231 T init,
typename std::enable_if<std::is_signed<T>::value && std::is_integral<T>::value>::type* =
nullptr)
248 decimal_fixedpoint(
const T init,
typename std::enable_if<std::is_floating_point<T>::value>::type* =
nullptr)
260 negative = init.negative;
261 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
262 data[i] = init.data[i];
271 negative = v.negative;
272 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
323 void negate() { negative = negative ^ 0x1; }
333 for (
int i = 0; i < fraction_words; ++i ) {
334 factor /= storage_radix;
337 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
338 ret += (
static_cast<double>(data[i]) * factor);
339 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) ) { round =
true; }
361 else if ( data[fraction_words - 1] == (storage_radix / 2) ) {
362 for (
int i = fraction_words - 2; i >= 0; --i ) {
363 if ( data[i] != 0 ) {
372 if ( ret % 2 == 1 ) round =
true;
376 if ( negative ) ret = -ret;
388 for (
int i = 0; i < whole_words; ++i ) {
389 ret += (
static_cast<int64_t
>(data[i]) * factor);
390 factor *= storage_radix;
400 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
401 if ( data[i] != 0 )
return false;
409 template <
typename T>
410 T
convert_to(
typename std::enable_if<std::is_unsigned<T>::value>::type* = 0)
const
418 template <
typename T>
419 T
convert_to(
typename std::enable_if<std::is_signed<T>::value && std::is_integral<T>::value>::type* = 0)
const
421 return static_cast<T
>(
toLong());
427 template <
typename T>
428 T
convert_to(
typename std::enable_if<std::is_floating_point<T>::value>::type* = 0)
const
442 std::stringstream stream;
443 if ( precision <= 0 || precision > ((whole_words + fraction_words) * digits_per_word) )
444 precision = (whole_words + fraction_words) * digits_per_word;
448 constexpr int num_digits = (whole_words + fraction_words) * digits_per_word;
450 unsigned char digits[num_digits];
451 for (
int i = 0; i < whole_words + fraction_words; ++i ) {
452 uint32_t value = data[i];
453 for (
int j = 0; j < digits_per_word; ++j ) {
454 digits[i * digits_per_word + j] = value % 10;
460 int first_non_zero = -1;
461 for (
int i = num_digits - 1; i >= 0; --i ) {
462 if ( digits[i] != 0 ) {
469 if ( first_non_zero == -1 )
return "0";
472 int round_position = first_non_zero - precision;
477 if ( round_position >= 0 ) {
478 if ( digits[round_position] > 5 )
480 else if ( digits[round_position] < 5 )
484 for (
int i = round_position - 1; i >= 0; --i ) {
485 if ( digits[i] != 0 ) {
493 if ( digits[round_position + 1] % 2 == 1 ) round =
true;
499 unsigned char carry = 1;
500 for (
int i = round_position + 1; i < num_digits; ++i ) {
502 carry = digits[i] / 10;
503 digits[i] = digits[i] % 10;
508 for (
int i = 0; i <= round_position; ++i ) {
514 if ( negative ) stream <<
'-';
518 for (
int i = num_digits - 1; i >= 0; --i ) {
519 if ( digits[i] != 0 ) {
526 if ( first_non_zero == -1 ) {
529 stream <<
"1e+" << (whole_words * digits_per_word);
536 if ( first_non_zero >= ((fraction_words * digits_per_word) + precision) ) {
538 int exponent = first_non_zero - (fraction_words * digits_per_word);
539 stream << static_cast<uint32_t>(digits[first_non_zero]) <<
".";
541 for (
int i = first_non_zero - 1; i >= first_non_zero - precision; --i ) {
545 if ( digits[i] == 0 )
548 for (
int j = 0; j < zeros; ++j ) {
551 stream << static_cast<uint32_t>(digits[i]);
555 std::string ret = stream.str();
556 if ( ret[ret.length() - 1] ==
'.' ) {
557 ret = ret.substr(0, ret.length() - 1);
558 stream.str(std::string(
""));
561 stream <<
"e+" << std::setfill(
'0') << std::setw(2) << exponent;
566 else if ( first_non_zero >= (fraction_words * digits_per_word) ) {
568 for (
int i = first_non_zero; i >= (fraction_words * digits_per_word); --i ) {
570 stream << static_cast<uint32_t>(digits[i]);
575 for (
int i = (fraction_words * digits_per_word) - 1; i >= first_non_zero - precision && (i >= 0); --i ) {
579 if ( digits[i] == 0 )
582 for (
int j = 0; j < zeros; ++j ) {
585 stream << static_cast<uint32_t>(digits[i]);
589 std::string ret = stream.str();
590 if ( ret[ret.length() - 1] ==
'.' ) {
591 ret = ret.substr(0, ret.length() - 1);
592 stream.str(std::string(
""));
600 else if ( first_non_zero > (fraction_words * digits_per_word) - 5 ) {
602 for (
int i = (fraction_words * digits_per_word) - 1; i > first_non_zero; --i ) {
606 for (
int i = first_non_zero; (i >= first_non_zero - precision) && (i >= 0); --i ) {
610 if ( digits[i] == 0 )
613 for (
int j = 0; j < zeros; ++j ) {
616 stream << static_cast<uint32_t>(digits[i]);
624 int exponent = first_non_zero - (fraction_words * digits_per_word);
625 exponent = -exponent;
626 stream << static_cast<uint32_t>(digits[first_non_zero]) <<
".";
628 for (
int i = first_non_zero - 1; (i >= first_non_zero - precision) && (i >= 0); --i ) {
632 if ( digits[i] == 0 )
635 for (
int j = 0; j < zeros; ++j ) {
638 stream << static_cast<uint32_t>(digits[i]);
642 std::string ret = stream.str();
643 if ( ret[ret.length() - 1] ==
'.' ) {
644 ret = ret.substr(0, ret.length() - 1);
645 stream.str(std::string(
""));
648 stream <<
"e-" << std::setfill(
'0') << std::setw(2) << exponent;
663 if ( (negative ^ v.negative) == 0 ) {
666 uint64_t carry_over = 0;
667 for (
int i = 0; i < whole_words + fraction_words; i++ ) {
668 uint64_t value =
static_cast<uint64_t
>(data[i]) +
static_cast<uint64_t
>(v.data[i]) + carry_over;
669 carry_over = value / storage_radix;
671 data[i] = value % storage_radix;
677 if (
operator>=(v) ) {
680 uint64_t carry_over = 1;
681 for (
int i = 0; i < whole_words + fraction_words; i++ ) {
682 uint64_t
negate =
static_cast<uint64_t
>(storage_radix - 1) -
static_cast<uint64_t
>(v.data[i]);
684 uint64_t value =
static_cast<uint64_t
>(data[i]) +
negate + carry_over;
685 carry_over = value / storage_radix;
686 data[i] =
static_cast<uint32_t
>(value % storage_radix);
693 uint64_t carry_over = 1;
694 for (
int i = 0; i < whole_words + fraction_words; i++ ) {
695 uint64_t
negate =
static_cast<uint64_t
>(storage_radix - 1) -
static_cast<uint64_t
>(data[i]);
697 uint64_t value =
static_cast<uint64_t
>(v.data[i]) +
negate + carry_over;
698 carry_over = value / storage_radix;
699 data[i] =
static_cast<uint32_t
>(value % storage_radix);
702 negative = v.negative;
734 uint64_t carry_over = 0;
735 for (
int i = 0; i < fraction_words; ++i ) {
736 uint64_t sum = carry_over;
737 for (
int j = 0; j <= i; ++j ) {
738 sum +=
static_cast<uint64_t
>(me.data[j]) *
static_cast<uint64_t
>(v.data[i - j]);
740 carry_over = sum / storage_radix_long;
744 for (
int i = fraction_words; i < whole_words + fraction_words; ++i ) {
745 uint64_t sum = carry_over;
746 for (
int j = 0; j <= i; ++j ) {
747 sum +=
static_cast<uint64_t
>(me.data[j]) *
static_cast<uint64_t
>(v.data[i - j]);
749 carry_over = sum / storage_radix_long;
750 data[i - fraction_words] =
static_cast<uint32_t
>(sum % storage_radix_long);
753 for (
int i = 0; i < fraction_words; ++i ) {
754 uint64_t sum = carry_over;
755 for (
int j = i + 1; j < whole_words + fraction_words; ++j ) {
756 sum +=
static_cast<uint64_t
>(me.data[j]) *
757 static_cast<uint64_t
>(v.data[whole_words + fraction_words + i - j]);
759 carry_over = sum / storage_radix_long;
760 data[i + whole_words] =
static_cast<uint32_t
>(sum % storage_radix_long);
763 negative = negative ^ v.negative;
802 int digits_of_prec = std::numeric_limits<double>::digits10 / 2;
805 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;
837 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
838 if ( data[i] != v.data[i] )
return true;
850 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
851 if ( data[i] > v.data[i] )
return true;
852 if ( data[i] < v.data[i] )
return false;
865 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
866 if ( data[i] > v.data[i] )
return true;
867 if ( data[i] < v.data[i] )
return false;
879 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
880 if ( data[i] < v.data[i] )
return true;
881 if ( data[i] > v.data[i] )
return false;
894 for (
int i = whole_words + fraction_words - 1; i >= 0; --i ) {
895 if ( data[i] < v.data[i] )
return true;
896 if ( data[i] > v.data[i] )
return false;
902template <
int whole_words,
int fraction_words>
903decimal_fixedpoint<whole_words, fraction_words>
904operator+(decimal_fixedpoint<whole_words, fraction_words> lhs, decimal_fixedpoint<whole_words, fraction_words> rhs)
906 decimal_fixedpoint<whole_words, fraction_words> ret(lhs);
910template <
int whole_words,
int fraction_words>
911decimal_fixedpoint<whole_words, fraction_words>
912operator-(decimal_fixedpoint<whole_words, fraction_words> lhs, decimal_fixedpoint<whole_words, fraction_words> rhs)
914 decimal_fixedpoint<whole_words, fraction_words> ret(lhs);
918template <
int whole_words,
int fraction_words>
919decimal_fixedpoint<whole_words, fraction_words>
920operator*(decimal_fixedpoint<whole_words, fraction_words> lhs, decimal_fixedpoint<whole_words, fraction_words> rhs)
922 decimal_fixedpoint<whole_words, fraction_words> ret(lhs);
926template <
int whole_words,
int fraction_words>
927decimal_fixedpoint<whole_words, fraction_words>
928operator/(decimal_fixedpoint<whole_words, fraction_words> lhs, decimal_fixedpoint<whole_words, fraction_words> rhs)
930 decimal_fixedpoint<whole_words, fraction_words> ret(lhs);
934template <
int whole_words,
int fraction_words,
typename T>
936operator==(
const T& lhs,
const decimal_fixedpoint<whole_words, fraction_words>& rhs)
938 return rhs == decimal_fixedpoint<whole_words, fraction_words>(lhs);
941template <
int whole_words,
int fraction_words,
typename T>
943operator!=(
const T& lhs,
const decimal_fixedpoint<whole_words, fraction_words>& rhs)
945 return rhs != decimal_fixedpoint<whole_words, fraction_words>(lhs);
948template <
int whole_words,
int fraction_words>
950operator<<(std::ostream& os,
const decimal_fixedpoint<whole_words, fraction_words>& rhs)
952 os << rhs.toString(os.precision());
Class that implements a decimal fixed-point number.
Definition: decimal_fixedpoint.h:41
decimal_fixedpoint(const std::string &init)
Build a decimal_fixedpoint using a string initializer.
Definition: decimal_fixedpoint.h:211
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
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:219
std::string toString(int32_t precision=6) const
Create a string representation of this decimal_fixedpoint.
Definition: decimal_fixedpoint.h:439
decimal_fixedpoint & inverse()
Inverts the number (1 divided by this number)
Definition: decimal_fixedpoint.h:785
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:248
bool operator>(const decimal_fixedpoint &v) const
Checks to see if this number is greater than another number.
Definition: decimal_fixedpoint.h:848
decimal_fixedpoint & operator=(const std::string &v)
Equal operator for string.
Definition: decimal_fixedpoint.h:314
decimal_fixedpoint & operator=(const decimal_fixedpoint &v)
Equal operator for other decimal_fixedpoint objects.
Definition: decimal_fixedpoint.h:269
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:230
decimal_fixedpoint(const decimal_fixedpoint &init)
Build a decimal_fixedpoint using another decimal_fixedpoint.
Definition: decimal_fixedpoint.h:258
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:419
bool operator!=(const decimal_fixedpoint &v) const
Checks to see if two numbers are not equal.
Definition: decimal_fixedpoint.h:835
constexpr int getWholeWords() const
Get the value of whole_words template parameter.
Definition: decimal_fixedpoint.h:51
int64_t toLong() const
Return a int64_t version of the decimal_fixedpoint.
Definition: decimal_fixedpoint.h:349
decimal_fixedpoint & operator=(int64_t v)
Equal operator for 64-bit signed int.
Definition: decimal_fixedpoint.h:290
double toDouble() const
Return a double precision version of the decimal_fixedpoint.
Definition: decimal_fixedpoint.h:329
decimal_fixedpoint & operator+=(const decimal_fixedpoint &v)
Adds another number to this one and sets it equal to the result.
Definition: decimal_fixedpoint.h:660
decimal_fixedpoint & operator=(double v)
Equal operator for double.
Definition: decimal_fixedpoint.h:305
bool isZero() const
Return true if value is zero, otherwise return false.
Definition: decimal_fixedpoint.h:398
decimal_fixedpoint()
Default constructor.
Definition: decimal_fixedpoint.h:196
uint64_t toUnsignedLong() const
Return a uint64_t version of the decimal_fixedpoint.
Definition: decimal_fixedpoint.h:384
decimal_fixedpoint & operator/=(const decimal_fixedpoint &v)
Divides another number from this one and sets it equal to the result.
Definition: decimal_fixedpoint.h:773
bool operator<(const decimal_fixedpoint &v) const
Checks to see if this number is less than another number.
Definition: decimal_fixedpoint.h:877
bool operator==(const decimal_fixedpoint &v) const
Checks to see if two numbers are equal.
Definition: decimal_fixedpoint.h:822
void negate()
Negate the value (change the sign bit).
Definition: decimal_fixedpoint.h:323
decimal_fixedpoint & operator=(uint64_t v)
Equal operator for 64-bit unsigned int.
Definition: decimal_fixedpoint.h:281
decimal_fixedpoint & operator-=(const decimal_fixedpoint &v)
Subtracts another number from this one and sets it equal to the result.
Definition: decimal_fixedpoint.h:713
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:428
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:892
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:863
constexpr int getFractionWords() const
Get the value of fraction_words template parameter.
Definition: decimal_fixedpoint.h:56
decimal_fixedpoint & operator*=(const decimal_fixedpoint &v)
Multiplies another number to this one and sets it equal to the result.
Definition: decimal_fixedpoint.h:726