36 : lower(lower), upper(upper), leftClosed(leftClosed), rightClosed(rightClosed) {}
39 : lower(other.lower), upper(other.upper), leftClosed(other.leftClosed), rightClosed(other.rightClosed) {}
59 return !(*
this == other);
64 throw std::invalid_argument(
"Lower bound is greater than upper bound");
71 throw std::invalid_argument(
"Upper bound is less than lower bound");
89 std::string result =
"";
108 throw std::invalid_argument(
"Interval is unbounded");
111 integers.push_back(i);
134 return lowerOk && upperOk;
151 return lowerOk && upperOk;
167 return lowerOk && upperOk;
206 return Interval(low, high, newLeftClosed, newRightClosed);
214 throw std::invalid_argument(
"Intervals are disjoint");
231 return Interval(newLower, newUpper, newLeftClosed, newRightClosed);
251 return static_cast<size_t>(
255 return static_cast<size_t>(
259 return static_cast<size_t>(
264 return static_cast<size_t>(
280 std::vector<Interval> result;
325 if (intervals.empty())
327 if (intervals.size() == 1)
328 return {intervals[0]};
331 std::vector<Interval> sortedIntervals = intervals;
332 std::sort(sortedIntervals.begin(), sortedIntervals.end(), [](
const Interval &a,
const Interval &b) {
333 return a.lower < b.lower ||
334 (a.lower == b.lower && a.leftClosed > b.leftClosed);
337 std::vector<Interval> result;
338 Interval current = sortedIntervals[0];
340 for (
size_t i = 1; i < sortedIntervals.size(); ++i) {
342 bool intersectOrAdjacent = !current.
isDisjointFrom(sortedIntervals[i]);
344 if (intersectOrAdjacent) {
347 std::min(current.
lower, sortedIntervals[i].lower),
348 std::max(current.
upper, sortedIntervals[i].upper),
350 : (sortedIntervals[i].lower < current.
lower)
352 : (current.
leftClosed || sortedIntervals[i].leftClosed),
354 : (sortedIntervals[i].upper > current.
upper)
356 : (current.
rightClosed || sortedIntervals[i].rightClosed));
361 result.push_back(current);
362 current = sortedIntervals[i];
367 result.push_back(current);
434 else if (
upper <= 0) {
457 bool new_leftClosed =
true;
458 bool new_rightClosed =
true;
466 new_leftClosed =
false;
470 new_leftClosed =
false;
475 new_leftClosed =
false;
481 new_rightClosed =
false;
486 new_rightClosed =
false;
489 return Interval(new_lower, new_upper, new_leftClosed, new_rightClosed);
503 bool new_leftClosed =
true;
504 bool new_rightClosed =
true;
509 new_leftClosed =
false;
513 new_leftClosed =
false;
518 new_leftClosed =
false;
524 new_rightClosed =
false;
529 new_rightClosed =
false;
532 return Interval(new_lower, new_upper, new_leftClosed, new_rightClosed);
546 bool new_leftClosed =
true;
547 bool new_rightClosed =
true;
552 new_leftClosed =
false;
556 new_leftClosed =
false;
561 new_leftClosed =
false;
567 new_rightClosed =
false;
572 new_rightClosed =
false;
575 return Interval(new_lower, new_upper, new_leftClosed, new_rightClosed);
584 bool newLeftClosed =
false;
585 bool newRightClosed =
false;
609 return Interval(newLower, newUpper, newLeftClosed, newRightClosed);
625 newLeftClosed =
true;
629 newLeftClosed =
false;
634 newLeftClosed =
false;
639 newRightClosed =
true;
643 newRightClosed =
false;
648 newRightClosed =
false;
651 return Interval(newLower, newUpper, newLeftClosed, newRightClosed);
668 newLeftClosed =
true;
672 newLeftClosed =
false;
677 newLeftClosed =
false;
682 newRightClosed =
true;
686 newRightClosed =
false;
691 newRightClosed =
false;
694 return Interval(newLower, newUpper, newLeftClosed, newRightClosed);
721 factor = (
upper / TWO_PI).floor();
727 if (highNorm < lowNorm) {
735 Number minVal = std::min(sinLow, sinHigh);
736 Number maxVal = std::max(sinLow, sinHigh);
745 if ((lowNorm <= PI_HALF && highNorm >= PI_HALF) ||
746 (lowNorm <= PI_HALF + TWO_PI && highNorm >= PI_HALF + TWO_PI)) {
748 newLeftClosed =
true;
752 if ((lowNorm <= THREE_PI_HALF && highNorm >= THREE_PI_HALF) ||
753 (lowNorm <= THREE_PI_HALF + TWO_PI &&
754 highNorm >= THREE_PI_HALF + TWO_PI)) {
756 newRightClosed =
true;
759 if (minVal >
Number(-1)) {
762 newLeftClosed =
false;
767 newRightClosed =
false;
770 return Interval(minVal, maxVal, newLeftClosed, newRightClosed);
797 factor = (
upper / TWO_PI).floor();
803 if (highNorm < lowNorm) {
811 Number minVal = std::min(cosLow, cosHigh);
812 Number maxVal = std::max(cosLow, cosHigh);
822 if ((lowNorm <= ZERO && highNorm >= ZERO) ||
823 (lowNorm <= ZERO + TWO_PI && highNorm >= ZERO + TWO_PI)) {
825 newLeftClosed =
true;
829 if ((lowNorm <= PI && highNorm >= PI) ||
830 (lowNorm <= PI + TWO_PI && highNorm >= PI + TWO_PI)) {
832 newRightClosed =
true;
835 if (minVal >
Number(-1)) {
838 newLeftClosed =
false;
843 newRightClosed =
false;
846 return Interval(minVal, maxVal, newLeftClosed, newRightClosed);
866 if (lowMod < -PI_HALF)
868 if (lowMod >= PI_HALF)
871 factor = (
upper / PI).floor();
873 if (highMod < -PI_HALF)
875 if (highMod >= PI_HALF)
879 if ((lowMod <= -PI_HALF && highMod >= -PI_HALF) ||
880 (lowMod <= PI_HALF && highMod >= PI_HALF)) {
892 if (tanLow > tanHigh) {
893 std::swap(tanLow, tanHigh);
894 std::swap(newLeftClosed, newRightClosed);
899 newLeftClosed =
false;
900 newRightClosed =
false;
902 return Interval(tanLow, tanHigh, newLeftClosed, newRightClosed);
920 return one / tanInterval;
938 return one / cosInterval;
956 return one / sinInterval;
966 throw std::domain_error(
"Argument for asin must be in range [-1, 1]");
976 bool newLeftClosed =
false;
977 bool newRightClosed =
false;
979 return Interval(asinLow, asinHigh, newLeftClosed, newRightClosed);
989 throw std::domain_error(
"Argument for acos must be in range [-1, 1]");
1012 bool newLeftClosed =
false;
1013 bool newRightClosed =
false;
1015 return Interval(atanLow, atanHigh, newLeftClosed, newRightClosed);
1029 return Interval(acotLow, acotHigh,
false,
false);
1039 throw std::domain_error(
"Argument for asec must be outside range (-1, 1)");
1052 return oneOver.
acos();
1062 throw std::domain_error(
"Argument for acsc must be outside range (-1, 1)");
1075 return oneOver.
asin();
1090 bool newLeftClosed =
false;
1091 bool newRightClosed =
false;
1093 return Interval(sinhLow, sinhHigh, newLeftClosed, newRightClosed);
1106 bool newLeftClosed =
false;
1107 bool newRightClosed =
false;
1114 if (coshLow <
Number(1)) {
1116 newLeftClosed =
true;
1119 return Interval(coshLow, coshHigh, newLeftClosed, newRightClosed);
1126 bool newLeftClosed =
false;
1127 bool newRightClosed =
false;
1134 if (coshLow <
Number(1)) {
1136 newLeftClosed =
true;
1139 return Interval(coshLow, coshHigh, newLeftClosed, newRightClosed);
1145 bool newLeftClosed =
true;
1146 bool newRightClosed =
false;
1151 return Interval(coshLow, coshHigh, newLeftClosed, newRightClosed);
1167 bool newLeftClosed =
false;
1168 bool newRightClosed =
false;
1170 return Interval(tanhLow, tanhHigh, newLeftClosed, newRightClosed);
1188 return Interval(cothLow, cothHigh,
false,
false);
1203 bool newLeftClosed =
false;
1204 bool newRightClosed =
false;
1208 newRightClosed =
true;
1215 return Interval(sechLow, sechHigh, newLeftClosed, newRightClosed);
1235 bool newLeftClosed =
false;
1236 bool newRightClosed =
false;
1238 return Interval(cschLow, cschHigh, newLeftClosed, newRightClosed);
1254 bool newLeftClosed =
false;
1255 bool newRightClosed =
false;
1257 return Interval(asinhLow, asinhHigh, newLeftClosed, newRightClosed);
1267 throw std::domain_error(
"Argument for acosh must be >= 1");
1277 bool newLeftClosed =
false;
1278 bool newRightClosed =
false;
1280 return Interval(acoshLow, acoshHigh, newLeftClosed, newRightClosed);
1290 throw std::domain_error(
"Argument for atanh must be in range (-1, 1)");
1300 bool newLeftClosed =
false;
1301 bool newRightClosed =
false;
1303 return Interval(atanhLow, atanhHigh, newLeftClosed, newRightClosed);
1313 throw std::domain_error(
"Argument for acoth must be outside range [-1, 1]");
1319 return oneOver.
atanh();
1329 throw std::domain_error(
"Argument for asech must be in range (0, 1]");
1336 return oneOver.
acosh();
1346 throw std::domain_error(
"Argument for acsch cannot be 0");
1353 return oneOver.
asinh();
1371 else if (value < 0) {
1388 throw std::domain_error(
"Division by zero");
1421 Number newLower = std::min({p1, p2, p3, p4});
1422 Number newUpper = std::max({p1, p2, p3, p4});
1423 bool newLeftClosed =
false;
1424 bool newRightClosed =
false;
1425 if (p1 == newLower) {
1428 else if (p2 == newLower) {
1431 else if (p3 == newLower) {
1434 else if (p4 == newLower) {
1438 if (p1 == newUpper) {
1441 else if (p2 == newUpper) {
1444 else if (p3 == newUpper) {
1447 else if (p4 == newUpper) {
1451 return Interval(newLower, newUpper, newLeftClosed, newRightClosed);
1483 throw std::domain_error(
"Division by zero");
1515 Number newLower = std::min({p1, p2, p3, p4});
1516 Number newUpper = std::max({p1, p2, p3, p4});
1517 bool newLeftClosed =
false;
1518 bool newRightClosed =
false;
1519 if (p1 == newLower) {
1522 else if (p2 == newLower) {
1525 else if (p3 == newLower) {
1528 else if (p4 == newLower) {
1532 if (p1 == newUpper) {
1535 else if (p2 == newUpper) {
1538 else if (p3 == newUpper) {
1541 else if (p4 == newUpper) {
1545 return Interval(newLower, newUpper, newLeftClosed, newRightClosed);
1553 throw std::domain_error(
"Division by zero");
1584 Number newLower = std::min({p1, p2, p3, p4});
1585 Number newUpper = std::max({p1, p2, p3, p4});
1586 bool newLeftClosed =
false;
1587 bool newRightClosed =
false;
1588 if (p1 == newLower) {
1591 else if (p2 == newLower) {
1594 else if (p3 == newLower) {
1597 else if (p4 == newLower) {
1601 if (p1 == newUpper) {
1604 else if (p2 == newUpper) {
1607 else if (p3 == newUpper) {
1610 else if (p4 == newUpper) {
1614 return Interval(newLower, newUpper, newLeftClosed, newRightClosed);
1621 if (value ==
Number(0)) {
1622 throw std::domain_error(
"Modulo by zero");
1624 else if (value <
Number(0)) {
1625 throw std::domain_error(
"Modulo by negative value");
1634 bool newLeftClosed =
true;
1635 bool newRightClosed =
true;
1638 if (newUpper >
upper) {
1642 else if (newUpper <
lower) {
1648 return Interval(newLower, newUpper, newLeftClosed, newRightClosed);
1660 throw std::domain_error(
"Modulo by interval containing zero");
1669 Number maxDivisor = std::max(absLower, absUpper);
1678 if (
upper < resultUpper) {
1679 resultUpper =
upper;
1683 return Interval(resultLower, resultUpper,
true,
true);
1687 return this->
mod(other);
1691 return this->
mod(value);
1695 return this->
pow(other);
1699 return this->
pow(value);
1713 newLeftClosed =
false;
1718 newLeftClosed =
false;
1727 newLeftClosed =
false;
1733 newRightClosed =
false;
1737 newRightClosed =
false;
1746 newRightClosed =
false;
1752 return Interval(newLower, newUpper, newLeftClosed, newRightClosed);
1760 if (
exp.isInfinity()) {
1761 if (
exp.isPositiveInfinity()) {
1775 throw std::domain_error(
1776 "Cannot compute infinite power with negative base");
1796 throw std::domain_error(
1797 "Cannot compute infinite power of interval containing zero");
1800 throw std::domain_error(
1801 "Cannot compute infinite power with complex results");
1807 if (
exp.isInteger()) {
1808 int n =
exp.toInteger().toInt();
1843 throw std::domain_error(
1844 "Cannot compute negative power of interval containing zero");
1898 throw std::domain_error(
1899 "Cannot compute non-integer power of negative interval");
1906 throw std::domain_error(
1907 "Cannot compute non-integer power with negative base");
1923 return Interval(val, val,
true,
true);
1925 else if (val ==
Number(2)) {
1932 bool newLeftClosed =
true;
1933 bool newRightClosed =
true;
1936 newLeftClosed =
false;
1941 newLeftClosed =
false;
1950 newLeftClosed =
false;
1956 newRightClosed =
false;
1960 newRightClosed =
false;
1969 newRightClosed =
false;
1973 return Interval(newLower, newUpper, newLeftClosed, newRightClosed);
1980 std::vector<Number> vals;
1985 vals.erase(std::remove_if(vals.begin(), vals.end(), [](
Number x) { return x.isNaN(); }),
1995 for (
auto val : vals) {
2006 bool newLeftClosed =
false, newRightClosed =
false;
2008 if (minVal == vals[0]) {
2011 else if (minVal == vals[1]) {
2014 else if (minVal == vals[2]) {
2017 else if (minVal == vals[3]) {
2021 if (maxVal == vals[0]) {
2024 else if (maxVal == vals[1]) {
2027 else if (maxVal == vals[2]) {
2030 else if (maxVal == vals[3]) {
2033 return Interval(minVal, maxVal, newLeftClosed, newRightClosed);
2039 throw std::domain_error(
2040 "Cannot compute interval power with negative or zero "
2041 "base and non-integer exponent");
2067 std::swap(low, high);
2068 std::swap(newLeftClosed, newRightClosed);
2074 newLeftClosed =
true;
2078 newLeftClosed =
false;
2083 newRightClosed =
true;
2087 newRightClosed =
false;
2089 return Interval(low, high, newLeftClosed, newRightClosed);
2137 Number minVal = std::min({vals[0], vals[1], vals[2], vals[3]});
2138 Number maxVal = std::max({vals[0], vals[1], vals[2], vals[3]});
2149 bool newLeftClosed =
false, newRightClosed =
false;
2151 if (minVal == vals[0])
2153 else if (minVal == vals[1])
2155 else if (minVal == vals[2])
2157 else if (minVal == vals[3])
2160 if (maxVal == vals[0])
2162 else if (maxVal == vals[1])
2164 else if (maxVal == vals[2])
2166 else if (maxVal == vals[3])
2172 newLeftClosed =
true;
2176 newLeftClosed =
false;
2181 newRightClosed =
true;
2184 maxVal = maxVal.nextAbove();
2185 newRightClosed =
false;
2188 return Interval(minVal, maxVal, newLeftClosed, newRightClosed);
2193 throw std::invalid_argument(
"Cannot compare empty intervals");
2206 throw std::invalid_argument(
"Cannot compare empty intervals");
2210 return !(*
this > other);
2215 throw std::invalid_argument(
"Cannot compare empty intervals");
2228 throw std::invalid_argument(
"Cannot compare empty intervals");
2232 return !(*
this < other);
2255 upper = temp * value;
2265 throw std::domain_error(
"Division by zero");
2274 upper = temp / value;
2301 return this->
sqrt();
2317 return this->
asin();
2319 return this->
acos();
2321 return this->
atan();
2323 return this->
acot();
2325 return this->
asec();
2327 return this->
acsc();
2329 return this->
sinh();
2331 return this->
cosh();
2333 return this->
tanh();
2335 return this->
coth();
2337 return this->
sech();
2339 return this->
csch();
2341 return this->
asinh();
2343 return this->
acosh();
2345 return this->
atanh();
2347 return this->
acoth();
2349 return this->
asech();
2351 return this->
acsch();
2353 throw std::invalid_argument(
"Unsupported unary operation");
2364 return (*
this + value);
2366 return (*
this - value);
2368 return (*
this * value);
2372 return this->
divInt(value);
2374 return this->
mod(value);
2376 return this->
pow(value);
2378 return this->
atan2(value);
2387 throw std::invalid_argument(
2388 "Comparison operations not supported for interval arithmetic");
2390 throw std::invalid_argument(
"Unsupported binary operation with Number");
2396 throw std::invalid_argument(
"One or both intervals are empty");
2401 return (*
this + other);
2403 return (*
this - other);
2405 return (*
this * other);
2409 return this->
divInt(other);
2411 return this->
mod(other);
2413 return this->
pow(other);
2415 return this->
atan2(other);
2435 return Interval(newLower, newUpper,
false,
false);
2445 throw std::invalid_argument(
2446 "Comparison operations not supported for interval arithmetic");
2448 throw std::invalid_argument(
"Unsupported binary operation with Interval");
#define condAssert(cond, msg)
void getIntegers(std::vector< Number > &integers) const
Interval operator~() const
Interval add(const Number &value) const
Interval operator--() const
bool isIntersectingWith(const Interval &other) const
bool isSupersetOf(const Interval &other) const
Interval(Number lower=Number::zero(), Number upper=Number::zero(), bool leftClosed=true, bool rightClosed=true)
void setLeftClosed(bool leftClosed)
void setUpper(const Number &upper)
Interval & operator/=(const Number &value)
void setLower(const Number &lower)
Interval divReal(const Number &value) const
Interval operator+() const
Interval mul(const Number &value) const
Interval operator!() const
bool operator==(const Interval &other) const
bool isRightClosed() const
bool operator<=(const Interval &other) const
Interval intersection(const Interval &other) const
Interval & operator-=(const Number &value)
Interval operator%(const Number &value) const
Interval operate(const NODE_KIND &kind) const
Interval unionWith(const Interval &other) const
bool operator<(const Interval &other) const
Interval mod(const Number &value) const
static std::vector< Interval > unionMulti(const std::vector< Interval > &intervals)
Interval operator++() const
std::vector< Interval > difference(const Interval &other) const
std::string toString() const
bool operator!=(const Interval &other) const
bool isSubsetEqOf(const Interval &other) const
bool isDisjointFrom(const Interval &other) const
size_t getIntervalIntCount() const
bool contains(const Number &value) const
Interval operator/(const Number &value) const
bool isRightUnbounded() const
Interval pow(const Number &exp) const
Interval divInt(const Number &value) const
Interval & operator*=(const Number &value)
Interval & operator=(const Interval &other)
bool operator>=(const Interval &other) const
Interval operator-() const
void setRightClosed(bool rightClosed)
bool isLeftClosed() const
Interval & operator+=(const Number &value)
Interval atan2(const Number &x) const
bool operator>(const Interval &other) const
Interval safeSqrt() const
Interval operator*(const Number &value) const
Interval sub(const Number &value) const
bool isLeftUnbounded() const
Interval operator^(const Number &value) const
bool isSubsetOf(const Interval &other) const
Number pow(const Number &exp) const
std::string toString() const
HighPrecisionInteger toInteger() const
static Number atan2(const Number &y, const Number &x)
bool isPositiveInfinity() const
static Number pi(size_t precision=128)
bool isNegativeInfinity() const
static Number positiveInfinity()
static Number negativeInfinity()