SST  10.0.0
StructuralSimulationToolkit
decimal_fixedpoint.h
1 // -*- c++ -*-
2 
3 // Copyright 2009-2020 NTESS. Under the terms
4 // of Contract DE-NA0003525 with NTESS, the U.S.
5 // Government retains certain rights in this software.
6 //
7 // Copyright (c) 2009-2020, NTESS
8 // All rights reserved.
9 //
10 // This file is part of the SST software package. For license
11 // information, see the LICENSE file in the top level directory of the
12 // distribution.
13 
14 #ifndef SST_CORE_DECIMAL_FIXEDPOINT_H
15 #define SST_CORE_DECIMAL_FIXEDPOINT_H
16 
17 #include <iomanip>
18 #include <sstream>
19 #include <type_traits>
20 
21 #include "sst/core/from_string.h"
22 
23 namespace SST {
24 /**
25  Class that implements a decimal fixed-point number.
26 
27  Fixed point class that stores digits in radix-10. Size is
28  specified in words, and each word represents 8 digits.
29 
30  @tparam whole_words Number of words used to represent the digits to
31  the left of the decimal point. Each word represents 8 decimal
32  digits.
33 
34  @tparam fraction_words Number of words used to represent the digits
35  to the right of the decimal point. Each word represents 8 decimal
36  digits.
37 */
38 template <int whole_words, int fraction_words>
40 
41 public:
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;
45 
46  /**
47  Get the value of whole_words template parameter.
48  */
49  constexpr int getWholeWords() const {
50  return whole_words;
51  }
52 
53  /**
54  Get the value of fraction_words template parameter.
55  */
56  constexpr int getFractionWords() const {
57  return fraction_words;
58  }
59 
60 private:
61 
62  // I should be a friend of all versions of this class
63  template <int A, int B>
64  friend class sst_dec_fixed;
65 
66  /**
67  Data representing the digits of the number.
68 
69  Represents 8 decimal digits per 32-bits. Each digit will not
70  be represented independently, but rather all 8 digits will be
71  represented as a number of parts out of 100,000,000.
72  Essentially, we're storing as radix 100,000,000. Index 0 holds
73  the least significant digits
74  */
75  uint32_t data[whole_words + fraction_words];
76 
77  /**
78  Represents if the number is negative or not.
79  */
80  bool negative;
81 
82 
83  /**
84  initialize a decimal_fixedpoint using a string initializer
85 
86  @param init Initialization string. The format is similar to
87  the c++ double precision strings. For example 1.234, -1.234,
88  0.234, 1.234e14, 1.234e14, etc.
89  */
90  void from_string(const std::string& init_str) {
91  std::string init(init_str);
92  negative = false;
93  for ( int i = 0; i < whole_words + fraction_words; ++i ) {
94  data[i] = 0;
95  }
96 
97  // Look for a negative sign
98  if ( init[0] == '-' ) {
99  negative = true;
100  init = init.substr(1,init.npos);
101  }
102 
103  // See if we have an exponent
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);
109  }
110 
111  int dp = init.length();
112  for ( size_t i = 0; i < init.length(); ++i ) {
113  if ( init[i] == '.' ) {
114  dp = i;
115  }
116  }
117 
118  // get rid of the decimal point
119  init.erase(dp,1);
120 
121  // pos of decimal pt digits after dec pt
122  int start_of_digits = (fraction_words * digits_per_word) - (init.length() - dp) + exponent;
123  // Convert digits to numbers
124 
125  // Compute the first mult
126  int start_pos_word = start_of_digits % digits_per_word;
127  uint32_t mult = 1;
128  for ( int i = 0; i < start_pos_word; i++ ) {
129  mult *= 10;
130  }
131 
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 );
135 
136  data[word] += (SST::Core::from_string<uint32_t>(init.substr(i,1)) * mult);
137  mult *= 10;
138  if (mult == storage_radix) mult = 1;
139  }
140 
141  }
142 
143  /**
144  Initialize a decimal_fixedpoint using a 64-bit unsigned number.
145 
146  @param init Initialization value.
147  */
148  void from_uint64(uint64_t init) {
149  negative = false;
150 
151  for ( int i = 0; i < whole_words + fraction_words; ++i ) {
152  data[i] = 0;
153  }
154 
155  // A 64-bit integer can use at most two of the words
156  // uint64_t factor = ( storage_radix_long * storage_radix_long );
157  // for ( int i = 2; i > 0; --i ) {
158  // data[i+fraction_words] = init / factor;
159  // init -= data[i+fraction_words] * factor;
160  // factor /= storage_radix_long;
161  // }
162  // data[fraction_words] = init;
163 
164  for ( int i = fraction_words; i < whole_words + fraction_words; ++i ) {
165  data[i] = init % storage_radix_long;
166  init /= storage_radix_long;
167  }
168  }
169 
170  /**
171  Initialize a decimal_fixedpoint using a double.
172 
173  @param init Initialization value.
174  */
175  void from_double(double init) {
176  negative = false;
177 
178  for ( int i = 0; i < whole_words + fraction_words; ++i ) {
179  data[i] = 0;
180  }
181  double factor = 1;
182 
183  for ( int i = 0; i < whole_words - 1; ++i ) {
184  factor *= storage_radix;
185  }
186 
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;
191  }
192  }
193 
194 public:
195 
196  /**
197  Default constructor.
198 
199  Builds a decimal_fixedpoint with the value 0;
200  */
202  negative = false;
203  for ( int i = 0; i < whole_words + fraction_words; ++i ) {
204  data[i] = 0;
205  }
206  }
207 
208  /**
209  Build a decimal_fixedpoint using a string initializer.
210 
211  @param init Initialization string. The format is similar to
212  the c++ double precision strings. For example 1.234, -1.234,
213  0.234, 1.234e14, 1.234e14, etc.
214  */
215  decimal_fixedpoint(const std::string& init) {
216  from_string(init);
217  }
218 
219 
220  /**
221  Build a decimal_fixedpoint using a 64-bit unsigned number.
222 
223  @param init Initialization value.
224  */
225  template <class T>
226  decimal_fixedpoint(T init, typename std::enable_if<std::is_unsigned<T>::value >::type* = nullptr) {
227  from_uint64(init);
228  }
229 
230 
231  /**
232  Build a decimal_fixedpoint using a 64-bit signed number.
233 
234  @param init Initialization value.
235  */
236  template <class T>
237  decimal_fixedpoint(T init, typename std::enable_if<std::is_signed<T>::value &&
238  std::is_integral<T>::value >::type* = nullptr) {
239  if ( init < 0 ) {
240  from_uint64(-init);
241  negative = true;
242  }
243  else {
244  from_uint64(init);
245  }
246  }
247 
248  /**
249  Build a decimal_fixedpoint using a double.
250 
251  @param init Initialization value.
252  */
253  template <class T>
254  decimal_fixedpoint(const T init, typename std::enable_if<std::is_floating_point<T>::value >::type* = nullptr) {
255  from_double(init);
256  }
257 
258  /**
259  Build a decimal_fixedpoint using another decimal_fixedpoint.
260 
261  @param init Initialization value.
262  */
264  negative = init.negative;
265  for (int i = 0; i < whole_words + fraction_words; ++i ) {
266  data[i] = init.data[i];
267  }
268  }
269 
270  /**
271  Equal operator for other decimal_fixedpoint objects.
272  */
274  negative = v.negative;
275  for (int i = 0; i < whole_words + fraction_words; ++i ) {
276  data[i] = v.data[i];
277  }
278  return *this;
279  }
280 
281  /**
282  Equal operator for 64-bit unsigned int.
283  */
285  from_uint64(v);
286  return *this;
287  }
288 
289  /**
290  Equal operator for 64-bit signed int.
291  */
293  if ( v < 0 ) {
294  from_uint64(-v);
295  negative = true;
296  }
297  else {
298  from_uint64(v);
299  }
300  return *this;
301  }
302 
303  /**
304  Equal operator for double.
305  */
307  from_double(v);
308  return *this;
309  }
310 
311  /**
312  Equal operator for string.
313  */
314  decimal_fixedpoint& operator=(const std::string& v) {
315  from_string(v);
316  return *this;
317  }
318 
319 
320  /**
321  Negate the value (change the sign bit).
322  */
323  void negate() {
324  negative = negative ^ 0x1;
325  }
326 
327  /**
328  Return a double precision version of the decimal_fixedpoint.
329  There is possible precision loss in this conversion.
330  */
331  double toDouble() const {
332  double ret = 0;
333  double factor = 1;
334  for ( int i = 0; i < fraction_words; ++i ) {
335  factor /= storage_radix;
336  }
337 
338  for ( int i = 0; i <whole_words + fraction_words; ++i ) {
339  ret += ( static_cast<double>(data[i]) * factor );
340  factor *= storage_radix;
341  }
342 
343  return ret;
344  }
345 
346  /**
347  Return a int64_t version of the decimal_fixedpoint. There is
348  possible precision loss in this conversion.
349  */
350  int64_t toLong() const {
351  int64_t ret = 0;
352  int64_t factor = 1;
353  for ( int i = 0; i < whole_words; ++i ) {
354  ret += ( static_cast<int64_t>(data[fraction_words + i]) * factor );
355  factor *= storage_radix;
356  }
357 
358  // Check to see if we need to round
359  bool round = false;
360  if ( data[fraction_words - 1] > ( storage_radix / 2 ) ) {
361  round = true;
362  }
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 ) {
366  round = true;
367  break;
368  }
369  }
370 
371  if ( !round ) {
372  // There were no extra digits, so we need to do a
373  // round to nearest even.
374  if ( ret % 2 == 1 ) round = true;
375  }
376  }
377  if ( round ) ++ret;
378  if ( negative ) ret = -ret;
379  return ret;
380  }
381 
382  /**
383  Return a uint64_t version of the decimal_fixedpoint. There is
384  possible precision loss in this conversion.
385  */
386  uint64_t toUnsignedLong() const {
387  uint64_t ret = 0;
388  uint64_t factor = 1;
389  for ( int i = 0; i < whole_words; ++i ) {
390  ret += ( static_cast<int64_t>(data[i]) * factor );
391  factor *= storage_radix;
392  }
393  return ret;
394  }
395 
396  /**
397  Templated conversion function for unsigned types.
398  */
399  template<typename T>
400  T convert_to(typename std::enable_if<std::is_unsigned<T>::value>::type* = 0) const {
401  return static_cast<T>(toUnsignedLong());
402  }
403 
404  /**
405  Templated conversion function for signed integral types.
406  */
407  template<typename T>
408  T convert_to(typename std::enable_if<std::is_signed<T>::value &&
409  std::is_integral<T>::value >::type* = 0) const {
410  return static_cast<T>(toLong());
411  }
412 
413  /**
414  Templated conversion function for floating point types.
415  */
416  template<typename T>
417  T convert_to(typename std::enable_if<std::is_floating_point<T>::value >::type* = 0) const {
418  return static_cast<T>(toDouble());
419  }
420 
421  /**
422  Create a string representation of this decimal_fixedpoint.
423 
424  @param precision Precision to use when printing number
425 
426  */
427  std::string toString(int32_t precision = 6) const {
428 
429  std::stringstream stream;
430  if ( precision <= 0 || precision > ((whole_words + fraction_words) * digits_per_word ) )
431  precision = (whole_words + fraction_words) * digits_per_word;
432 
433  // First create a digit by digit representation so we can
434  // reason about what to print based on the precision.
435  constexpr int num_digits = (whole_words + fraction_words) * digits_per_word;
436 
437  unsigned char digits[num_digits];
438  for ( int i = 0; i < whole_words + fraction_words; ++i ) {
439  uint32_t value = data[i];
440  for ( int j = 0; j < digits_per_word; ++j ) {
441  digits[i*digits_per_word+j] = value % 10;
442  value /= 10;
443  }
444  }
445 
446  // Find the first non-zero
447  int first_non_zero = -1;
448  for ( int i = num_digits - 1; i >= 0; --i ) {
449  if ( digits[i] != 0 ) {
450  first_non_zero = i;
451  break;
452  }
453  }
454 
455  // If no non-zeros, return 0
456  if ( first_non_zero == -1 ) return "0";
457 
458  // Now, we will round to the precision asked for
459  int round_position = first_non_zero - precision;
460  bool round = false;
461 
462  // If round_position < 0 then we have already gotten all the
463  // digits that exist, so no need to round
464  if ( round_position >= 0 ) {
465  if ( digits[round_position] > 5 ) round = true;
466  else if ( digits[round_position] < 5 ) round = false;
467  else { // Round if the rest aren't zeros
468 
469  for ( int i = round_position - 1; i >= 0; --i ) {
470  if ( digits[i] != 0 ) {
471  round = true;
472  break;
473  }
474  }
475  if ( !round ) {
476  // There were no extra zeros, so we need to do round
477  // to nearest even.
478  if ( digits[round_position+1] % 2 == 1 ) round = true;
479  }
480  }
481 
482  if ( round ) {
483  // Do the round
484  unsigned char carry = 1;
485  for ( int i = round_position + 1; i < num_digits; ++i ) {
486  digits[i] += carry;
487  carry = digits[i] / 10;
488  digits[i] = digits[i] % 10;
489  }
490  }
491 
492  // Zero out all the bits beyond the precision
493  for ( int i = 0; i <= round_position; ++i ) {
494  digits[i] = 0;
495  }
496  }
497 
498  // print possible negative sign
499  if ( negative ) stream << '-';
500 
501 
502  // Find the first non-zero
503  first_non_zero = -1;
504  for ( int i = num_digits - 1; i >= 0; --i ) {
505  if ( digits[i] != 0 ) {
506  first_non_zero = i;
507  break;
508  }
509  }
510 
511  // Check for overflow in the round
512  if ( first_non_zero == -1 ) {
513  // This means we rounded to a number bigger than we can
514  // support
515  stream << "1e+" << (whole_words*digits_per_word);
516  return stream.str();
517  }
518 
519  // There are several cases to cover:
520 
521  // Need to switch to exponent notation for numbers > 1
522  if ( first_non_zero >= ((fraction_words*digits_per_word) + precision) ) {
523  // Need to use exponent notation
524  int exponent = first_non_zero - (fraction_words * digits_per_word );
525  stream << static_cast<uint32_t>(digits[first_non_zero]) << ".";
526  int zeros = 0;
527  for ( int i = first_non_zero - 1; i >= first_non_zero - precision; --i ) {
528  // Avoid printing trailing zeros. Keep track of runs
529  // of zeros and only print them if we hit another
530  // non-xero
531  if ( digits[i] == 0 ) zeros++;
532  else {
533  for ( int j = 0; j < zeros; ++j ) {
534  stream << "0";
535  }
536  stream << static_cast<uint32_t>(digits[i]);
537  zeros = 0;
538  }
539  }
540  std::string ret = stream.str();
541  if ( ret[ret.length()-1] == '.' ) {
542  ret = ret.substr(0,ret.length()-1);
543  stream.str(std::string(""));
544  stream << ret;
545  }
546  stream << "e+" << std::setfill('0') << std::setw(2) << exponent;
547  // return stream.str();
548  }
549 
550  // Decimal point is within the string of digits to print
551  else if ( first_non_zero >= (fraction_words * digits_per_word)) {
552  int zeros = 0;
553  for ( int i = first_non_zero; i >= (fraction_words * digits_per_word); --i ) {
554  // Digits before the decimal point
555  stream << static_cast<uint32_t>(digits[i]);
556  }
557 
558  stream << ".";
559 
560  for ( int i = (fraction_words * digits_per_word) - 1;
561  i >= first_non_zero - precision && (i >= 0);
562  --i ) {
563  // Avoid printing trailing zeros. Keep track of runs
564  // of zeros and only print them if we hit another
565  // non-xero
566  if ( digits[i] == 0 ) zeros++;
567  else {
568  for ( int j = 0; j < zeros; ++j ) {
569  stream << "0";
570  }
571  stream << static_cast<uint32_t>(digits[i]);
572  zeros = 0;
573  }
574  }
575  std::string ret = stream.str();
576  if ( ret[ret.length()-1] == '.' ) {
577  ret = ret.substr(0,ret.length()-1);
578  stream.str(std::string(""));
579  stream << ret;
580  }
581  }
582 
583  // No whole digits, but not switching to exponent notation
584  // yet. We are willing to print three leading zeros before
585  // switching to exponent notation
586  else if ( first_non_zero > (fraction_words * digits_per_word) - 5 ) {
587  stream << "0.";
588  for ( int i = (fraction_words * digits_per_word) - 1; i > first_non_zero; --i ) {
589  stream << "0";
590  }
591  int zeros = 0;
592  for ( int i = first_non_zero;
593  (i >= first_non_zero - precision) && (i >= 0);
594  --i ) {
595  // Avoid printing trailing zeros. Keep track of runs
596  // of zeros and only print them if we hit another
597  // non-xero
598  if ( digits[i] == 0 ) zeros++;
599  else {
600  for ( int j = 0; j < zeros; ++j ) {
601  stream << "0";
602  }
603  stream << static_cast<uint32_t>(digits[i]);
604  zeros = 0;
605  }
606  }
607  }
608  // Switch to exponent notation
609  else {
610  // Need to use exponent notation
611  int exponent = first_non_zero - (fraction_words * digits_per_word );
612  exponent = -exponent;
613  stream << static_cast<uint32_t>(digits[first_non_zero]) << ".";
614  int zeros = 0;
615  for ( int i = first_non_zero - 1;
616  (i >= first_non_zero - precision) && (i >= 0);
617  --i ) {
618  // Avoid printing trailing zeros. Keep track of runs
619  // of zeros and only print them if we hit another
620  // non-xero
621  if ( digits[i] == 0 ) zeros++;
622  else {
623  for ( int j = 0; j < zeros; ++j ) {
624  stream << "0";
625  }
626  stream << static_cast<uint32_t>(digits[i]);
627  zeros = 0;
628  }
629  }
630  std::string ret = stream.str();
631  if ( ret[ret.length()-1] == '.' ) {
632  ret = ret.substr(0,ret.length()-1);
633  stream.str(std::string(""));
634  stream << ret;
635  }
636  stream << "e-" << std::setfill('0') << std::setw(2) << exponent;
637  }
638 
639  return stream.str();
640  }
641 
642  /**
643  Adds another number to this one and sets it equal to the
644  result.
645 
646  @param v Number to add to this one
647  */
649  // Depending on the signs, this may be a subtract
650  if ( (negative ^ v.negative) == 0 ) {
651  // Signs match, just do an add
652  // Calculate the result for each digit.
653  uint64_t carry_over = 0;
654  for ( int i = 0; i < whole_words + fraction_words; i++ ) {
655  uint64_t value = static_cast<uint64_t>(data[i])
656  + static_cast<uint64_t>(v.data[i])
657  + carry_over;
658  carry_over = value / storage_radix;
659  // data[i] = static_cast<uint32_t>(value % storage_radix);
660  data[i] = value % storage_radix;
661  }
662  return *this;
663  }
664 
665  // Signs don't match, so we need to sort
666  if ( operator>=(v) ) {
667  // Calculate the result for each digit. Need to negate the
668  // second operand and pass a 1 in as carry-in (carry-over).
669  uint64_t carry_over = 1;
670  for ( int i = 0; i < whole_words + fraction_words; i++ ) {
671  uint64_t negate = static_cast<uint64_t>(storage_radix - 1) - static_cast<uint64_t>(v.data[i]);
672 
673  uint64_t value = static_cast<uint64_t>(data[i])
674  + negate
675  + carry_over;
676  carry_over = value / storage_radix;
677  data[i] = static_cast<uint32_t>(value % storage_radix);
678  }
679  return *this;
680  }
681  else {
682  // Calculate the result for each digit. Need to negate the
683  // second operand and pass a 1 in as carry-in (carry-over).
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>(data[i]);
687 
688  uint64_t value = static_cast<uint64_t>(v.data[i])
689  + negate
690  + carry_over;
691  carry_over = value / storage_radix;
692  data[i] = static_cast<uint32_t>(value % storage_radix);
693  }
694  // Since the other one is bigger, I take his sign
695  negative = v.negative;
696  return *this;
697  }
698  }
699 
700 
701  /**
702  Subtracts another number from this one and sets it equal to the
703  result.
704 
705  @param v Number to subtract from this one
706  */
708  decimal_fixedpoint ret(v);
709  ret.negate();
710  return operator+=(ret);
711  }
712 
713 
714  /**
715  Multiplies another number to this one and sets it equal to the
716  result.
717 
718  @param v Number to multiply to this one
719  */
721  // Need to do the multiply accumulate for each digit.
723 
724  // The first "fraction_words" digits only matter as far as
725  // their carries go. They get dropped in the final output
726  // because they are less than the least significant digit.
727  uint64_t carry_over = 0;
728  for ( int i = 0; i < fraction_words; ++i ) {
729  uint64_t sum = carry_over;
730  for ( int j = 0; j <= i; ++j ) {
731  sum += static_cast<uint64_t>(me.data[j]) * static_cast<uint64_t>(v.data[i-j]);
732  }
733  carry_over = sum / storage_radix_long;
734  }
735 
736  // Calculate the digits that we'll keep
737  for ( int i = fraction_words; i < whole_words + fraction_words; ++i ) {
738  uint64_t sum = carry_over;
739  for ( int j = 0; j <= i; ++j ) {
740  sum += static_cast<uint64_t>(me.data[j]) * static_cast<uint64_t>(v.data[i-j]);
741  }
742  carry_over = sum / storage_radix_long;
743  data[i-fraction_words] = static_cast<uint32_t>(sum % storage_radix_long);
744  }
745 
746  for ( int i = 0; i < fraction_words; ++i ) {
747  uint64_t sum = carry_over;
748  for ( int j = i+1; j < whole_words + fraction_words; ++j ) {
749  sum += static_cast<uint64_t>(me.data[j])
750  * static_cast<uint64_t>(v.data[whole_words+fraction_words+i-j]);
751  }
752  carry_over = sum / storage_radix_long;
753  data[i+whole_words] = static_cast<uint32_t>(sum % storage_radix_long);
754  }
755  return *this;
756  }
757 
758  /**
759  Divides another number from this one and sets it equal to the
760  result.
761 
762  @param v Number to divide from this one
763  */
765  decimal_fixedpoint inv(v);
766  inv.inverse();
767  operator*=(inv);
768  return *this;
769  }
770 
771  /**
772  Inverts the number (1 divided by this number)
773  */
774 
776  // We will use the Newton-Raphson method to compute the
777  // inverse
778 
779  // First, get an estimate of the inverse by converting to a
780  // double and inverting
781  decimal_fixedpoint me(*this);
783  // decimal_fixedpoint<whole_words,fraction_words> inv("400");
784 
786 
787  // Since we converted to double to get an estimate of the
788  // inverse, we have approximated a double's worth of precision
789  // in our answer. We'll divide that by 2 for now, just to be
790  // save.
791  int digits_of_prec = std::numeric_limits<double>::digits10 / 2;
792 
793  // Number of digits of precision doubles with each iteration
794  for ( int i = digits_of_prec; i <= (whole_words + fraction_words) * digits_per_word; i *= 2 ) {
795  decimal_fixedpoint temp(inv);
796  temp *= me;
797  temp -= two;
798  temp.negate();
799  inv *= temp;
800  }
801 
802  *this = inv;
803  return *this;
804  }
805 
806  /**
807  Checks to see if two numbers are equal
808 
809  @param v Number to check equality against
810  */
811  bool operator== (const decimal_fixedpoint& v) const {
812  for ( int i = whole_words + fraction_words - 1; i >= 0; --i ) {
813  if ( data[i] != v.data[i] ) return false;
814  }
815  return true;
816  }
817 
818  /**
819  Checks to see if two numbers are not equal
820 
821  @param v Number to check equality against
822  */
823  bool operator!= (const decimal_fixedpoint& v) const {
824  for ( int i = whole_words + fraction_words - 1; i >= 0; --i ) {
825  if ( data[i] != v.data[i] ) return true;
826  }
827  return false;
828  }
829 
830  /**
831  Checks to see if this number is greater than another number
832 
833  @param v Number to compare to
834  */
835  bool operator> (const decimal_fixedpoint& v) const {
836  for ( int i = whole_words +fraction_words - 1; i >= 0; --i ) {
837  if ( data[i] > v.data[i] ) return true;
838  if ( data[i] < v.data[i] ) return false;
839  }
840  return false;
841  }
842 
843  /**
844  Checks to see if this number is greater than or equal to
845  another number
846 
847  @param v Number to compare to
848  */
849  bool operator>= (const decimal_fixedpoint& v) const {
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;
853  }
854  return true;
855  }
856 
857  /**
858  Checks to see if this number is less than another number
859 
860  @param v Number to compare to
861  */
862  bool operator< (const decimal_fixedpoint& v) const {
863  for ( int i = whole_words + fraction_words - 1; i >= 0; --i ) {
864  if ( data[i] < v.data[i] ) return true;
865  if ( data[i] > v.data[i] ) return false;
866  }
867  return false;
868  }
869 
870  /**
871  Checks to see if this number is less than or equal to another
872  number
873 
874  @param v Number to compare to
875  */
876  bool operator<= (const decimal_fixedpoint& v) const {
877  for ( int i = whole_words + fraction_words - 1; i >= 0; --i ) {
878  if ( data[i] < v.data[i] ) return true;
879  if ( data[i] > v.data[i] ) return false;
880  }
881  return true;
882  }
883 
884 };
885 
886 template <int whole_words, int fraction_words>
887 decimal_fixedpoint<whole_words,fraction_words> operator+(decimal_fixedpoint<whole_words,fraction_words> lhs,
888  decimal_fixedpoint<whole_words,fraction_words> rhs) {
889  decimal_fixedpoint<whole_words,fraction_words> ret(lhs);
890  return ret += rhs;
891 }
892 
893 template <int whole_words, int fraction_words>
894 decimal_fixedpoint<whole_words,fraction_words> operator-(decimal_fixedpoint<whole_words,fraction_words> lhs,
895  decimal_fixedpoint<whole_words,fraction_words> rhs) {
896  decimal_fixedpoint<whole_words,fraction_words> ret(lhs);
897  return ret -= rhs;
898 }
899 
900 template <int whole_words, int fraction_words>
901 decimal_fixedpoint<whole_words,fraction_words> operator*(decimal_fixedpoint<whole_words,fraction_words> lhs,
902  decimal_fixedpoint<whole_words,fraction_words> rhs) {
903  decimal_fixedpoint<whole_words,fraction_words> ret(lhs);
904  return ret *= rhs;
905 }
906 
907 template <int whole_words, int fraction_words>
908 decimal_fixedpoint<whole_words,fraction_words> operator/(decimal_fixedpoint<whole_words,fraction_words> lhs,
909  decimal_fixedpoint<whole_words,fraction_words> rhs) {
910  decimal_fixedpoint<whole_words,fraction_words> ret(lhs);
911  return ret /= rhs;
912 }
913 
914 template <int whole_words, int fraction_words, typename T>
915 bool operator==(const T& lhs, const decimal_fixedpoint<whole_words,fraction_words>& rhs) {
916  return rhs == decimal_fixedpoint<whole_words,fraction_words>(lhs);
917 }
918 
919 template <int whole_words, int fraction_words, typename T>
920 bool operator!=(const T& lhs, const decimal_fixedpoint<whole_words,fraction_words>& rhs) {
921  return rhs != decimal_fixedpoint<whole_words,fraction_words>(lhs);
922 }
923 
924 template <int whole_words, int fraction_words>
925 std::ostream& operator <<(std::ostream& os, const decimal_fixedpoint<whole_words,fraction_words>& rhs) {
926  os << rhs.toString(os.precision());
927  return os;
928 }
929 
930 } // namespace SST
931 
932 #endif
std::string toString(int32_t precision=6) const
Create a string representation of this decimal_fixedpoint.
Definition: decimal_fixedpoint.h:427
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:408
decimal_fixedpoint & operator-=(const decimal_fixedpoint &v)
Subtracts another number from this one and sets it equal to the result.
Definition: decimal_fixedpoint.h:707
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:417
bool operator<(const decimal_fixedpoint &v) const
Checks to see if this number is less than another number.
Definition: decimal_fixedpoint.h:862
decimal_fixedpoint & inverse()
Inverts the number (1 divided by this number)
Definition: decimal_fixedpoint.h:775
decimal_fixedpoint & operator/=(const decimal_fixedpoint &v)
Divides another number from this one and sets it equal to the result.
Definition: decimal_fixedpoint.h:764
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:835
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:720
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:876
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:400
bool operator!=(const decimal_fixedpoint &v) const
Checks to see if two numbers are not equal.
Definition: decimal_fixedpoint.h:823
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
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:849
decimal_fixedpoint & operator+=(const decimal_fixedpoint &v)
Adds another number to this one and sets it equal to the result.
Definition: decimal_fixedpoint.h:648
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:811
double toDouble() const
Return a double precision version of the decimal_fixedpoint.
Definition: decimal_fixedpoint.h:331