/* -*- 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 */

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 
 * <a href="http://www.mscs.mu.edu/~globsol/Papers/spec.ps">
 * Interval Arithmetic Specification</a> by Chiriaev and Walster. The 
 * implementation is following this specification.  
 * Three special intervals are supported in the extended system:
 * <UL>
 * <LI> [ EMPTY ], represented as [ NaN, NaN ]
 * <LI> [ -INF ], represented as [ -INF, -MAX ]
 * <LI> [ +INF ], represented as [ MAX, +INF] 
 * </UL>
 * 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:
	 * <UL>
	 * <LI> if x == +INF then [ +INF ] is constructed
	 * <LI> if x == -INF then [ -INF ] is constructed
	 * <LI> if x == NaN then the entire interval [ -INF,+INF ] is constructed
	 * </UL>
	 */
    public MutableInterval(double x) {
		assign(x);
	}

	/**
	 * Constructs the interval [inf, sup]. 
	 *
	 * Special cases in the extended system:
	 * <UL>
	 * <LI> if inf < sup then the entire interval [ -INF,+INF ] is constructed
	 * </UL>
	 *
	 * @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:
	 * <UL>
	 * <LI> if inf < sup then the entire interval [ -INF,+INF ] is constructed
	 * </UL>
	 *
	 * @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:
	 * <UL>
	 * <LI> if inf == sup == -INF the interval [ -INF ] is constructed
	 * <LI> if inf == sup == +INF the interval [ +INF ] is constructed
	 * <LI> if inf < sup then the entire interval [ -INF,+INF ] is constructed
	 * <LI> if inf == NaN or sup == NaN then the entire interval [ -INF,+INF ] is constructed
	 * </UL>
	 *
	 * @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:
	 * <UL>
	 * <LI> if x == +INF then [ +INF ] is constructed
	 * <LI> if x == -INF then [ -INF ] is constructed
	 * <LI> if x == NaN then the entire interval [ -INF,+INF ] is constructed
	 * </UL>
	 */
    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:
	 * <UL>
	 * <LI> if inf < sup then the entire interval [ -INF,+INF ] is constructed
	 * </UL>
	 *
	 * @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:
	 * <UL>
	 * <LI> if inf < sup then the the entire interval [ -INF,+INF ] is constructed
	 * </UL>
	 *
	 * @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:
	 * <UL>
	 * <LI> if inf == sup == -INF the interval [ -INF ] is constructed
	 * <LI> if inf == sup == +INF the interval [ +INF ] is constructed
	 * <LI> if inf < sup then the entire interval [ -INF,+INF ] is constructed
	 * <LI> if inf == NaN or sup == NaN then the entire [ -INF,+INF ] is constructed
	 * </UL>
	 *
	 * @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:
	 * <ul><li> x.inf() == NaN for x == [ EMPTY ].
	 * <li> x.inf() == MAX_DOUBLE for x == [ +INF ].</ul> 
	 */
	public double inf() {
		return inf;
	}

	/**
	 * Returns the supremum of this interval.
	 *
	 * Special cases:
	 * <ul><li> x.sup() == NaN for x == [ EMPTY ].
	 * <li> x.sup() == MAX_DOUBLE for x == [ +INF ].</ul> 
	 */
	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:
	 * <UL>
	 * <LI> x.isPoint() == false for x == [ EMPTY ] 
	 * </UL> 
	 */
	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:
	 * <UL>
	 * <LI> x.hasUlpAcc(n) == false for x == [ EMPTY ] or any infinite interval 
	 * </UL> 
	 */
	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:
	 * <UL>
	 * <LI> x.isEntire(n) == false for x == [ EMPTY ] 
	 * </UL> 
	 */
	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:
	 * <UL>
	 * <LI> x.mid() == NaN for x == [ EMPTY ] 
	 * <LI> x.mid() == 0.0 for x == [ ENTIRE ]
	 * <LI> x.mid() == +INF for x == [ +INF ] or x = [ a, +INF ]
	 * <LI> x.mid() == -INF for x == [ -INF ] or x = [ -INF, a]
	 * </UL> 
	 */
    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:
	 * <UL>
	 * <LI> x.wid() == NaN for x == [ EMPTY ] 
	 * <LI> x.wid() == +INF for any infinite interval
	 * </UL> 
	 */
    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:
	 * <UL>
	 * <LI> x.rad() == NaN for x == [ EMPTY ] 
	 * <LI> x.rad() == +INF for any infinite interval
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.mig() == NaN for x == [ EMPTY ] 
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.mag() == NaN for x == [ EMPTY ] 
	 * <LI> x.mag() == +INF for any infinite interval
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.abs() == [ EMPTY ] for x == [ EMPTY ] 
	 * <LI> x.abs() == [ +INF ] for x == [ +/- INF ]
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.min(y) == [ EMPTY ] for x == [ EMPTY ] and y == [ EMPTY ] 
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.max(y) == [ EMPTY ] for x == [ EMPTY ] and y == [ EMPTY ]
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.dist(y) == NaN for x == [ EMPTY ] or y == [ EMPTY ] 
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.intersect(y) == [ EMPTY ] iff x and y are disjoint
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.interval_hull(y) == [ EMPTY ] for x == y == [ EMPTY ]
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.interval_hull(y) == [ -INF,+INF ] for y == NaN
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.disjoint(y) == true for x or y == [ EMPTY ]
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.contains(y) == false for x == [ EMPTY ] or y == NaN
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.contains(y) == false for x == [ EMPTY ] or y == NaN
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.in_interior(y) == true for x == [ EMPTY ] 
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.proper_subset(y) == true for x == [ EMPTY ] and y != [ EMPTY ] 
	 * </UL>
	 */
	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:
	 *
	 * <UL>
	 * <LI> x.subset(y) == true for x == [ EMPTY ] 
	 * </UL>   
	 */
	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:
	 * <UL>
	 * <LI> x.proper_superset(y) == true for x != [ EMPTY ] and y == [ EMPTY ] 
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.superset(y) == true for y == [ EMPTY ] 
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.seq(y) == true for x == y == [ EMPTY ] 
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.sge(y) == true for x == y == [ EMPTY ] 
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.sgt(y) == false for x == [ EMPTY ] or y == [ EMPTY ] 
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.sle(y) == true for x == y == [ EMPTY ] 
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.slt(y) == false for x == [ EMPTY ] or y == [ EMPTY ] 
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.ceq(y) == false for x == [ EMPTY ] or y == [ EMPTY ] 
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.cne(y) == true for x == [ EMPTY ] or y == [ EMPTY ] 
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.cge(y) == false for x == [ EMPTY ] or y == [ EMPTY ]
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.cgt(y) == false for x == [ EMPTY ] or y == [ EMPTY ] 
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.cle(y) == false for x == [ EMPTY ] or y == [ EMPTY ]
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.clt(y) == false for x == [ EMPTY ] or y == [ EMPTY ] 
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.peq(y) == false for x == [ EMPTY ] or y == [ EMPTY ] 
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.pne(y) == true for x == [ EMPTY ] or y == [ EMPTY ] 
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.pge(y) == false for x == [ EMPTY ] or y == [ EMPTY ]
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.pgt(y) == false for x == [ EMPTY ] or y == [ EMPTY ] 
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.ple(y) == false for x == [ EMPTY ] or y == [ EMPTY ]
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x.plt(y) == false for x == [ EMPTY ] or y == [ EMPTY ] 
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> -x == [ EMPTY ] for x == [ EMPTY ]
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x += y == [ EMPTY ] for x == [ EMPTY ] or y == [ EMPTY ]
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x += y == [ EMPTY ] for x == [ EMPTY ] or y == NaN
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x -= y == [ EMPTY ] for x == [ EMPTY ] or y == [ EMPTY ]
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x -= y == [ EMPTY ] for x == [ EMPTY ] or y == NaN
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x *= y == [ EMPTY ] for x == [ EMPTY ] or y == [ EMPTY ]
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> x /= y == [ EMPTY ] for x == [ EMPTY ] or y == [ EMPTY ]
	 * <LI> x /= y == [ ENTIRE ] if y contains 0
	 * </UL>
	 */
	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
     * <code>double</code> value is the positive distance between this
     * floating-point value and the <code>double</code> value next
     * larger in magnitude.  Note that for non-NaN <i>x</i>,
     * <code>ulp(-<i>x</i>) == ulp(<i>x</i>)</code>.
     * 
     * <p>Special Cases:
     * <ul>
     * <li> If the argument is NaN, then the result is NaN.
     * <li> If the argument is positive or negative infinity, then the
     * result is positive infinity.
     * <li> If the argument is positive or negative zero, then the result is
     * <code>Double.MIN_VALUE</code>.
     * <li> If the argument is &plusmn;<code>Double.MAX_VALUE</code>, then
     * the result is equal to 2<sup>971</sup>.
     * </ul>
     *
     * @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:
	 * <UL>
	 * <LI> prev(NaN) == NaN
	 * <LI> prev(+INF) == Double.MAX_VALUE
	 * <LI> prev(-INF) == -INF
	 * <LI> prev(0) == -Double.MIN_VALUE
	 * </UL>
	 */
	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:
	 * <UL>
	 * <LI> next(NaN) == NaN
	 * <LI> next(+INF) == +INF
	 * <LI> next(-INF) == -Double.MAX_VALUE
	 * <LI> next(0) == Double.MIN_VALUE
	 * </UL>
	 */
	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;
	}

}
