SST 12.1.0
Structural Simulation Toolkit
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
24namespace 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*/
39template <int whole_words, int fraction_words>
41{
42
43public:
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
58private:
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
190public:
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
902template <int whole_words, int fraction_words>
903decimal_fixedpoint<whole_words, fraction_words>
904operator+(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
910template <int whole_words, int fraction_words>
911decimal_fixedpoint<whole_words, fraction_words>
912operator-(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
918template <int whole_words, int fraction_words>
919decimal_fixedpoint<whole_words, fraction_words>
920operator*(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
926template <int whole_words, int fraction_words>
927decimal_fixedpoint<whole_words, fraction_words>
928operator/(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
934template <int whole_words, int fraction_words, typename T>
935bool
936operator==(const T& lhs, const decimal_fixedpoint<whole_words, fraction_words>& rhs)
937{
938 return rhs == decimal_fixedpoint<whole_words, fraction_words>(lhs);
939}
940
941template <int whole_words, int fraction_words, typename T>
942bool
943operator!=(const T& lhs, const decimal_fixedpoint<whole_words, fraction_words>& rhs)
944{
945 return rhs != decimal_fixedpoint<whole_words, fraction_words>(lhs);
946}
947
948template <int whole_words, int fraction_words>
949std::ostream&
950operator<<(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
Class that implements a decimal fixed-point number.
Definition: decimal_fixedpoint.h:41
decimal_fixedpoint(const std::string &init)
Build a decimal_fixedpoint using a string initializer.
Definition: decimal_fixedpoint.h:211
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
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
std::string toString(int32_t precision=6) const
Create a string representation of this decimal_fixedpoint.
Definition: decimal_fixedpoint.h:439
decimal_fixedpoint & inverse()
Inverts the number (1 divided by this number)
Definition: decimal_fixedpoint.h:785
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 greater than another number.
Definition: decimal_fixedpoint.h:848
decimal_fixedpoint & operator=(const std::string &v)
Equal operator for string.
Definition: decimal_fixedpoint.h:314
decimal_fixedpoint & operator=(const decimal_fixedpoint &v)
Equal operator for other decimal_fixedpoint objects.
Definition: decimal_fixedpoint.h:269
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(const decimal_fixedpoint &init)
Build a decimal_fixedpoint using another decimal_fixedpoint.
Definition: decimal_fixedpoint.h:258
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
bool operator!=(const decimal_fixedpoint &v) const
Checks to see if two numbers are not equal.
Definition: decimal_fixedpoint.h:835
constexpr int getWholeWords() const
Get the value of whole_words template parameter.
Definition: decimal_fixedpoint.h:51
int64_t toLong() const
Return a int64_t version of the decimal_fixedpoint.
Definition: decimal_fixedpoint.h:349
decimal_fixedpoint & operator=(int64_t v)
Equal operator for 64-bit signed int.
Definition: decimal_fixedpoint.h:290
double toDouble() const
Return a double precision version of the decimal_fixedpoint.
Definition: decimal_fixedpoint.h:329
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
decimal_fixedpoint & operator=(double v)
Equal operator for double.
Definition: decimal_fixedpoint.h:305
bool isZero() const
Return true if value is zero, otherwise return false.
Definition: decimal_fixedpoint.h:398
decimal_fixedpoint()
Default constructor.
Definition: decimal_fixedpoint.h:196
uint64_t toUnsignedLong() const
Return a uint64_t version of the decimal_fixedpoint.
Definition: decimal_fixedpoint.h:384
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
bool operator<(const decimal_fixedpoint &v) const
Checks to see if this number is less than another number.
Definition: decimal_fixedpoint.h:877
bool operator==(const decimal_fixedpoint &v) const
Checks to see if two numbers are equal.
Definition: decimal_fixedpoint.h:822
void negate()
Negate the value (change the sign bit).
Definition: decimal_fixedpoint.h:323
decimal_fixedpoint & operator=(uint64_t v)
Equal operator for 64-bit unsigned int.
Definition: decimal_fixedpoint.h:281
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 or equal to another number.
Definition: decimal_fixedpoint.h:892
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
constexpr int getFractionWords() const
Get the value of fraction_words template parameter.
Definition: decimal_fixedpoint.h:56
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