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