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