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