com.sun.electric.util.math.MutableInterval Maven / Gradle / Ivy
The newest version!
/* -*- tab-width: 4 -*-
*
* Electric(tm) VLSI Design System
*
* File: MutableInterval.java
*
* Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
*
* Electric(tm) is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* Electric(tm) is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Electric(tm); see the file COPYING. If not, write to
* the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, Mass 02111-1307, USA.
*/
package com.sun.electric.util.math;
import java.math.BigDecimal;
/**
* Mutable class for representation of intervals X = [a, b].
* a and b are double precision floation point numbers with a <= b.
*
* Closed ("extended") interval system is implemented, which is the extension
* of regular interval system.
*
* The elements of the regular interval system (IR) are intervals with regular
* IEEE floating point number bounds.
*
* In the closed ("extended") interval system (IR*) the set of regular
* intervals IR is extended by infinite intervals and the empty interval.
* All arithmetic operations and mathematical functions are closed on IR*.
* For details see the paper
*
* Interval Arithmetic Specification by Chiriaev and Walster. The
* implementation is following this specification.
* Three special intervals are supported in the extended system:
*
* - [ EMPTY ], represented as [ NaN, NaN ]
*
- [ -INF ], represented as [ -INF, -MAX ]
*
- [ +INF ], represented as [ MAX, +INF]
*
* where MAX is the largest regular floating point number. All interval
* operations are guaranteed to produce results consistent with these
* representations.
*/
public class MutableInterval
{
/* Fields */
private double inf;
private double sup;
/* Constants */
/**
* A constant holding 3/4*ulp(1).
* next(x) is round-to-nearest
* of (x + x*ULP_EPS) for positive normalized doble numbers.
*/
private static final double ULP_EPS = 1.5/(1L << 53); // 0x1.8p-53;
/**
* A constant holding prev(1).
* prev(x) is round-to-nearest
* if (x*SCALE_DOWN) for positive normalized double numbers.
*/
private static final double SCALE_DOWN = 1.0 - 1.0/(1L << 53); // 0x1.fffffffffffffp-1;
/**
* A constant holding minimal positive normalized double number.
*/
private static final double MIN_NORMAL = Double.MIN_VALUE*(1L << 52); // 0x1.0p-1022;
/**
* A constant limiting those x for which x*ULP_EPS is noramlized.
*/
private static final double ULP_EPS_NORMAL = MIN_NORMAL / ULP_EPS; // 0x1.5555555555555p-970
/**
* A constant holding ulp(Double.MAX_VALUE).
*/
private static final double MAX_ULP = Double.MAX_VALUE/(1L << 53)/SCALE_DOWN; // 0x1.0p971;
/**
* A constant holding range of long numbers exactly represented
* by double numbers. All longs in [ -EXACT_LONG, EXACT_LONG] are
* represented exactly. Some of other longs are not.
*/
private static final long EXACT_LONG = 1L << 53;
// -----------------------------------------------------------------------
// Constructors
// -----------------------------------------------------------------------
/**
* Constructs a point interval [0,0].
*/
public MutableInterval() {
}
/**
* Constructs a point interval [x,x].
*/
public MutableInterval(int x) {
assign(x);
}
/**
* Constructs sharpest interval containing x.
*/
public MutableInterval(long x) {
assign(x);
}
/**
* Constructs a point interval [x,x].
*
* Special cases in the extended system:
*
* - if x == +INF then [ +INF ] is constructed
*
- if x == -INF then [ -INF ] is constructed
*
- if x == NaN then the entire interval [ -INF,+INF ] is constructed
*
*/
public MutableInterval(double x) {
assign(x);
}
/**
* Constructs the interval [inf, sup].
*
* Special cases in the extended system:
*
* - if inf < sup then the entire interval [ -INF,+INF ] is constructed
*
*
* @param inf The infimum of the interval to be constructed.
* @param sup The supremum of the interval to be constructed.
*/
public MutableInterval(int inf, int sup) {
assign(inf, sup);
}
/**
* Constructs the interval [inf, sup].
*
* Special cases in the extended system:
*
* - if inf < sup then the entire interval [ -INF,+INF ] is constructed
*
*
* @param inf The infimum of the interval to be constructed.
* @param sup The supremum of the interval to be constructed.
*/
public MutableInterval(long inf, long sup) {
assign(inf, sup);
}
/**
* Constructs the interval [inf, sup].
*
* Special cases in the extended system:
*
* - if inf == sup == -INF the interval [ -INF ] is constructed
*
- if inf == sup == +INF the interval [ +INF ] is constructed
*
- if inf < sup then the entire interval [ -INF,+INF ] is constructed
*
- if inf == NaN or sup == NaN then the entire interval [ -INF,+INF ] is constructed
*
*
* @param inf The infimum of the interval to be constructed.
* @param sup The supremum of the interval to be constructed.
*/
public MutableInterval(double inf, double sup) {
assign(inf, sup);
}
/**
* Constructs the interval same as x.
*/
public MutableInterval(MutableInterval x) {
assign(x);
}
/**
* Constructs the interval from string.
*/
public MutableInterval(String s) {
assign(s);
}
/**
* Constructs the interval from character array.
*/
public MutableInterval(char[] b) {
assign(b);
}
// -----------------------------------------------------------------------
// Assigns
// -----------------------------------------------------------------------
/**
* Assigns a point interval [x,x].
*/
public MutableInterval assign(int x) {
inf = sup = (double)x;
return this;
}
/**
* Assigns sharpest interval containing x.
*/
public MutableInterval assign(long x) {
double xd = (double)x;
inf = sup = xd;
if (Math.abs(x) > EXACT_LONG) {
long xx = (long)xd;
if (xx > x || x == Long.MAX_VALUE)
inf = prev(xd);
else if (xx < x)
sup = next(xd);
}
return this;
}
/**
* Assigns a point interval.
*
* Special cases in the extended system:
*
* - if x == +INF then [ +INF ] is constructed
*
- if x == -INF then [ -INF ] is constructed
*
- if x == NaN then the entire interval [ -INF,+INF ] is constructed
*
*/
public MutableInterval assign(double x) {
inf = sup = x;
if (x == Double.POSITIVE_INFINITY)
inf = Double.MAX_VALUE;
else if (x == Double.NEGATIVE_INFINITY)
sup = -Double.MAX_VALUE;
else if (x != x)
assignEntire();
return this;
}
/**
* Assigns the interval [inf, sup].
*
* Special cases in the extended system:
*
* - if inf < sup then the entire interval [ -INF,+INF ] is constructed
*
*
* @param inf The infimum of the interval to be constructed.
* @param sup The supremum of the interval to be constructed.
*/
public MutableInterval assign(int inf, int sup) {
if (inf <= sup) {
this.inf = (double)inf;
this.sup = (double)sup;
} else
assignEntire();
return this;
}
/**
* Assigns the interval [inf, sup].
*
* Special cases in the extended system:
*
* - if inf < sup then the the entire interval [ -INF,+INF ] is constructed
*
*
* @param inf The infimum of the interval to be constructed.
* @param sup The supremum of the interval to be constructed.
*/
public MutableInterval assign(long inf, long sup) {
if (inf <= sup) {
this.inf = (double)inf;
this.sup = (double)sup;
if (inf < -EXACT_LONG || sup > EXACT_LONG) {
if ((long)this.inf > inf || inf == Long.MAX_VALUE)
this.inf = prev(this.inf);
if ((long)this.sup < sup)
this.sup = next(this.sup);
}
} else
assignEntire();
return this;
}
/**
* Assigns the interval [inf, sup].
*
* Special cases in the extended system:
*
* - if inf == sup == -INF the interval [ -INF ] is constructed
*
- if inf == sup == +INF the interval [ +INF ] is constructed
*
- if inf < sup then the entire interval [ -INF,+INF ] is constructed
*
- if inf == NaN or sup == NaN then the entire [ -INF,+INF ] is constructed
*
*
* @param inf The infimum of the interval to be constructed.
* @param sup The supremum of the interval to be constructed.
*/
public MutableInterval assign(double inf, double sup) {
if (inf <= sup) {
this.inf = (inf == Double.POSITIVE_INFINITY ? Double.MAX_VALUE : inf);
this.sup = (sup == Double.NEGATIVE_INFINITY ? -Double.MAX_VALUE : sup);
} else
assignEntire();
return this;
}
/**
* Assigns interval same as x.
*/
public MutableInterval assign(MutableInterval x) {
this.inf = x.inf;
this.sup = x.sup;
return this;
}
/**
* Assigns the interval from string.
*/
public MutableInterval assign(String s) {
parse(s);
return this;
}
/**
* Assigns the interval from character array.
*/
public MutableInterval assign(char[] b) {
parse(new String(b));
return this;
}
/**
* Creates and returns a copy of this MutableInterval.
*/
public MutableInterval clon() {
try {
return (MutableInterval)clone();
}
catch (CloneNotSupportedException e) {
return new MutableInterval(inf, sup);
}
}
/**
* Assigns entire interval [ -INF, +INF ].
*/
public MutableInterval assignEntire() {
inf = Double.NEGATIVE_INFINITY;
sup = Double.POSITIVE_INFINITY;
return this;
}
/**
* Assigns empty interval [-EMPTY ].
*/
public MutableInterval assignEmpty() {
inf = sup = Double.NaN;
return this;
}
// -----------------------------------------------------------------------
// Interval bounds
// -----------------------------------------------------------------------
/**
* Returns the infimum of this interval.
*
* Special cases:
* - x.inf() == NaN for x == [ EMPTY ].
*
- x.inf() == MAX_DOUBLE for x == [ +INF ].
*/
public double inf() {
return inf;
}
/**
* Returns the supremum of this interval.
*
* Special cases:
* - x.sup() == NaN for x == [ EMPTY ].
*
- x.sup() == MAX_DOUBLE for x == [ +INF ].
*/
public double sup() {
return sup;
}
// -----------------------------------------------------------------------
// Info functions
// -----------------------------------------------------------------------
/**
* Returns true iff this interval is a point interval.
* i.e. inf() == sup().
*
* Special cases in the extended system:
*
* - x.isPoint() == false for x == [ EMPTY ]
*
*/
public boolean isPoint() {
return inf == sup;
}
/**
* Same as isPoint().
*/
public boolean isDegenerate() {
return inf == sup;
}
/**
* Returns true if this == [ EMPTY ].
*/
public boolean isEmpty() {
return inf != inf;
}
/**
* Return true if either x.inf() or x.sup() is infinite.
*/
public boolean isInfinite() {
return inf == Double.NEGATIVE_INFINITY || sup == Double.POSITIVE_INFINITY;
}
/**
* Returns true iff this interval has an ulp accuracy of n.
* I.e. x.inf() and x.sup() have a distance of at most n machine numbers.
*
* Special cases in the extended system:
*
* - x.hasUlpAcc(n) == false for x == [ EMPTY ] or any infinite interval
*
*/
public boolean hasUlpAcc(int n) {
if (isInfinite())
return false;
double x = inf;
int i = 0;
while (i++ < n && x < sup)
x = next(x);
return x == sup;
}
/**
* Returns true iff this interval is an entire interval [ -INF, +INF ].
*
* Special cases in the extended system:
*
* - x.isEntire(n) == false for x == [ EMPTY ]
*
*/
public boolean isEntire() {
return -inf == sup && sup == Double.POSITIVE_INFINITY;
}
/**
* Always returns true indicating that the extended system is currently used.
*/
public static boolean isExtended() {
return true;
}
/**
* Always returns false, indicating that this is not native implementation.
*/
public static boolean isNative() {
return false;
}
// -----------------------------------------------------------------------
// Utility functions
// -----------------------------------------------------------------------
/**
* Returns double number nearest to the midpoint of this interval, i.e.
*
* x.mid == (x.inf() + x.sup()) / 2.
*
* Special cases in the extended system:
*
* - x.mid() == NaN for x == [ EMPTY ]
*
- x.mid() == 0.0 for x == [ ENTIRE ]
*
- x.mid() == +INF for x == [ +INF ] or x = [ a, +INF ]
*
- x.mid() == -INF for x == [ -INF ] or x = [ -INF, a]
*
*/
public double mid() {
double mid = 0.5*(inf + sup);
if (mid > Double.NEGATIVE_INFINITY && mid < Double.POSITIVE_INFINITY)
return mid;
return -inf == sup ? 0 : 0.5*inf + 0.5*sup;
}
/**
* Returns an upper bound for the width (diameter) of this interval, i.e.
*
* x.wid() == x.sup()-x.inf()
*
* Special cases in the extended system:
*
* - x.wid() == NaN for x == [ EMPTY ]
*
- x.wid() == +INF for any infinite interval
*
*/
public double wid() {
return addPosUp(sup, -inf);
}
/**
* Returns an upper bound for the radius of this interval, i.e.
*
* x.mid() - x.rad() <= x.inf() <= x.sup <= x.mid() + x.rad()
*
* Special cases in the extended system:
*
* - x.rad() == NaN for x == [ EMPTY ]
*
- x.rad() == +INF for any infinite interval
*
*/
public double rad() {
double mid = (inf + sup) * 0.5;
if (!(mid > Double.NEGATIVE_INFINITY && mid < Double.POSITIVE_INFINITY)) {
if (inf == Double.NEGATIVE_INFINITY || sup == Double.POSITIVE_INFINITY) return Double.POSITIVE_INFINITY;
mid = 0.5*inf + 0.5*sup;
}
return Math.max(addPosUp(sup, -mid), addPosUp(mid, -inf));
}
/**
* Returns the mignitude of this interval, i.e.
*
* x.mig() == min{abs(y) : y in x }
*
* Special cases in the extended system:
*
* - x.mig() == NaN for x == [ EMPTY ]
*
*/
public double mig() {
return inf <= 0 && sup >= 0 ? 0 : inf < 0 ? -sup : inf;
}
/**
* Returns the magnitude of this interval, i.e.
*
* x.mag() == max{abs(y) : y in x }
*
* Special cases in the extended system:
*
* - x.mag() == NaN for x == [ EMPTY ]
*
- x.mag() == +INF for any infinite interval
*
*/
public double mag() {
return -inf > sup ? -inf : sup;
}
/**
* Returns the interval of absolute values of this interval, i.e.
*
* x.abs() == [ x.mig(), x.mag() ]
*
* Special cases in the extended system:
*
* - x.abs() == [ EMPTY ] for x == [ EMPTY ]
*
- x.abs() == [ +INF ] for x == [ +/- INF ]
*
*/
public MutableInterval abs()
{
if (sup <= 0) {
double h = sup;
this.sup = -inf;
this.inf = -h;
} else if (inf < 0) {
if (-inf > sup)
this.sup = -inf;
// else sup = this.sup;
inf = 0;
} // else { inf = this.inf; sup = this.sup; }
return this;
}
/**
* Returns an enclosure for the range of minima of this interval and the
* interval x, i.e.
*
* x.min(y) == { z : z == min(a, b) : a in x, b in y }
*
* Special cases in the extended system:
*
* - x.min(y) == [ EMPTY ] for x == [ EMPTY ] and y == [ EMPTY ]
*
*/
public MutableInterval min(MutableInterval y) {
if (this.inf != this.inf) // inf = this.inf; sup = this.sup;
return this;
inf = (this.inf < y.inf ? this.inf : y.inf);
sup = (this.sup < y.sup ? this.sup : y.sup);
return this;
}
/**
* Returns an enclosure for the range of maxima of this interval and the
* interval x, i.e.
*
* x.max(y) == { z : z == max(a, b) : a in x, b in y }
*
* Special cases in the extended system:
*
* - x.max(y) == [ EMPTY ] for x == [ EMPTY ] and y == [ EMPTY ]
*
*/
public MutableInterval max(MutableInterval y) {
if (this.inf != this.inf) // inf = this.inf; sup = this.sup;
return this;
inf = (this.inf > y.inf ? this.inf : y.inf);
sup = (this.sup > y.sup ? this.sup : y.sup);
return this;
}
/**
* Returns an upper bound for the Hausdorff distance of this interval
* and the interval x, i.e.
*
* x.dist(y) == max{ abs(x.inf()-y.inf()), abs(x.sup() - y.sup()) }
*
* Special cases in the extended system:
*
* - x.dist(y) == NaN for x == [ EMPTY ] or y == [ EMPTY ]
*
*/
double dist(MutableInterval x) {
if (isEmpty() || x.isEmpty())
return Double.NaN;
if ( this.inf == x.inf && this.sup == x.sup)
return 0;
if (isInfinite() || x.isInfinite())
return Double.POSITIVE_INFINITY;;
double dinf = this.inf > x.inf ? addPosUp(this.inf, -x.inf) : addPosUp(-this.inf, x.inf);
double dsup = this.sup > x.sup ? addPosUp(this.sup, -x.sup) : addPosUp(-this.sup, x.sup);
return Math.max(dinf, dsup);
}
// -----------------------------------------------------------------------
// Set operations
// -----------------------------------------------------------------------
/**
* Returns the intersection of this interval and the interval x.
*
* Special cases in the extended system:
*
* - x.intersect(y) == [ EMPTY ] iff x and y are disjoint
*
*/
public MutableInterval intersect(MutableInterval y) {
double l, u;
if (isEmpty() || y.isEmpty()) {
this.inf = Double.NaN;
this.sup = Double.NaN;
return this;
}
l = (this.inf > y.inf ? this.inf : y.inf);
u = (this.sup < y.sup ? this.sup : y.sup);
if (l > u) {
this.inf = Double.NaN;
this.sup = Double.NaN;
return this;
}
this.inf = l;
this.sup = u;
return this;
}
/**
* Same as x.intersect(y)
*/
public MutableInterval ix(MutableInterval y) {
return intersect(y);
}
/**
* Returns the convex hull of this interval and the interval x.
*
* Special cases in the extended system:
*
* - x.interval_hull(y) == [ EMPTY ] for x == y == [ EMPTY ]
*
*/
public MutableInterval interval_hull(MutableInterval y) {
if (isEmpty()) {
this.inf = y.inf;
this.sup = y.sup;
return this;
}
if (y.isEmpty())
return this;
inf = (this.inf < y.inf ? this.inf : y.inf);
sup = (this.sup > y.sup ? this.sup : y.sup);
return this;
}
/**
* Returns the convex hull of this interval and the double x.
*
* Special cases in the extended system:
*
* - x.interval_hull(y) == [ -INF,+INF ] for y == NaN
*
*/
public MutableInterval interval_hull(double x) {
if (isEmpty())
return assign(x);
if (x != x)
return assignEntire();
inf = (this.inf < x ? this.inf : x);
sup = (this.sup > x ? this.sup : x);
return this;
}
/**
* Same as x.interval_hull(y)
*/
public MutableInterval ih(MutableInterval y) {
return interval_hull(y);
}
// -----------------------------------------------------------------------
// Set relations
// -----------------------------------------------------------------------
/**
* Returns true iff this interval and interval x are disjoint., i.e.
*
* Special cases in the extended system:
*
* - x.disjoint(y) == true for x or y == [ EMPTY ]
*
*/
public boolean disjoint(MutableInterval y) {
return !(this.inf <= y.sup && y.inf <= this.sup);
}
/**
* Same as x.disjoint(y)
*/
public boolean dj(MutableInterval y) {
return !(this.inf <= y.sup && y.inf <= this.sup);
}
/**
* Returns true iff double number x is contained in this interval.
*
* Special cases in the extended system:
*
* - x.contains(y) == false for x == [ EMPTY ] or y == NaN
*
*/
public boolean in(long x) {
double xd = (double)x;
if (xd >= -EXACT_LONG && xd <= EXACT_LONG)
return inf <= xd && xd <= sup;
long xx = (long)xd;
return (xx > x || x == Long.MAX_VALUE ? inf < xd : inf <= xd) &&
(xx < x ? xd < sup : xd <= sup);
}
/**
* Returns true iff double number x is contained in this interval.
*
* Special cases in the extended system:
*
* - x.contains(y) == false for x == [ EMPTY ] or y == NaN
*
*/
public boolean in(double y) {
return y >= this.inf && y <= this.sup;
}
/**
* Returns true iff this interval is in interior of interval x.
*
* Special cases in the extended system:
*
* - x.in_interior(y) == true for x == [ EMPTY ]
*
*/
public boolean in_interior(MutableInterval y) {
return (inf > y.inf && sup < y.sup) || isEmpty();
}
/**
* Same as x.interior(y)
*/
public boolean interior(MutableInterval y) {
return in_interior(y);
}
/**
* Returns true iff this interval is a proper subset of interval x.
*
* Special cases in the extended system:
*
* - x.proper_subset(y) == true for x == [ EMPTY ] and y != [ EMPTY ]
*
*/
public boolean proper_subset(MutableInterval y) {
return (inf >= y.inf && sup <= y.sup && (inf > y.inf || sup < y.sup)) ||
(isEmpty() && ! y.isEmpty());
}
/**
* Returns true iff this interval is a subset of interval x.
* Special cases in the extended system:
*
*
* - x.subset(y) == true for x == [ EMPTY ]
*
*/
public boolean subset(MutableInterval y) {
return y.inf <= inf && sup <= y.sup || isEmpty();
}
/**
* Returns true iff this interval is a proper superset of interval x.
*
* Special cases in the extended system:
*
* - x.proper_superset(y) == true for x != [ EMPTY ] and y == [ EMPTY ]
*
*/
public boolean proper_superset(MutableInterval y) {
return (inf <= y.inf && y.sup <= sup && (inf < y.inf || y.sup < sup)) ||
(y.isEmpty() && ! isEmpty());
}
/**
* Returns true iff this interval is a superset of interval x.
*
* Special cases in the extended system:
*
* - x.superset(y) == true for y == [ EMPTY ]
*
*/
public boolean superset(MutableInterval y) {
return inf <= y.inf && y.sup <= sup || y.isEmpty();
}
/**
* Returns true iff this interval is set-equal to interval x.
*
* Special cases in the extended system:
*
* - x.seq(y) == true for x == y == [ EMPTY ]
*
*/
public boolean seq(MutableInterval y) {
return (inf == y.inf && sup == y.sup) || isEmpty() && y.isEmpty();
}
/**
* Returns true iff this interval is set-not-equal to interval x.
*/
public boolean sne(MutableInterval y) {
return !seq(y);
}
/**
* Returns true iff this interval is set-greater-or-equal to
* interval x.
*
* Special cases in the extended system:
*
* - x.sge(y) == true for x == y == [ EMPTY ]
*
*/
public boolean sge(MutableInterval y) {
return inf >= y.inf && sup >= y.sup || isEmpty() && y.isEmpty();
}
/**
* Returns true iff this interval is set-greater than interval x.
*
* Special cases in the extended system:
*
* - x.sgt(y) == false for x == [ EMPTY ] or y == [ EMPTY ]
*
*/
public boolean sgt(MutableInterval y) {
return inf > y.inf && sup > y.sup;
}
/**
* Returns true iff this interval is set-less-or-equal to
* interval x.
*
* Special cases in the extended system:
*
* - x.sle(y) == true for x == y == [ EMPTY ]
*
*/
public boolean sle(MutableInterval y) {
return inf <= y.inf && sup <= y.sup || isEmpty() && y.isEmpty();
}
/**
* Returns true iff this interval is set-less than interval x.
*
* Special cases in the extended system:
*
* - x.slt(y) == false for x == [ EMPTY ] or y == [ EMPTY ]
*
*/
public boolean slt(MutableInterval y) {
return inf < y.inf && sup < y.sup;
}
// -----------------------------------------------------------------------
// Certainly relations
// -----------------------------------------------------------------------
/**
* Returns true iff this interval is certainly-equal to interval x.
*
* Special cases in the extended system:
*
* - x.ceq(y) == false for x == [ EMPTY ] or y == [ EMPTY ]
*
*/
public boolean ceq(MutableInterval y) {
return sup <= y.inf && inf >= y.sup;
}
/**
* Returns true iff this interval is certainly-not-equal to interval x.
*
* Special cases in the extended system:
*
* - x.cne(y) == true for x == [ EMPTY ] or y == [ EMPTY ]
*
*/
public boolean cne(MutableInterval y) {
return !(inf <= y.sup && y.inf <= sup);
}
/**
* Returns true iff this interval is certainly-greater-or-equal to
* interval x.
*
* Special cases in the extended system:
*
* - x.cge(y) == false for x == [ EMPTY ] or y == [ EMPTY ]
*
*/
public boolean cge(MutableInterval y) {
return inf >= y.sup;
}
/**
* Returns true iff this interval is certainly-greater than interval x.
*
* Special cases in the extended system:
*
* - x.cgt(y) == false for x == [ EMPTY ] or y == [ EMPTY ]
*
*/
public boolean cgt(MutableInterval y) {
return inf > y.sup;
}
/**
* Returns true iff this interval is certainly-less-or-equal to
* interval x.
*
* Special cases in the extended system:
*
* - x.cle(y) == false for x == [ EMPTY ] or y == [ EMPTY ]
*
*/
public boolean cle(MutableInterval y) {
return sup <= y.inf;
}
/**
* Returns true iff this interval is certainly-less than interval x.
*
* Special cases in the extended system:
*
* - x.clt(y) == false for x == [ EMPTY ] or y == [ EMPTY ]
*
*/
public boolean clt(MutableInterval y) {
return sup < y.inf;
}
// -----------------------------------------------------------------------
// Possibly relations
// -----------------------------------------------------------------------
/**
* Returns true iff this interval is possibly-equal to interval x.
*
* Special cases in the extended system:
*
* - x.peq(y) == false for x == [ EMPTY ] or y == [ EMPTY ]
*
*/
public boolean peq(MutableInterval y) {
return inf <= y.sup && sup >= y.inf;
}
/**
* Returns true iff this interval is possibly-not-equal to interval x.
*
* Special cases in the extended system:
*
* - x.pne(y) == true for x == [ EMPTY ] or y == [ EMPTY ]
*
*/
public boolean pne(MutableInterval y) {
return !(sup <= y.inf && inf >= y.sup);
}
/**
* Returns true iff this interval is possibly-greater-or-equal to
* interval x.
*
* Special cases in the extended system:
*
* - x.pge(y) == false for x == [ EMPTY ] or y == [ EMPTY ]
*
*/
public boolean pge(MutableInterval y) {
return sup >= y.inf;
}
/**
* Returns true iff this interval is possibly-greater than interval x.
*
* Special cases in the extended system:
*
* - x.pgt(y) == false for x == [ EMPTY ] or y == [ EMPTY ]
*
*/
public boolean pgt(MutableInterval y) {
return sup > y.inf;
}
/**
* Returns true iff this interval is possibly-less-or-equal to
* interval x.
*
* Special cases in the extended system:
*
* - x.ple(y) == false for x == [ EMPTY ] or y == [ EMPTY ]
*
*/
public boolean ple(MutableInterval y) {
return inf <= y.sup;
}
/**
* Returns true iff this interval is possibly-less than interval x.
*
* Special cases in the extended system:
*
* - x.plt(y) == false for x == [ EMPTY ] or y == [ EMPTY ]
*
*/
public boolean plt(MutableInterval y) {
return inf < y.sup;
}
// -----------------------------------------------------------------------
// Arithmetic operations
// -----------------------------------------------------------------------
/**
* Unary operator -. Myltiplies this interval by -1 and returns the product.
*
* Special cases in the extended system:
*
* - -x == [ EMPTY ] for x == [ EMPTY ]
*
*/
public MutableInterval negate() {
double l = inf;
inf = -sup;
sup = -l;
return this;
}
/**
* Adds interval y to this interval and returns the sum.
*
* Special cases in the extended system:
*
* - x += y == [ EMPTY ] for x == [ EMPTY ] or y == [ EMPTY ]
*
*/
public MutableInterval add(MutableInterval y) {
double l = this.inf + y.inf;
if (l - this.inf > y.inf || l - y.inf > this.inf) {
assert Math.abs(l) >= MIN_NORMAL*2;
l = (l < 0 ? (l < -ULP_EPS_NORMAL ? l + l*ULP_EPS : l/SCALE_DOWN) : l <= Double.MAX_VALUE ? l*SCALE_DOWN : Double.MAX_VALUE);
}
double h = this.sup + y.sup;
if (h - this.sup < y.sup || h - y.sup < this.sup) {
assert Math.abs(h) >= MIN_NORMAL*2;
h = (h > 0 ? (h > ULP_EPS_NORMAL ? h + h*ULP_EPS : h/SCALE_DOWN) : h >= -Double.MAX_VALUE ? h*SCALE_DOWN : -Double.MAX_VALUE);
}
inf = l;
sup = h;
return this;
}
/**
* Adds double number y to this interval and returns the sum.
*
* Special cases in the extended system:
*
* - x += y == [ EMPTY ] for x == [ EMPTY ] or y == NaN
*
*/
public MutableInterval add(double y) {
double l = this.inf + y;
if (l - this.inf > y || l - y > this.inf) {
assert Math.abs(l) >= MIN_NORMAL*2;
l = (l < 0 ? (l < -ULP_EPS_NORMAL ? l + l*ULP_EPS : l/SCALE_DOWN) : l <= Double.MAX_VALUE ? l*SCALE_DOWN : Double.MAX_VALUE);
} else if (!(l < Double.POSITIVE_INFINITY)) {
if (y >= this.sup) // x is not [EMPTY] and y is not NaN
l = Double.MAX_VALUE;
}
double h = this.sup + y;
if (h - this.sup < y || h - y < this.sup) {
assert Math.abs(h) >= MIN_NORMAL*2;
h = (h > 0 ? (h > ULP_EPS_NORMAL ? h + h*ULP_EPS : h/SCALE_DOWN) : h >= -Double.MAX_VALUE ? h*SCALE_DOWN : -Double.MAX_VALUE);
} else if (!(h > Double.NEGATIVE_INFINITY)) {
if (y <= this.inf) // x is not [EMPTY] and y is not NaN
h = -Double.MAX_VALUE;
}
inf = l;
sup = h;
return this;
}
/**
* Subtracts interval y from this interval and returns the difference.
*
* Special cases in the extended system:
*
* - x -= y == [ EMPTY ] for x == [ EMPTY ] or y == [ EMPTY ]
*
*/
public MutableInterval sub(MutableInterval y) {
double l = this.inf - y.sup;
if (this.inf - l < y.sup || l + y.sup > this.inf) {
assert Math.abs(l) >= MIN_NORMAL*2;
l = (l < 0 ? (l < -ULP_EPS_NORMAL ? l + l*ULP_EPS : l/SCALE_DOWN) : l <= Double.MAX_VALUE ? l*SCALE_DOWN : Double.MAX_VALUE);
}
double h = this.sup - y.inf;
if (this.sup - h > y.inf || h + y.inf < this.sup) {
assert Math.abs(h) >= MIN_NORMAL*2;
h = (h > 0 ? (h > ULP_EPS_NORMAL ? h + h*ULP_EPS : h/SCALE_DOWN) : h >= -Double.MAX_VALUE ? h*SCALE_DOWN : -Double.MAX_VALUE);
}
inf = l;
sup = h;
return this;
}
/**
* Subtracts double number y from this interval and returns the difference.
*
* Special cases in the extended system:
*
* - x -= y == [ EMPTY ] for x == [ EMPTY ] or y == NaN
*
*/
public MutableInterval sub(double y) {
double l = this.inf - y;
if (this.inf - l < y || l + y > this.inf) {
assert Math.abs(l) >= MIN_NORMAL*2;
l = (l < 0 ? (l < -ULP_EPS_NORMAL ? l + l*ULP_EPS : l/SCALE_DOWN) : l <= Double.MAX_VALUE ? l*SCALE_DOWN : Double.MAX_VALUE);
} else if (!(l < Double.POSITIVE_INFINITY)) {
if (y >= this.sup) // x is not [EMPTY] and y is not NaN
l = Double.MAX_VALUE;
}
double h = this.sup - y;
if (this.sup - h > y || h + y < this.sup) {
assert Math.abs(h) >= MIN_NORMAL*2;
h = (h > 0 ? (h > ULP_EPS_NORMAL ? h + h*ULP_EPS : h/SCALE_DOWN) : h >= -Double.MAX_VALUE ? h*SCALE_DOWN : -Double.MAX_VALUE);
} else if (!(h > Double.NEGATIVE_INFINITY)) {
if (y <= this.inf) // x is not [EMPTY] and y is not NaN
h = -Double.MAX_VALUE;
}
inf = l;
sup = h;
return this;
}
/**
* Multiplies this interval by interval y and returns the product.
*
*
* Special cases in the extended system:
*
* - x *= y == [ EMPTY ] for x == [ EMPTY ] or y == [ EMPTY ]
*
*/
public MutableInterval mul(MutableInterval y) {
double l, h;
if (y.inf > 0) {
if (this.inf > 0) { // x > 0, y > 0
l = this.inf*y.inf;
h = this.sup*y.sup;
} else if (this.sup < 0) { // x < 0, y > 0
l = this.inf*y.sup;
h = this.sup*y.inf;
} else { // 0 in x or x is [NaN,NaN], y > 0
l = this.inf*y.sup;
h = this.sup*y.sup;
}
} else if (y.sup < 0) {
if (this.inf > 0) { // x > 0, y < 0
l = this.sup*y.inf;
h = this.inf*y.sup;
} else if (this.sup < 0) { // x < 0, y < 0
l = this.sup*y.sup;
h = this.inf*y.inf;
} else { // 0 in x or x is [NaN,NaN], y < 0
l = this.sup*y.inf;
h = this.inf*y.inf;
}
} else {
if (this.inf > 0) { // x > 0, 0 in y or y is [NaN,NaN]
l = this.sup*y.inf;
h = this.sup*y.sup;
} else if (this.sup < 0) { // x < 0, 0 in y or y is [NaN,NaN]
l = this.inf*y.sup;
h = this.inf*y.inf;
} else { // 0 in x or x is [NaN,NaN], 0 in y or y is [NaN,NaN]
l = this.sup*y.inf;
double lo = this.inf*y.sup;
if (l > lo || lo != lo)
l = lo;
h = this.inf*y.inf;
double ho = this.sup*y.sup;
if (h < ho || ho != ho)
h = ho;
}
}
if (l > 0)
l = prevPos(l);
else if (l < 0)
l = prevNeg(l);
else if (l == 0)
l = (this.inf >= 0 && y.inf >= 0 || this.sup <= 0 && y.sup <= 0) ? 0 : -Double.MIN_VALUE;
else if (this.inf == this.inf && y.inf == y.inf)
return assignEntire();
if (h > 0)
h = nextPos(h);
else if (h < 0)
h = nextNeg(h);
else if (h == 0)
h = (this.inf >= 0 && y.sup <= 0 || this.sup <= 0 && y.inf >= 0) ? 0 : Double.MIN_VALUE;
else if (this.inf == this.inf && y.inf == y.inf)
return assignEntire();
inf = l;
sup = h;
return this;
}
/**
* Divides this interval by interval y and returns the quotient.
*
* Special cases in the extended system:
*
* - x /= y == [ EMPTY ] for x == [ EMPTY ] or y == [ EMPTY ]
*
- x /= y == [ ENTIRE ] if y contains 0
*
*/
public MutableInterval div(MutableInterval y) {
double l, h;
if (y.inf > 0) {
if (this.inf > 0) { // x > 0, y > 0
l = this.inf/y.sup;
h = this.sup/y.inf;
} else if (this.sup < 0) { // x < 0, y > 0
l = this.inf/y.inf;
h = this.sup/y.sup;
} else { // 0 in x or x is [NaN,NaN], y > 0
l = this.inf/y.inf;
h = this.sup/y.inf;
}
} else if (y.sup < 0) {
if (this.inf > 0) { // x > 0, y < 0
l = this.sup/y.sup;
h = this.inf/y.inf;
} else if (this.sup < 0) { // x < 0, y < 0
l = this.sup/y.inf;
h = this.inf/y.sup;
} else { // 0 in x or x is [NaN,NaN], y < 0
l = this.sup/y.sup;
h = this.inf/y.sup;
}
} else { // 0 in y or y is [NaN,NaN]
l = h = Double.NaN;
}
if (l > 0)
l = prevPos(l);
else if (l < 0)
l = prevNeg(l);
else if (l == 0)
l = (this.inf >= 0 && y.inf > 0 || this.sup <= 0 && y.sup < 0) ? 0 : -Double.MIN_VALUE;
else if (this.inf == this.inf && y.inf == y.inf)
return assignEntire();
if (h > 0)
h = nextPos(h);
else if (h < 0)
h = nextNeg(h);
else if (h == 0)
h = (this.inf >= 0 && y.sup < 0 || this.sup <= 0 && y.inf > 0) ? 0 : Double.MIN_VALUE;
else if (this.inf == this.inf && y.inf == y.inf)
return assignEntire();
inf = l;
sup = h;
return this;
}
// -----------------------------------------------------------------------
// Elementary functions
// -----------------------------------------------------------------------
/**
* Replaces this interval by an interval enclosure of its exponential.
*/
public MutableInterval exp() {
double l = Math.exp(this.inf);
if (l > 0)
l = prevPos(l);
double h = Math.exp(this.sup);
if (h > 0)
h = nextPos(h);
else if (h == 0)
h = Double.MIN_VALUE;
inf = l;
sup = h;
return this;
}
/**
* Replaces this interval by an interval enclosure of its natural logarithm.
*/
public MutableInterval log() {
double l = Math.log(this.inf);
double h = Math.log(this.sup);
if (l > 0)
l = prevPos(l);
else if (l < 0)
l = prevNeg(l);
else if (l != l && h == h)
l = Double.NEGATIVE_INFINITY;
if (h > 0)
h = nextPos(h);
else if (h < 0)
h = nextNeg(h);
inf = l;
sup = h;
return this;
}
// -----------------------------------------------------------------------
// I/O
// -----------------------------------------------------------------------
/**
* Return string representation.
*/
public String toString() {
if (isEmpty())
return "[EMPTY ]";
StringBuffer buf = new StringBuffer(49);
buf.append('[');
append(buf, inf, false);
buf.append(',');
append(buf, sup, true);
buf.append(']');
return buf.toString();
}
private static void append(StringBuffer buf, double x, boolean isSup) {
final int d = 16; // digits after floating point
if (x == Double.NEGATIVE_INFINITY)
buf.append(" -Infinity");
else if (x == Double.POSITIVE_INFINITY)
buf.append(" Infinity");
else if (x == 0 && !isSup)
buf.append("-.0000000000000000E+000");
else if (x == 0 && isSup)
buf.append("0.0000000000000000E+000");
else {
BigDecimal bx = new BigDecimal(x);
String s = bx.unscaledValue().abs().toString();
int drop = 0;
if (s.length() != d) {
drop = s.length() - d;
bx = bx.setScale(bx.scale() - drop, isSup ? BigDecimal.ROUND_CEILING : BigDecimal.ROUND_FLOOR);
}
s = bx.unscaledValue().abs().toString();
if (s.length() > d) {
assert s.length() == d + 1 && s.charAt(s.length() - 1) == '0';
drop++;
bx = bx.setScale(bx.scale() - 1, BigDecimal.ROUND_UNNECESSARY);
s = bx.unscaledValue().abs().toString();
}
buf.append(bx.signum() < 0 ? '-' : '0');
buf.append('.');
buf.append(s);
buf.append('E');
int exp = d - bx.scale();
if (exp >= 0)
buf.append('+');
else {
buf.append('-');
exp = -exp;
}
assert (exp < 1000);
buf.append((char)('0' + exp/100));
exp %= 100;
buf.append((char)('0' + exp/10));
exp %= 10;
buf.append((char)('0' + exp));
}
}
private void parse(String s) {
s = s.trim();
if (s.length() < 2 || s.charAt(0) != '[' || s.charAt(s.length() - 1) != ']')
throw new NumberFormatException();
int comma = s.indexOf(',');
String ls = s.substring(1, comma < 0 ? s.length() - 1 : comma).trim();
BigDecimal lb = null;
if (ls.equals("NaN") || ls.equals("+NaN") || ls.equals("-NaN"))
inf = Double.NaN;
else if (ls.equals("Infinity") || ls.equals("+Infinity"))
inf = Double.POSITIVE_INFINITY;
else if (ls.equals("-Infinity"))
inf = Double.NEGATIVE_INFINITY;
else if (ls.equals("EMPTY")) {
if (comma >= 0)
throw new NumberFormatException();
assignEmpty();
return;
} else {
lb = new BigDecimal(ls);
inf = lb.doubleValue();
}
if (comma >= 0) {
String rs = s.substring(comma + 1, s.length() - 1).trim();
BigDecimal rb = null;
if (rs.equals("NaN") || rs.equals("+NaN") || rs.equals("-NaN"))
sup = Double.NaN;
else if (rs.equals("Infinity") || rs.equals("+Infinity"))
sup = Double.POSITIVE_INFINITY;
else if (rs.equals("-Infinity"))
sup = Double.NEGATIVE_INFINITY;
else {
rb = new BigDecimal(rs);
sup = rb.doubleValue();
if (inf >= sup && (inf > sup || lb.compareTo(rb) > 0)) {
assignEntire();
return;
}
sup = correct(rb, sup, true);
}
} else {
sup = correct(lb, inf, true);
}
inf = correct(lb, inf, false);
if (inf != inf || sup != sup || inf > sup) {
assignEntire();
return;
}
if (inf == Double.POSITIVE_INFINITY)
inf = Double.MAX_VALUE;
if (sup == Double.NEGATIVE_INFINITY)
sup = -Double.MAX_VALUE;
}
private static double correct(BigDecimal b, double d, boolean isSup) {
if (b == null || Double.isInfinite(d))
return d;
int diff = b.compareTo(new BigDecimal(d));
if (isSup) {
if (diff > 0)
d = next(d);
} else {
if (diff < 0)
d = prev(d);
}
return d;
}
// -----------------------------------------------------------------------
// predecessor and successor of a number
// -----------------------------------------------------------------------
/**
* Returns the size of an ulp of the argument. An ulp of a
* double
value is the positive distance between this
* floating-point value and the double
value next
* larger in magnitude. Note that for non-NaN x,
* ulp(-x) == ulp(x)
.
*
* Special Cases:
*
* - If the argument is NaN, then the result is NaN.
*
- If the argument is positive or negative infinity, then the
* result is positive infinity.
*
- If the argument is positive or negative zero, then the result is
*
Double.MIN_VALUE
.
* - If the argument is ±
Double.MAX_VALUE
, then
* the result is equal to 2971.
*
*
* @param d the floating-point value whose ulp is to be returned
* @return the size of an ulp of the argument
*/
public static double ulp(double d) {
if (d < 0)
d = -d;
if (d < Double.MAX_VALUE) {
if (d > ULP_EPS_NORMAL)
return (d + d*ULP_EPS) - d;
if (d >= MIN_NORMAL*2)
return d/SCALE_DOWN - d;
return Double.MIN_VALUE;
}
if (d == Double.MAX_VALUE)
return MAX_ULP;
return d;
}
/**
* Returns previous floating point double number.
*
* Special cases in the extended system:
*
* - prev(NaN) == NaN
*
- prev(+INF) == Double.MAX_VALUE
*
- prev(-INF) == -INF
*
- prev(0) == -Double.MIN_VALUE
*
*/
public static double prev(double x) {
if (x <= MIN_NORMAL) {
if (x < -ULP_EPS_NORMAL)
return x + x*ULP_EPS;
else if (x <= -MIN_NORMAL)
return x/SCALE_DOWN;
else if (x == 0)
return -Double.MIN_VALUE;
else
return Double.longBitsToDouble(Double.doubleToLongBits(x) + (x > 0 ? -1 : 1));
} else if (x > Double.MAX_VALUE)
return Double.MAX_VALUE;
else
return x*SCALE_DOWN;
}
/**
* Returns next floating point double number.
*
* Special cases:
*
* - next(NaN) == NaN
*
- next(+INF) == +INF
*
- next(-INF) == -Double.MAX_VALUE
*
- next(0) == Double.MIN_VALUE
*
*/
public static double next(double x) {
if (x >= -MIN_NORMAL) {
if (x > ULP_EPS_NORMAL)
return x + x*ULP_EPS;
else if (x >= MIN_NORMAL)
return x/SCALE_DOWN;
else if (x == 0)
return Double.MIN_VALUE;
else
return Double.longBitsToDouble(Double.doubleToLongBits(x) + (x > 0 ? 1 : -1));
} else if (x < -Double.MAX_VALUE)
return -Double.MAX_VALUE;
else
return x*SCALE_DOWN;
}
private static double nextPos(double x) {
assert x > 0;
return x > ULP_EPS_NORMAL ? x + x*ULP_EPS : x >= MIN_NORMAL ? x/SCALE_DOWN : Double.longBitsToDouble(Double.doubleToLongBits(x) + 1);
}
private static double nextNeg(double x) {
assert x < 0;
return x <= -MIN_NORMAL ? (x >= -Double.MAX_VALUE ? x*SCALE_DOWN : -Double.MAX_VALUE) : Double.longBitsToDouble(Double.doubleToLongBits(x) - 1);
}
private static double prevPos(double x) {
assert x > 0;
return x >= MIN_NORMAL ? (x <= Double.MAX_VALUE ? x*SCALE_DOWN : Double.MAX_VALUE) : Double.longBitsToDouble(Double.doubleToLongBits(x) - 1);
}
private static double prevNeg(double x) {
assert x < 0;
return x < -ULP_EPS_NORMAL ? x + x*ULP_EPS : x <= -MIN_NORMAL ? x/SCALE_DOWN : Double.longBitsToDouble(Double.doubleToLongBits(x) + 1);
}
public static double addUp(double x, double y) {
double z = x + y;
if (z - x < y || z - y < x) {
assert Math.abs(z) >= MIN_NORMAL*2;
return (z > 0 ? (z > ULP_EPS_NORMAL ? z + z*ULP_EPS : z/SCALE_DOWN) : z >= -Double.MAX_VALUE ? z*SCALE_DOWN : -Double.MAX_VALUE);
}
return (z == z || x != x || y != y ? z : Double.POSITIVE_INFINITY);
}
public static double addPosUp(double x, double y) {
double z = x + y;
assert z >= 0 || z != z;
if (z - x < y || z - y < x) {
assert z >= MIN_NORMAL*2;
return (z > ULP_EPS_NORMAL ? z + z*ULP_EPS : z/SCALE_DOWN);
}
return z;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy