SST  11.0.0
StructuralSimulationToolkit
decimal_fixedpoint.h
1 // -*- c++ -*-
2 
3 // Copyright 2009-2021 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-2021, 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  Return true if value is zero, otherwise return false.
398  */
399  bool isZero() const {
400  for ( int i = whole_words + fraction_words - 1; i >= 0; --i ) {
401  if ( data[i] != 0 ) return false;
402  }
403  return true;
404  }
405 
406  /**
407  Templated conversion function for unsigned types.
408  */
409  template<typename T>
410  T convert_to(typename std::enable_if<std::is_unsigned<T>::value>::type* = 0) const {
411  return static_cast<T>(toUnsignedLong());
412  }
413 
414  /**
415  Templated conversion function for signed integral types.
416  */
417  template<typename T>
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());
421  }
422 
423  /**
424  Templated conversion function for floating point types.
425  */
426  template<typename T>
427  T convert_to(typename std::enable_if<std::is_floating_point<T>::value >::type* = 0) const {
428  return static_cast<T>(toDouble());
429  }
430 
431  /**
432  Create a string representation of this decimal_fixedpoint.
433 
434  @param precision Precision to use when printing number
435 
436  */
437  std::string toString(int32_t precision = 6) const {
438 
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;
442 
443  // First create a digit by digit representation so we can
444  // reason about what to print based on the precision.
445  constexpr int num_digits = (whole_words + fraction_words) * digits_per_word;
446 
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;
452  value /= 10;
453  }
454  }
455 
456  // Find the first non-zero
457  int first_non_zero = -1;
458  for ( int i = num_digits - 1; i >= 0; --i ) {
459  if ( digits[i] != 0 ) {
460  first_non_zero = i;
461  break;
462  }
463  }
464 
465  // If no non-zeros, return 0
466  if ( first_non_zero == -1 ) return "0";
467 
468  // Now, we will round to the precision asked for
469  int round_position = first_non_zero - precision;
470  bool round = false;
471 
472  // If round_position < 0 then we have already gotten all the
473  // digits that exist, so no need to round
474  if ( round_position >= 0 ) {
475  if ( digits[round_position] > 5 ) round = true;
476  else if ( digits[round_position] < 5 ) round = false;
477  else { // Round if the rest aren't zeros
478 
479  for ( int i = round_position - 1; i >= 0; --i ) {
480  if ( digits[i] != 0 ) {
481  round = true;
482  break;
483  }
484  }
485  if ( !round ) {
486  // There were no extra zeros, so we need to do round
487  // to nearest even.
488  if ( digits[round_position+1] % 2 == 1 ) round = true;
489  }
490  }
491 
492  if ( round ) {
493  // Do the round
494  unsigned char carry = 1;
495  for ( int i = round_position + 1; i < num_digits; ++i ) {
496  digits[i] += carry;
497  carry = digits[i] / 10;
498  digits[i] = digits[i] % 10;
499  }
500  }
501 
502  // Zero out all the bits beyond the precision
503  for ( int i = 0; i <= round_position; ++i ) {
504  digits[i] = 0;
505  }
506  }
507 
508  // print possible negative sign
509  if ( negative ) stream << '-';
510 
511 
512  // Find the first non-zero
513  first_non_zero = -1;
514  for ( int i = num_digits - 1; i >= 0; --i ) {
515  if ( digits[i] != 0 ) {
516  first_non_zero = i;
517  break;
518  }
519  }
520 
521  // Check for overflow in the round
522  if ( first_non_zero == -1 ) {
523  // This means we rounded to a number bigger than we can
524  // support
525  stream << "1e+" << (whole_words*digits_per_word);
526  return stream.str();
527  }
528 
529  // There are several cases to cover:
530 
531  // Need to switch to exponent notation for numbers > 1
532  if ( first_non_zero >= ((fraction_words*digits_per_word) + precision) ) {
533  // Need to use exponent notation
534  int exponent = first_non_zero - (fraction_words * digits_per_word );
535  stream << static_cast<uint32_t>(digits[first_non_zero]) << ".";
536  int zeros = 0;
537  for ( int i = first_non_zero - 1; i >= first_non_zero - precision; --i ) {
538  // Avoid printing trailing zeros. Keep track of runs
539  // of zeros and only print them if we hit another
540  // non-xero
541  if ( digits[i] == 0 ) zeros++;
542  else {
543  for ( int j = 0; j < zeros; ++j ) {
544  stream << "0";
545  }
546  stream << static_cast<uint32_t>(digits[i]);
547  zeros = 0;
548  }
549  }
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(""));
554  stream << ret;
555  }
556  stream << "e+" << std::setfill('0') << std::setw(2) << exponent;
557  // return stream.str();
558  }
559 
560  // Decimal point is within the string of digits to print
561  else if ( first_non_zero >= (fraction_words * digits_per_word)) {
562  int zeros = 0;
563  for ( int i = first_non_zero; i >= (fraction_words * digits_per_word); --i ) {
564  // Digits before the decimal point
565  stream << static_cast<uint32_t>(digits[i]);
566  }
567 
568  stream << ".";
569 
570  for ( int i = (fraction_words * digits_per_word) - 1;
571  i >= first_non_zero - precision && (i >= 0);
572  --i ) {
573  // Avoid printing trailing zeros. Keep track of runs
574  // of zeros and only print them if we hit another
575  // non-xero
576  if ( digits[i] == 0 ) zeros++;
577  else {
578  for ( int j = 0; j < zeros; ++j ) {
579  stream << "0";
580  }
581  stream << static_cast<uint32_t>(digits[i]);
582  zeros = 0;
583  }
584  }
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(""));
589  stream << ret;
590  }
591  }
592 
593  // No whole digits, but not switching to exponent notation
594  // yet. We are willing to print three leading zeros before
595  // switching to exponent notation
596  else if ( first_non_zero > (fraction_words * digits_per_word) - 5 ) {
597  stream << "0.";
598  for ( int i = (fraction_words * digits_per_word) - 1; i > first_non_zero; --i ) {
599  stream << "0";
600  }
601  int zeros = 0;
602  for ( int i = first_non_zero;
603  (i >= first_non_zero - precision) && (i >= 0);
604  --i ) {
605  // Avoid printing trailing zeros. Keep track of runs
606  // of zeros and only print them if we hit another
607  // non-xero
608  if ( digits[i] == 0 ) zeros++;
609  else {
610  for ( int j = 0; j < zeros; ++j ) {
611  stream << "0";
612  }
613  stream << static_cast<uint32_t>(digits[i]);
614  zeros = 0;
615  }
616  }
617  }
618  // Switch to exponent notation
619  else {
620  // Need to use exponent notation
621  int exponent = first_non_zero - (fraction_words * digits_per_word );
622  exponent = -exponent;
623  stream << static_cast<uint32_t>(digits[first_non_zero]) << ".";
624  int zeros = 0;
625  for ( int i = first_non_zero - 1;
626  (i >= first_non_zero - precision) && (i >= 0);
627  --i ) {
628  // Avoid printing trailing zeros. Keep track of runs
629  // of zeros and only print them if we hit another
630  // non-xero
631  if ( digits[i] == 0 ) zeros++;
632  else {
633  for ( int j = 0; j < zeros; ++j ) {
634  stream << "0";
635  }
636  stream << static_cast<uint32_t>(digits[i]);
637  zeros = 0;
638  }
639  }
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(""));
644  stream << ret;
645  }
646  stream << "e-" << std::setfill('0') << std::setw(2) << exponent;
647  }
648 
649  return stream.str();
650  }
651 
652  /**
653  Adds another number to this one and sets it equal to the
654  result.
655 
656  @param v Number to add to this one
657  */
659  // Depending on the signs, this may be a subtract
660  if ( (negative ^ v.negative) == 0 ) {
661  // Signs match, just do an add
662  // Calculate the result for each digit.
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])
667  + carry_over;
668  carry_over = value / storage_radix;
669  // data[i] = static_cast<uint32_t>(value % storage_radix);
670  data[i] = value % storage_radix;
671  }
672  return *this;
673  }
674 
675  // Signs don't match, so we need to sort
676  if ( operator>=(v) ) {
677  // Calculate the result for each digit. Need to negate the
678  // second operand and pass a 1 in as carry-in (carry-over).
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]);
682 
683  uint64_t value = static_cast<uint64_t>(data[i])
684  + negate
685  + carry_over;
686  carry_over = value / storage_radix;
687  data[i] = static_cast<uint32_t>(value % storage_radix);
688  }
689  return *this;
690  }
691  else {
692  // Calculate the result for each digit. Need to negate the
693  // second operand and pass a 1 in as carry-in (carry-over).
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]);
697 
698  uint64_t value = static_cast<uint64_t>(v.data[i])
699  + negate
700  + carry_over;
701  carry_over = value / storage_radix;
702  data[i] = static_cast<uint32_t>(value % storage_radix);
703  }
704  // Since the other one is bigger, I take his sign
705  negative = v.negative;
706  return *this;
707  }
708  }
709 
710 
711  /**
712  Subtracts another number from this one and sets it equal to the
713  result.
714 
715  @param v Number to subtract from this one
716  */
718  decimal_fixedpoint ret(v);
719  ret.negate();
720  return operator+=(ret);
721  }
722 
723 
724  /**
725  Multiplies another number to this one and sets it equal to the
726  result.
727 
728  @param v Number to multiply to this one
729  */
731  // Need to do the multiply accumulate for each digit.
733 
734  // The first "fraction_words" digits only matter as far as
735  // their carries go. They get dropped in the final output
736  // because they are less than the least significant digit.
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]);
742  }
743  carry_over = sum / storage_radix_long;
744  }
745 
746  // Calculate the digits that we'll keep
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]);
751  }
752  carry_over = sum / storage_radix_long;
753  data[i-fraction_words] = static_cast<uint32_t>(sum % storage_radix_long);
754  }
755 
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]);
761  }
762  carry_over = sum / storage_radix_long;
763  data[i+whole_words] = static_cast<uint32_t>(sum % storage_radix_long);
764  }
765  // Get the sign
766  negative = negative ^ v.negative;
767  return *this;
768  }
769 
770  /**
771  Divides another number from this one and sets it equal to the
772  result.
773 
774  @param v Number to divide from this one
775  */
777  decimal_fixedpoint inv(v);
778  inv.inverse();
779  operator*=(inv);
780  return *this;
781  }
782 
783  /**
784  Inverts the number (1 divided by this number)
785  */
786 
788  // We will use the Newton-Raphson method to compute the
789  // inverse
790 
791  // First, get an estimate of the inverse by converting to a
792  // double and inverting
793  decimal_fixedpoint me(*this);
795  // decimal_fixedpoint<whole_words,fraction_words> inv("400");
796 
798 
799  // Since we converted to double to get an estimate of the
800  // inverse, we have approximated a double's worth of precision
801  // in our answer. We'll divide that by 2 for now, just to be
802  // save.
803  int digits_of_prec = std::numeric_limits<double>::digits10 / 2;
804 
805  // Number of digits of precision doubles with each iteration
806  for ( int i = digits_of_prec; i <= (whole_words + fraction_words) * digits_per_word; i *= 2 ) {
807  decimal_fixedpoint temp(inv);
808  temp *= me;
809  temp -= two;
810  temp.negate();
811  inv *= temp;
812  }
813 
814  *this = inv;
815  return *this;
816  }
817 
818  /**
819  Checks to see if two numbers are 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 false;
826  }
827  return true;
828  }
829 
830  /**
831  Checks to see if two numbers are not equal
832 
833  @param v Number to check equality against
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  }
839  return false;
840  }
841 
842  /**
843  Checks to see if this number is greater than another number
844 
845  @param v Number to compare to
846  */
847  bool operator> (const decimal_fixedpoint& v) const {
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;
851  }
852  return false;
853  }
854 
855  /**
856  Checks to see if this number is greater than or equal to
857  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 true;
867  }
868 
869  /**
870  Checks to see if this number is less than another number
871 
872  @param v Number to compare to
873  */
874  bool operator< (const decimal_fixedpoint& v) const {
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;
878  }
879  return false;
880  }
881 
882  /**
883  Checks to see if this number is less than or equal to another
884  number
885 
886  @param v Number to compare to
887  */
888  bool operator<= (const decimal_fixedpoint& v) const {
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;
892  }
893  return true;
894  }
895 
896 };
897 
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);
902  return ret += rhs;
903 }
904 
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);
909  return ret -= rhs;
910 }
911 
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);
916  return ret *= rhs;
917 }
918 
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);
923  return ret /= rhs;
924 }
925 
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);
929 }
930 
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);
934 }
935 
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());
939  return os;
940 }
941 
942 } // namespace SST
943 
944 #endif
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