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