Static Value-Flow Analysis
Loading...
Searching...
No Matches
NumericValue.h
Go to the documentation of this file.
1//===- NumericValue.h ----Numeric Value-------------------------//
2//
3// SVF: Static Value-Flow Analysis
4//
5// Copyright (C) <2013-2022> <Yulei Sui>
6//
7
8// This program is free software: you can redistribute it and/or modify
9// it under the terms of the GNU Affero General Public License as published by
10// the Free Software Foundation, either version 3 of the License, or
11// (at your option) any later version.
12
13// This program is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16// GNU Affero General Public License for more details.
17
18// You should have received a copy of the GNU Affero General Public License
19// along with this program. If not, see <http://www.gnu.org/licenses/>.
20//
21//===----------------------------------------------------------------------===//
22/*
23 * Numeri Value.h
24 *
25 * Created on: May 11, 2024
26 * Author: Xiao Cheng, Jiawei Ren
27 *
28 */
29// The implementation is based on
30// Xiao Cheng, Jiawei Wang and Yulei Sui. Precise Sparse Abstract Execution via Cross-Domain Interaction.
31// 46th International Conference on Software Engineering. (ICSE24)
32
33#ifndef SVF_NUMERICVALUE_H
34#define SVF_NUMERICVALUE_H
35
36#include <cfloat> // For DBL_MAX
37#include <cmath>
38#include <utility>
39
40#include "Util/GeneralType.h"
41
42#define epsilon std::numeric_limits<double>::epsilon();
43namespace SVF
44{
45
56{
57protected:
58 s64_t _iVal; // The 64-bit integer value.
59 bool _isInf; // True if the value is infinite. If true, _iVal == 1
60 // represents positive infinity and _iVal == 0 represents
61 // negative infinity.
62
63 // Default constructor is protected to prevent creating an object without
64 // initializing _iVal and _isInf.
65 BoundedInt() = default;
66
67public:
68 // Constructs a BoundedInt with the given 64-bit integer value. The value is
69 // not infinite.
71
72 // Constructs a BoundedInt with the given 64-bit integer value and infinity
73 // flag.
75
76 // Copy constructor.
78
79 // Copy assignment operator.
81 {
82 _iVal = rhs._iVal;
83 _isInf = rhs._isInf;
84 return *this;
85 }
86
87 // Move constructor.
89
90 // Move assignment operator.
92 {
93 _iVal = rhs._iVal;
94 _isInf = rhs._isInf;
95 return *this;
96 }
97
98 // Virtual destructor.
99 virtual ~BoundedInt() {}
100
101 // Checks if the BoundedInt represents positive infinity.
102 bool is_plus_infinity() const
103 {
104 return _isInf && _iVal == 1;
105 }
106
107 // Checks if the BoundedInt represents negative infinity.
108 bool is_minus_infinity() const
109 {
110 return _isInf && _iVal == -1;
111 }
112
113 // Checks if the BoundedInt represents either positive or negative infinity.
114 bool is_infinity() const
115 {
117 }
118
119 // Sets the BoundedInt to represent positive infinity.
121 {
122 *this = plus_infinity();
123 }
124
125 // Sets the BoundedInt to represent negative infinity.
127 {
128 *this = minus_infinity();
129 }
130
131 // Returns a BoundedInt representing positive infinity.
133 {
134 return {1, true};
135 }
136
137 // Returns a BoundedInt representing negative infinity.
139 {
140 return {-1, true};
141 }
142
143 // Checks if the BoundedInt represents zero.
144 bool is_zero() const
145 {
146 return _iVal == 0;
147 }
148
149 // Checks if the given BoundedInt represents zero.
150 static bool isZero(const BoundedInt& expr)
151 {
152 return expr._iVal == 0;
153 }
154
155 // Checks if the BoundedInt is equal to another BoundedInt.
156 bool equal(const BoundedInt& rhs) const
157 {
158 return _iVal == rhs._iVal && _isInf == rhs._isInf;
159 }
160
161 // Checks if the BoundedInt is less than or equal to another BoundedInt.
162 bool leq(const BoundedInt& rhs) const
163 {
164 // If only one of the two BoundedInts is infinite.
165 if (is_infinity() ^ rhs.is_infinity())
166 {
167 if (is_infinity())
168 {
169 return is_minus_infinity();
170 }
171 else
172 {
173 return rhs.is_plus_infinity();
174 }
175 }
176 // If both BoundedInts are infinite.
177 if (is_infinity() && rhs.is_infinity())
178 {
179 if (is_minus_infinity())
180 return true;
181 else
182 return rhs.is_plus_infinity();
183 }
184 // If neither BoundedInt is infinite.
185 else
186 return _iVal <= rhs._iVal;
187 }
188
189 // Checks if the BoundedInt is greater than or equal to another BoundedInt.
190 bool geq(const BoundedInt& rhs) const
191 {
192 // If only one of the two BoundedInts is infinite.
193 if (is_infinity() ^ rhs.is_infinity())
194 {
195 if (is_infinity())
196 {
197 return is_plus_infinity();
198 }
199 else
200 {
201 return rhs.is_minus_infinity();
202 }
203 }
204 // If both BoundedInts are infinite.
205 if (is_infinity() && rhs.is_infinity())
206 {
207 if (is_plus_infinity())
208 return true;
209 else
210 return rhs.is_minus_infinity();
211 }
212 // If neither BoundedInt is infinite.
213 else
214 return _iVal >= rhs._iVal;
215 }
216
218 //{%
219 // Overloads the equality operator to compare two BoundedInt objects.
220 friend bool operator==(const BoundedInt& lhs, const BoundedInt& rhs)
221 {
222 return lhs.equal(rhs);
223 }
224
225 // Overloads the inequality operator to compare two BoundedInt objects.
226 friend bool operator!=(const BoundedInt& lhs, const BoundedInt& rhs)
227 {
228 return !lhs.equal(rhs);
229 }
230
231 // Overloads the greater than operator to compare two BoundedInt objects.
232 friend bool operator>(const BoundedInt& lhs, const BoundedInt& rhs)
233 {
234 return !lhs.leq(rhs);
235 }
236
237 // Overloads the less than operator to compare two BoundedInt objects.
238 friend bool operator<(const BoundedInt& lhs, const BoundedInt& rhs)
239 {
240 return !lhs.geq(rhs);
241 }
242
243 // Overloads the less than or equal to operator to compare two BoundedInt
244 // objects.
245 friend bool operator<=(const BoundedInt& lhs, const BoundedInt& rhs)
246 {
247 return lhs.leq(rhs);
248 }
249
250 // Overloads the greater than or equal to operator to compare two BoundedInt
251 // objects.
252 friend bool operator>=(const BoundedInt& lhs, const BoundedInt& rhs)
253 {
254 return lhs.geq(rhs);
255 }
256
282 {
283 // If one number is positive infinity and the other is negative
284 // infinity, this is an invalid operation, so we assert false.
285 if ((lhs.is_plus_infinity() && rhs.is_minus_infinity()) ||
286 (lhs.is_minus_infinity() && rhs.is_plus_infinity()))
287 {
288 assert(false && "invalid add");
289 }
290
291 // If either number is positive infinity, the result is positive
292 // infinity.
293 if (lhs.is_plus_infinity() || rhs.is_plus_infinity())
294 {
295 return plus_infinity();
296 }
297
298 // If either number is negative infinity, the result is negative
299 // infinity.
300 if (lhs.is_minus_infinity() || rhs.is_minus_infinity())
301 {
302 return minus_infinity();
303 }
304
305 // If both numbers are positive and their sum would exceed the maximum
306 // representable number, the result is positive infinity.
307 if (lhs._iVal > 0 && rhs._iVal > 0 &&
308 (std::numeric_limits<s64_t>::max() - lhs._iVal) < rhs._iVal)
309 {
310 return plus_infinity();
311 }
312
313 // If both numbers are negative and their sum would be less than the
314 // most negative representable number, the result is negative infinity.
315 if (lhs._iVal < 0 && rhs._iVal < 0 &&
316 (-std::numeric_limits<s64_t>::max() - lhs._iVal) > rhs._iVal)
317 {
318 return minus_infinity();
319 }
320
321 // If none of the above conditions are met, the numbers can be safely
322 // added.
323 return lhs._iVal + rhs._iVal;
324 }
325
326 // Overloads the addition operator to safely add two BoundedInt objects.
327 // Utilizes the safeAdd method to handle potential overflow and underflow.
329 {
330 return safeAdd(lhs, rhs);
331 }
332
333 // Overloads the unary minus operator to negate a BoundedInt object.
334 // The operation simply negates the internal integer value.
336 {
337 return {-lhs._iVal, lhs._isInf};
338 }
339
340 // Overloads the subtraction operator to safely subtract one BoundedInt
341 // object from another. This is implemented as the addition of the lhs and
342 // the negation of the rhs, using the safeAdd method for safety.
344 {
345 return safeAdd(lhs, -rhs);
346 }
347
366 {
367 // If either number is zero, the result is zero.
368 if (lhs._iVal == 0 || rhs._iVal == 0)
369 return 0;
370
371 // If either number is infinity, the result depends on the signs of the
372 // numbers.
373 if (lhs.is_infinity() || rhs.is_infinity())
374 {
375 // If the signs of the numbers are the same, the result is positive
376 // infinity. If the signs of the numbers are different, the result
377 // is negative infinity.
378 if (lhs._iVal * rhs._iVal > 0)
379 {
380 return plus_infinity();
381 }
382 else
383 {
384 return minus_infinity();
385 }
386 }
387
388 // If both numbers are positive and their product would exceed the
389 // maximum representable number, the result is positive infinity.
390 if (lhs._iVal > 0 && rhs._iVal > 0 &&
391 (std::numeric_limits<s64_t>::max() / lhs._iVal) < rhs._iVal)
392 {
393 return plus_infinity();
394 }
395
396 // If both numbers are negative and their product would exceed the
397 // maximum representable number, the result is positive infinity.
398 if (lhs._iVal < 0 && rhs._iVal < 0 &&
399 (std::numeric_limits<s64_t>::max() / lhs._iVal) > rhs._iVal)
400 {
401 return plus_infinity();
402 }
403
404 // If one number is positive and the other is negative and their product
405 // would be less than the most negative representable number, the result
406 // is negative infinity.
407 if ((lhs._iVal > 0 && rhs._iVal < 0 &&
408 (-std::numeric_limits<s64_t>::max() / lhs._iVal) > rhs._iVal) ||
409 (lhs._iVal < 0 && rhs._iVal > 0 &&
410 (-std::numeric_limits<s64_t>::max() / rhs._iVal) > lhs._iVal))
411 {
412 return minus_infinity();
413 }
414
415 // If none of the above conditions are met, the numbers can be safely
416 // multiplied.
417 return lhs._iVal * rhs._iVal;
418 }
419
420
422 {
423 if (rhs.is_zero())
424 assert(false && "divide by zero");
425 else if (!lhs.is_infinity() && !rhs.is_infinity())
426 return lhs._iVal % rhs._iVal;
427 else if (!lhs.is_infinity() && rhs.is_infinity())
428 return 0;
429 // TODO: not sure
430 else if (lhs.is_infinity() && !rhs.is_infinity())
431 return ite(rhs._iVal > 0, lhs, -lhs);
432 else
433 // TODO: +oo/-oo L'Hôpital's rule?
434 return eq(lhs, rhs) ? plus_infinity() : minus_infinity();
435 abort();
436 }
437 // Overloads the multiplication operator to safely multiply two BoundedInt
438 // objects. Utilizes the safeMul method to handle potential overflow.
440 {
441 return safeMul(lhs, rhs);
442 }
443
444 // Overloads the division operator to safely divide a BoundedInt object by
445 // another. Utilizes the safeDiv method to handle potential division by zero
446 // and overflow.
448 {
449 if (rhs.is_zero())
450 {
451 assert(false && "divide by zero");
452 abort();
453 }
454 else if (!lhs.is_infinity() && !rhs.is_infinity())
455 return lhs._iVal / rhs._iVal;
456 else if (!lhs.is_infinity() && rhs.is_infinity())
457 return 0;
458 else if (lhs.is_infinity() && !rhs.is_infinity())
459 return ite(rhs._iVal >= 0, lhs, -lhs);
460 else
461 return eq(lhs, rhs) ? plus_infinity() : minus_infinity();
462 }
463
464 // Overload bitwise operators for BoundedInt objects. These operators
465 // directly apply the corresponding bitwise operators to the internal
466 // integer values of the BoundedInt objects.
467
468 // Overloads the bitwise XOR operator for BoundedInt objects.
470 {
471 return lhs._iVal ^ rhs._iVal;
472 }
473
474 // Overloads the bitwise AND operator for BoundedInt objects.
476 {
477 return lhs._iVal & rhs._iVal;
478 }
479
480 // Overloads the bitwise OR operator for BoundedInt objects.
482 {
483 return lhs._iVal | rhs._iVal;
484 }
485
486 // Overload logical operators for BoundedInt objects. These operators
487 // directly apply the corresponding logical operators to the internal
488 // integer values of the BoundedInt objects.
489
490 // Overloads the logical AND operator for BoundedInt objects.
492 {
493 return lhs._iVal && rhs._iVal;
494 }
495
496 // Overloads the logical OR operator for BoundedInt objects.
498 {
499 return lhs._iVal || rhs._iVal;
500 }
501
502 // Overloads the logical NOT operator for BoundedInt objects.
504 {
505 return !lhs._iVal;
506 }
507
508 // Overloads the right shift operator for BoundedInt objects.
509 // This operation is safe as long as the right-hand side is non-negative.
510 // If the left-hand side is zero or infinity, the result is the same as the
511 // left-hand side. If the right-hand side is infinity, the result depends on
512 // the sign of the left-hand side.
514 {
515 assert(rhs.geq(0) && "rhs should be greater or equal than 0");
516 if (lhs.is_zero())
517 return lhs;
518 else if (lhs.is_infinity())
519 return lhs;
520 else if (rhs.is_infinity())
521 return lhs.geq(0) ? 0 : -1;
522 else
523 return lhs._iVal >> rhs._iVal;
524 }
525
526 // Overloads the left shift operator for BoundedInt objects.
527 // This operation is safe as long as the right-hand side is non-negative.
528 // If the left-hand side is zero or infinity, the result is the same as the
529 // left-hand side. If the right-hand side is infinity, the result depends on
530 // the sign of the left-hand side.
532 {
533 assert(rhs.geq(0) && "rhs should be greater or equal than 0");
534 if (lhs.is_zero())
535 return lhs;
536 else if (lhs.is_infinity())
537 return lhs;
538 else if (rhs.is_infinity())
539 return lhs.geq(0) ? plus_infinity() : minus_infinity();
540 else
541 return lhs._iVal << rhs._iVal;
542 }
543
544 // Overloads the ternary if-then-else operator for BoundedInt objects.
545 // The condition is evaluated as a boolean, and the result is either the
546 // second or third argument depending on the condition.
547 friend BoundedInt ite(const BoundedInt& cond, const BoundedInt& lhs,
548 const BoundedInt& rhs)
549 {
550 return cond._iVal != 0 ? lhs : rhs;
551 }
552
553 // Overloads the stream insertion operator for BoundedInt objects.
554 // This allows BoundedInt objects to be printed directly using std::cout or
555 // other output streams.
556 friend std::ostream& operator<<(std::ostream& out, const BoundedInt& expr)
557 {
558 out << expr._iVal;
559 return out;
560 }
561
562 // Defines a function to compare two BoundedInt objects for equality.
563 // This function directly compares the internal integer values of the
564 // BoundedInt objects.
565 friend bool eq(const BoundedInt& lhs, const BoundedInt& rhs)
566 {
567 return lhs._iVal == rhs._iVal && lhs._isInf == rhs._isInf;
568 }
569
570 // Defines a function to find the minimum of two BoundedInt objects.
571 // This function directly compares the internal integer values of the BoundedInt objects,
572 // and also checks if either of them represents infinity.
573 friend BoundedInt min(const BoundedInt& lhs, const BoundedInt& rhs)
574 {
575 if (lhs.is_minus_infinity() || rhs.is_minus_infinity())
576 return minus_infinity();
577 else if(lhs.is_plus_infinity())
578 return rhs;
579 else if(rhs.is_plus_infinity())
580 return lhs;
581 else
582 return BoundedInt(std::min(lhs._iVal, rhs._iVal));
583 }
584
585
586 // Defines a function to find the maximum of two BoundedInt objects.
587 // This function directly compares the internal integer values of the BoundedInt objects,
588 // and also checks if either of them represents infinity.
589 friend BoundedInt max(const BoundedInt& lhs, const BoundedInt& rhs)
590 {
591 if (lhs.is_plus_infinity() || rhs.is_plus_infinity())
592 return plus_infinity();
593 else if(lhs.is_minus_infinity())
594 return rhs;
595 else if(rhs.is_minus_infinity())
596 return lhs;
597 else
598 return BoundedInt(std::max(lhs._iVal, rhs._iVal));
599 }
600
601
602 // Defines a function to find the minimum of a vector of BoundedInt objects.
603 // This function iterates over the vector and returns the smallest
604 // BoundedInt object.
605 static BoundedInt min(std::vector<BoundedInt>& _l)
606 {
608 for (const auto& it : _l)
609 {
610 if (it.is_minus_infinity())
611 return minus_infinity();
612 else if (!it.geq(ret))
613 {
614 ret = it;
615 }
616 }
617 return ret;
618 }
619
620 // Defines a function to find the maximum of a vector of BoundedInt objects.
621 // This function iterates over the vector and returns the largest BoundedInt
622 // object.
623 static BoundedInt max(std::vector<BoundedInt>& _l)
624 {
626 for (const auto& it : _l)
627 {
628 if (it.is_plus_infinity())
629 return plus_infinity();
630 else if (!it.leq(ret))
631 {
632 ret = it;
633 }
634 }
635 return ret;
636 }
637
638 // Defines a function to find the absolute value of a BoundedInt object.
639 // This function directly applies the unary minus operator if the BoundedInt
640 // object is negative.
642 {
643 return lhs.leq(0) ? -lhs : lhs;
644 }
645
646 // Defines a method to check if a BoundedInt object is true.
647 // A BoundedInt object is considered true if its internal integer value is
648 // non-zero.
649 inline bool is_true() const
650 {
651 return _iVal != 0;
652 }
653
665 inline s64_t getNumeral() const
666 {
667 // If the object represents negative infinity, return the minimum
668 // representable 64-bit integer.
669 if (is_minus_infinity())
670 {
671 return std::numeric_limits<s64_t>::min();
672 }
673 // If the object represents positive infinity, return the maximum
674 // representable 64-bit integer.
675 else if (is_plus_infinity())
676 {
677 return std::numeric_limits<s64_t>::max();
678 }
679 // Otherwise, return the actual 64-bit integer value of the object.
680 else
681 {
682 return _iVal;
683 }
684 }
685
686 inline virtual const std::string to_string() const
687 {
688 if (is_minus_infinity())
689 {
690 return "-oo";
691 }
692 if (is_plus_infinity())
693 {
694 return "+oo";
695 }
696 else
697 return std::to_string(_iVal);
698 }
699
700 //%}
701
702 bool is_real() const
703 {
704 return false;
705 }
706
707 inline s64_t getIntNumeral() const
708 {
709 return getNumeral();
710 }
711
712 inline double getRealNumeral() const
713 {
714 assert(false && "cannot get real number for integer!");
715 abort();
716 }
717
718 const double getFVal() const
719 {
720 assert(false && "cannot get real number for integer!");
721 abort();
722 }
723};
728{
729protected:
730 double _fVal;
731
732 BoundedDouble() = default;
733
734public:
736
738
740 {
741 _fVal = rhs._fVal;
742 return *this;
743 }
744
746
748 {
749 _fVal = std::move(rhs._fVal);
750 return *this;
751 }
752
753 virtual ~BoundedDouble() {}
754
755 static bool doubleEqual(double a, double b)
756 {
757 if (std::isinf(a) && std::isinf(b))
758 return a == b;
759 return std::fabs(a - b) < epsilon;
760 }
761
762 const double getFVal() const
763 {
764 return _fVal;
765 }
766
767 bool is_plus_infinity() const
768 {
769 return _fVal == std::numeric_limits<double>::infinity();
770 }
771
772 bool is_minus_infinity() const
773 {
774 return _fVal == -std::numeric_limits<double>::infinity();
775 }
776
777 bool is_infinity() const
778 {
780 }
781
783 {
784 *this = plus_infinity();
785 }
786
788 {
789 *this = minus_infinity();
790 }
791
793 {
794 return std::numeric_limits<double>::infinity();
795 }
796
798 {
799 return -std::numeric_limits<double>::infinity();
800 }
801
802 bool is_zero() const
803 {
804 return doubleEqual(_fVal, 0.0f);
805 }
806
807 static bool isZero(const BoundedDouble& expr)
808 {
809 return doubleEqual(expr.getFVal(), 0.0f);
810 }
811
812 bool equal(const BoundedDouble& rhs) const
813 {
814 return doubleEqual(_fVal, rhs._fVal);
815 }
816
817 bool leq(const BoundedDouble& rhs) const
818 {
819 if (is_infinity() ^ rhs.is_infinity())
820 {
821 if (is_infinity())
822 {
823 return is_minus_infinity();
824 }
825 else
826 {
827 return rhs.is_plus_infinity();
828 }
829 }
830 if (is_infinity() && rhs.is_infinity())
831 {
832 if (is_minus_infinity())
833 return true;
834 else
835 return rhs.is_plus_infinity();
836 }
837 else
838 return _fVal <= rhs._fVal;
839 }
840
841 bool geq(const BoundedDouble& rhs) const
842 {
843 if (is_infinity() ^ rhs.is_infinity())
844 {
845 if (is_infinity())
846 {
847 return is_plus_infinity();
848 }
849 else
850 {
851 return rhs.is_minus_infinity();
852 }
853 }
854 if (is_infinity() && rhs.is_infinity())
855 {
856 if (is_plus_infinity())
857 return true;
858 else
859 return rhs.is_minus_infinity();
860 }
861 else
862 return _fVal >= rhs._fVal;
863 }
864
866 //{%
867 friend bool operator==(const BoundedDouble& lhs,
868 const BoundedDouble& rhs)
869 {
870 return lhs.equal(rhs);
871 }
872
873 friend bool operator!=(const BoundedDouble& lhs,
874 const BoundedDouble& rhs)
875 {
876 return !lhs.equal(rhs);
877 }
878
879 friend bool operator>(const BoundedDouble& lhs,
880 const BoundedDouble& rhs)
881 {
882 return !lhs.leq(rhs);
883 }
884
885 friend bool operator<(const BoundedDouble& lhs,
886 const BoundedDouble& rhs)
887 {
888 return !lhs.geq(rhs);
889 }
890
891 friend bool operator<=(const BoundedDouble& lhs,
892 const BoundedDouble& rhs)
893 {
894 return lhs.leq(rhs);
895 }
896
897 friend bool operator>=(const BoundedDouble& lhs,
898 const BoundedDouble& rhs)
899 {
900 return lhs.geq(rhs);
901 }
902
912 static double safeAdd(double lhs, double rhs)
913 {
914 if ((lhs == std::numeric_limits<double>::infinity() &&
915 rhs == -std::numeric_limits<double>::infinity()) ||
916 (lhs == -std::numeric_limits<double>::infinity() &&
917 rhs == std::numeric_limits<double>::infinity()))
918 {
919 assert(false && "invalid add");
920 }
921 double res =
922 lhs + rhs; // Perform the addition and store the result in 'res'
923
924 // Check if the result is positive infinity due to overflow
925 if (res == std::numeric_limits<double>::infinity())
926 {
927 return res; // Positive overflow has occurred, return positive
928 // infinity
929 }
930
931 // Check if the result is negative infinity, which can indicate a large
932 // negative overflow
933 if (res == -std::numeric_limits<double>::infinity())
934 {
935 return res; // Negative "overflow", effectively an underflow to
936 // negative infinity
937 }
938
939 // Check for positive overflow: verify if both operands are positive and
940 // their sum exceeds the maximum double value
941 if (lhs > 0 && rhs > 0 &&
942 (std::numeric_limits<double>::max() - lhs) < rhs)
943 {
944 res = std::numeric_limits<double>::infinity(); // Set result to
945 // positive infinity to
946 // indicate overflow
947 return res;
948 }
949
950 // Check for an underflow scenario: both numbers are negative and their
951 // sum is more negative than what double can represent
952 if (lhs < 0 && rhs < 0 &&
953 (-std::numeric_limits<double>::max() - lhs) > rhs)
954 {
955 res = -std::numeric_limits<
956 double>::infinity(); // Set result to negative infinity to
957 // clarify extreme negative sum
958 return res;
959 }
960
961 // If none of the above conditions are met, return the result of the
962 // addition
963 return res;
964 }
965
967 const BoundedDouble& rhs)
968 {
969 return safeAdd(lhs._fVal, rhs._fVal);
970 }
971
973 {
974 return -lhs._fVal;
975 }
976
978 const BoundedDouble& rhs)
979 {
980 return safeAdd(lhs._fVal, -rhs._fVal);
981 }
982
992 static double safeMul(double lhs, double rhs)
993 {
994 if (doubleEqual(lhs, 0.0f) || doubleEqual(rhs, 0.0f))
995 return 0.0f;
996 double res = lhs * rhs;
997 // Check if the result is positive infinity due to overflow
998 if (res == std::numeric_limits<double>::infinity())
999 {
1000 return res; // Positive overflow has occurred, return positive
1001 // infinity
1002 }
1003
1004 // Check if the result is negative infinity, which can indicate a large
1005 // negative overflow
1006 if (res == -std::numeric_limits<double>::infinity())
1007 {
1008 return res; // Negative "overflow", effectively an underflow to
1009 // negative infinity
1010 }
1011 // Check for overflow scenarios
1012 if (lhs > 0 && rhs > 0 &&
1013 lhs > std::numeric_limits<double>::max() / rhs)
1014 {
1015 return std::numeric_limits<double>::infinity();
1016 }
1017 if (lhs < 0 && rhs < 0 &&
1018 lhs < std::numeric_limits<double>::max() / rhs)
1019 {
1020 return std::numeric_limits<double>::infinity();
1021 }
1022
1023 // Check for "underflow" scenarios (negative overflow)
1024 if (lhs > 0 && rhs < 0 &&
1025 rhs < std::numeric_limits<double>::lowest() / lhs)
1026 {
1027 return -std::numeric_limits<double>::infinity();
1028 }
1029 if (lhs < 0 && rhs > 0 &&
1030 lhs < std::numeric_limits<double>::lowest() / rhs)
1031 {
1032 return -std::numeric_limits<double>::infinity();
1033 }
1034
1035 return res; // If no overflow or underflow, return the product
1036 }
1037
1039 const BoundedDouble& rhs)
1040 {
1041 return safeMul(lhs._fVal, rhs._fVal);
1042 }
1043
1053 static double safeDiv(double lhs, double rhs)
1054 {
1055 // Check for division by zero
1056 if (doubleEqual(rhs, 0.0f))
1057 {
1058 return (lhs >= 0.0f) ? std::numeric_limits<double>::infinity()
1059 : -std::numeric_limits<double>::infinity();
1060 }
1061 double res = lhs / rhs;
1062 // Check if the result is positive infinity due to overflow
1063 if (res == std::numeric_limits<double>::infinity())
1064 {
1065 return res; // Positive overflow has occurred, return positive
1066 // infinity
1067 }
1068
1069 // Check if the result is negative infinity, which can indicate a large
1070 // negative overflow
1071 if (res == -std::numeric_limits<double>::infinity())
1072 {
1073 return res; // Negative "overflow", effectively an underflow to
1074 // negative infinity
1075 }
1076
1077 // Check for overflow when dividing small numbers
1078 if (rhs > 0 && rhs < std::numeric_limits<double>::min() &&
1079 lhs > std::numeric_limits<double>::max() * rhs)
1080 {
1081 return std::numeric_limits<double>::infinity();
1082 }
1083 if (rhs < 0 && rhs > -std::numeric_limits<double>::min() &&
1084 lhs > std::numeric_limits<double>::max() * rhs)
1085 {
1086 return -std::numeric_limits<double>::infinity();
1087 }
1088
1089 return res; // If no special cases, return the quotient
1090 }
1091
1093 const BoundedDouble& rhs)
1094 {
1095 return safeDiv(lhs._fVal, rhs._fVal);
1096 }
1097
1099 const BoundedDouble& rhs)
1100 {
1101 if (rhs.is_zero())
1102 assert(false && "divide by zero");
1103 else if (!lhs.is_infinity() && !rhs.is_infinity())
1104 return std::fmod(lhs._fVal, rhs._fVal);
1105 else if (!lhs.is_infinity() && rhs.is_infinity())
1106 return 0.0f;
1107 // TODO: not sure
1108 else if (lhs.is_infinity() && !rhs.is_infinity())
1109 return ite(rhs._fVal > 0.0f, lhs, -lhs);
1110 else
1111 // TODO: +oo/-oo L'Hôpital's rule?
1112 return eq(lhs, rhs) ? plus_infinity() : minus_infinity();
1113 abort();
1114 }
1115
1116 inline bool is_int() const
1117 {
1118 return _fVal == std::round(_fVal);
1119 }
1120 inline bool is_real() const
1121 {
1122 return !is_int();
1123 }
1124
1126 const BoundedDouble& rhs)
1127 {
1128 int lInt = std::round(lhs._fVal), rInt = std::round(rhs._fVal);
1129 return lInt ^ rInt;
1130 }
1131
1133 const BoundedDouble& rhs)
1134 {
1135 int lInt = std::round(lhs._fVal), rInt = std::round(rhs._fVal);
1136 return lInt & rInt;
1137 }
1138
1140 const BoundedDouble& rhs)
1141 {
1142 int lInt = std::round(lhs._fVal), rInt = std::round(rhs._fVal);
1143 return lInt | rInt;
1144 }
1145
1147 const BoundedDouble& rhs)
1148 {
1149 return lhs._fVal && rhs._fVal;
1150 }
1151
1153 const BoundedDouble& rhs)
1154 {
1155 return lhs._fVal || rhs._fVal;
1156 }
1157
1159 {
1160 return !lhs._fVal;
1161 }
1162
1164 const BoundedDouble& rhs)
1165 {
1166 assert(rhs.geq(0) && "rhs should be greater or equal than 0");
1167 if (lhs.is_zero())
1168 return lhs;
1169 else if (lhs.is_infinity())
1170 return lhs;
1171 else if (rhs.is_infinity())
1172 return lhs.geq(0) ? 0 : -1;
1173 else
1174 return (s32_t)lhs.getNumeral() >> (s32_t)rhs.getNumeral();
1175 }
1176
1178 const BoundedDouble& rhs)
1179 {
1180 assert(rhs.geq(0) && "rhs should be greater or equal than 0");
1181 if (lhs.is_zero())
1182 return lhs;
1183 else if (lhs.is_infinity())
1184 return lhs;
1185 else if (rhs.is_infinity())
1186 return lhs.geq(0) ? plus_infinity() : minus_infinity();
1187 else
1188 return (s32_t)lhs.getNumeral() << (s32_t)rhs.getNumeral();
1189 }
1190
1191 friend BoundedDouble ite(const BoundedDouble& cond,
1192 const BoundedDouble& lhs, const BoundedDouble& rhs)
1193 {
1194 return cond._fVal != 0.0f ? lhs._fVal : rhs._fVal;
1195 }
1196
1197 friend std::ostream& operator<<(std::ostream& out,
1198 const BoundedDouble& expr)
1199 {
1200 out << expr._fVal;
1201 return out;
1202 }
1203
1204 friend bool eq(const BoundedDouble& lhs, const BoundedDouble& rhs)
1205 {
1206 return doubleEqual(lhs._fVal, rhs._fVal);
1207 }
1208
1210 {
1211 return std::min(lhs._fVal, rhs._fVal);
1212 }
1213
1215 {
1216 return std::max(lhs._fVal, rhs._fVal);
1217 }
1218
1219 static BoundedDouble min(std::vector<BoundedDouble>& _l)
1220 {
1222 for (const auto& it : _l)
1223 {
1224 if (it.is_minus_infinity())
1225 return minus_infinity();
1226 else if (!it.geq(ret))
1227 {
1228 ret = it;
1229 }
1230 }
1231 return ret;
1232 }
1233
1234 static BoundedDouble max(std::vector<BoundedDouble>& _l)
1235 {
1237 for (const auto& it : _l)
1238 {
1239 if (it.is_plus_infinity())
1240 return plus_infinity();
1241 else if (!it.leq(ret))
1242 {
1243 ret = it;
1244 }
1245 }
1246 return ret;
1247 }
1248
1250 {
1251 return lhs.leq(0) ? -lhs : lhs;
1252 }
1253
1254 inline bool is_true() const
1255 {
1256 return _fVal != 0.0f;
1257 }
1258
1260 inline s64_t getNumeral() const
1261 {
1262 if (is_minus_infinity())
1263 {
1264 return INT64_MIN;
1265 }
1266 else if (is_plus_infinity())
1267 {
1268 return INT64_MAX;
1269 }
1270 else
1271 {
1272 return std::round(_fVal);
1273 }
1274 }
1275
1276 inline s64_t getIntNumeral() const
1277 {
1278 return getNumeral();
1279 }
1280
1281 inline double getRealNumeral() const
1282 {
1283 return _fVal;
1284 }
1285
1286 inline virtual const std::string to_string() const
1287 {
1288 return std::to_string(_fVal);
1289 }
1290
1291 //%}
1292}; // end class BoundedDouble
1293
1294} // end namespace SVF
1295
1296#endif // SVF_NUMERICVALUE_H
#define epsilon
#define false
Definition cJSON.cpp:70
cJSON * a
Definition cJSON.cpp:2560
const cJSON *const b
Definition cJSON.h:255
BoundedDouble & operator=(const BoundedDouble &rhs)
friend BoundedDouble max(const BoundedDouble &lhs, const BoundedDouble &rhs)
friend bool operator!=(const BoundedDouble &lhs, const BoundedDouble &rhs)
bool is_int() const
friend bool operator<=(const BoundedDouble &lhs, const BoundedDouble &rhs)
friend BoundedDouble operator%(const BoundedDouble &lhs, const BoundedDouble &rhs)
friend bool operator<(const BoundedDouble &lhs, const BoundedDouble &rhs)
const double getFVal() const
BoundedDouble()=default
friend BoundedDouble operator>>(const BoundedDouble &lhs, const BoundedDouble &rhs)
static double safeDiv(double lhs, double rhs)
friend BoundedDouble operator*(const BoundedDouble &lhs, const BoundedDouble &rhs)
virtual ~BoundedDouble()
static double safeMul(double lhs, double rhs)
static BoundedDouble minus_infinity()
friend BoundedDouble operator!(const BoundedDouble &lhs)
friend BoundedDouble ite(const BoundedDouble &cond, const BoundedDouble &lhs, const BoundedDouble &rhs)
static BoundedDouble plus_infinity()
friend BoundedDouble operator&&(const BoundedDouble &lhs, const BoundedDouble &rhs)
bool equal(const BoundedDouble &rhs) const
BoundedDouble & operator=(BoundedDouble &&rhs)
s64_t getIntNumeral() const
static bool isZero(const BoundedDouble &expr)
static bool doubleEqual(double a, double b)
bool is_real() const
bool geq(const BoundedDouble &rhs) const
friend BoundedDouble operator-(const BoundedDouble &lhs)
friend BoundedDouble operator-(const BoundedDouble &lhs, const BoundedDouble &rhs)
s64_t getNumeral() const
Return Numeral.
friend BoundedDouble operator|(const BoundedDouble &lhs, const BoundedDouble &rhs)
friend BoundedDouble min(const BoundedDouble &lhs, const BoundedDouble &rhs)
bool is_true() const
friend BoundedDouble operator^(const BoundedDouble &lhs, const BoundedDouble &rhs)
static double safeAdd(double lhs, double rhs)
friend BoundedDouble abs(const BoundedDouble &lhs)
friend BoundedDouble operator<<(const BoundedDouble &lhs, const BoundedDouble &rhs)
friend BoundedDouble operator/(const BoundedDouble &lhs, const BoundedDouble &rhs)
friend bool eq(const BoundedDouble &lhs, const BoundedDouble &rhs)
static BoundedDouble min(std::vector< BoundedDouble > &_l)
friend BoundedDouble operator+(const BoundedDouble &lhs, const BoundedDouble &rhs)
BoundedDouble(const BoundedDouble &rhs)
bool is_minus_infinity() const
BoundedDouble(BoundedDouble &&rhs)
bool leq(const BoundedDouble &rhs) const
bool is_plus_infinity() const
virtual const std::string to_string() const
static BoundedDouble max(std::vector< BoundedDouble > &_l)
friend BoundedDouble operator&(const BoundedDouble &lhs, const BoundedDouble &rhs)
double getRealNumeral() const
friend bool operator>=(const BoundedDouble &lhs, const BoundedDouble &rhs)
BoundedDouble(double fVal)
friend BoundedDouble operator||(const BoundedDouble &lhs, const BoundedDouble &rhs)
friend bool operator==(const BoundedDouble &lhs, const BoundedDouble &rhs)
Reload operator.
bool is_zero() const
friend std::ostream & operator<<(std::ostream &out, const BoundedDouble &expr)
friend bool operator>(const BoundedDouble &lhs, const BoundedDouble &rhs)
bool is_infinity() const
A class representing a bounded 64-bit integer.
BoundedInt()=default
static BoundedInt plus_infinity()
friend BoundedInt operator||(const BoundedInt &lhs, const BoundedInt &rhs)
friend BoundedInt ite(const BoundedInt &cond, const BoundedInt &lhs, const BoundedInt &rhs)
friend bool operator<=(const BoundedInt &lhs, const BoundedInt &rhs)
bool is_minus_infinity() const
friend bool operator<(const BoundedInt &lhs, const BoundedInt &rhs)
s64_t getNumeral() const
Retrieves the numeral value of the BoundedInt object.
virtual ~BoundedInt()
bool is_plus_infinity() const
friend BoundedInt operator%(const BoundedInt &lhs, const BoundedInt &rhs)
friend BoundedInt operator<<(const BoundedInt &lhs, const BoundedInt &rhs)
static BoundedInt min(std::vector< BoundedInt > &_l)
friend BoundedInt operator&(const BoundedInt &lhs, const BoundedInt &rhs)
static BoundedInt safeMul(const BoundedInt &lhs, const BoundedInt &rhs)
Performs safe multiplication of two BoundedInt objects.
bool is_infinity() const
const double getFVal() const
friend BoundedInt operator*(const BoundedInt &lhs, const BoundedInt &rhs)
friend BoundedInt abs(const BoundedInt &lhs)
BoundedInt(BoundedInt &&rhs)
friend BoundedInt operator|(const BoundedInt &lhs, const BoundedInt &rhs)
friend BoundedInt operator/(const BoundedInt &lhs, const BoundedInt &rhs)
friend bool operator!=(const BoundedInt &lhs, const BoundedInt &rhs)
friend BoundedInt max(const BoundedInt &lhs, const BoundedInt &rhs)
s64_t getIntNumeral() const
friend bool operator>(const BoundedInt &lhs, const BoundedInt &rhs)
friend BoundedInt operator+(const BoundedInt &lhs, const BoundedInt &rhs)
friend BoundedInt operator>>(const BoundedInt &lhs, const BoundedInt &rhs)
friend BoundedInt operator!(const BoundedInt &lhs)
friend BoundedInt operator^(const BoundedInt &lhs, const BoundedInt &rhs)
bool is_zero() const
friend BoundedInt operator&&(const BoundedInt &lhs, const BoundedInt &rhs)
bool is_true() const
BoundedInt & operator=(const BoundedInt &rhs)
friend std::ostream & operator<<(std::ostream &out, const BoundedInt &expr)
static BoundedInt max(std::vector< BoundedInt > &_l)
friend bool eq(const BoundedInt &lhs, const BoundedInt &rhs)
static BoundedInt safeAdd(const BoundedInt &lhs, const BoundedInt &rhs)
static BoundedInt minus_infinity()
friend BoundedInt min(const BoundedInt &lhs, const BoundedInt &rhs)
bool geq(const BoundedInt &rhs) const
bool equal(const BoundedInt &rhs) const
BoundedInt & operator=(BoundedInt &&rhs)
bool leq(const BoundedInt &rhs) const
static bool isZero(const BoundedInt &expr)
double getRealNumeral() const
BoundedInt(s64_t fVal, bool isInf)
void set_minus_infinity()
bool is_real() const
friend BoundedInt operator-(const BoundedInt &lhs)
void set_plus_infinity()
friend BoundedInt operator-(const BoundedInt &lhs, const BoundedInt &rhs)
friend bool operator>=(const BoundedInt &lhs, const BoundedInt &rhs)
BoundedInt(const BoundedInt &rhs)
virtual const std::string to_string() const
friend bool operator==(const BoundedInt &lhs, const BoundedInt &rhs)
Reload operator.
BoundedInt(s64_t fVal)
for isBitcode
Definition BasicTypes.h:70
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76
signed s32_t
Definition GeneralType.h:68
signed long long s64_t
Definition GeneralType.h:70