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