/* Copyright 2008, 2009, 2010 by the Oxford University Computing Laboratory This file is part of HermiT. HermiT is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. HermiT 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 Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with HermiT. If not, see <http://www.gnu.org/licenses/>. */ package org.semanticweb.HermiT.datatypes.floatnum; import java.util.Collection; public class FloatInterval { protected final float m_lowerBoundInclusive; protected final float m_upperBoundInclusive; public FloatInterval(float lowerBoundInclusive,float upperBoundInclusive) { assert !isIntervalEmpty(lowerBoundInclusive,upperBoundInclusive); m_lowerBoundInclusive=lowerBoundInclusive; m_upperBoundInclusive=upperBoundInclusive; } /** * Computes the intersection of this interval with the supplied one. If the two intervals do not intersect, the result is null. */ public FloatInterval intersectWith(FloatInterval that) { // This code uses the assumption no bound in either interval contains NaN. float newLowerBoundInclusive; if (isSmallerEqual(m_lowerBoundInclusive,that.m_lowerBoundInclusive)) newLowerBoundInclusive=that.m_lowerBoundInclusive; else newLowerBoundInclusive=m_lowerBoundInclusive; float newUpperBoundInclusive; if (isSmallerEqual(m_upperBoundInclusive,that.m_upperBoundInclusive)) newUpperBoundInclusive=m_upperBoundInclusive; else newUpperBoundInclusive=that.m_upperBoundInclusive; if (isIntervalEmpty(newLowerBoundInclusive,newUpperBoundInclusive)) return null; else if (isEqual(newLowerBoundInclusive,newUpperBoundInclusive)) return this; else if (that.isEqual(newLowerBoundInclusive,newUpperBoundInclusive)) return that; else return new FloatInterval(newLowerBoundInclusive,newUpperBoundInclusive); } protected boolean isEqual(float lowerBoundInclusive,float upperBoundInclusive) { return areIdentical(m_lowerBoundInclusive,lowerBoundInclusive) && areIdentical(m_upperBoundInclusive,upperBoundInclusive); } public int subtractSizeFrom(int argument) { return subtractIntervalSizeFrom(m_lowerBoundInclusive,m_upperBoundInclusive,argument); } public boolean contains(float value) { return contains(m_lowerBoundInclusive,m_upperBoundInclusive,value); } public void enumerateNumbers(Collection<Object> numbers) { // We know that the interval is not empty; hence, neither bound is NaN. float number=m_lowerBoundInclusive; while (!areIdentical(number,m_upperBoundInclusive)) { numbers.add(number); number=nextFloat(number); } numbers.add(m_upperBoundInclusive); } public String toString() { StringBuffer buffer=new StringBuffer(); buffer.append("FLOAT["); buffer.append(m_lowerBoundInclusive); buffer.append(".."); buffer.append(m_upperBoundInclusive); buffer.append(']'); return buffer.toString(); } public static boolean isNaN(int bits) { return ((bits & 0x7f800000)==0x7f800000) && ((bits & 0x003fffff)!=0); } protected static boolean isIntervalEmpty(float lowerBoundInclusive,float upperBoundInclusive) { return !isSmallerEqual(lowerBoundInclusive,upperBoundInclusive); } public static boolean areIdentical(float value1,float value2) { return Float.floatToIntBits(value1)==Float.floatToIntBits(value2); } public static float nextFloat(float value) { int bits=Float.floatToIntBits(value); int magnitude=(bits & 0x7fffffff); boolean positive=((bits & 0x80000000)==0); // The successors of NaN and +INF are these numbers themselves. if (isNaN(bits) || (magnitude==0x7f800000 && positive)) return value; else { boolean newPositive; int newMagnitude; if (positive) { newPositive=true; newMagnitude=magnitude+1; } else if (!positive && magnitude==0) { // The successor of -0 is +0 newPositive=true; newMagnitude=0; } else { // if (!positive && magnitude!=0) newPositive=false; newMagnitude=magnitude-1; } int newBits=newMagnitude | (newPositive ? 0 : 0x80000000); return Float.intBitsToFloat(newBits); } } public static float previousFloat(float value) { int bits=Float.floatToIntBits(value); int magnitude=(bits & 0x7fffffff); boolean positive=((bits & 0x80000000)==0); // The predecessors of NaN and -INF are these numbers themselves. if (isNaN(bits) || (magnitude==0x7f800000 && !positive)) return value; else { boolean newPositive; int newMagnitude; if (!positive) { newPositive=false; newMagnitude=magnitude+1; } else if (positive && magnitude==0) { // The predecessor of +0 is -0 newPositive=false; newMagnitude=0; } else { // if (positive && magnitude!=0) newPositive=true; newMagnitude=magnitude-1; } int newBits=newMagnitude | (newPositive ? 0 : 0x80000000); return Float.intBitsToFloat(newBits); } } public static int subtractIntervalSizeFrom(float lowerBoundInclusive,float upperBoundInclusive,int argument) { if (argument<=0) return 0; int bitsLowerBoundInclusive=Float.floatToIntBits(lowerBoundInclusive); int bitsUpperBoundInclusive=Float.floatToIntBits(upperBoundInclusive); if (isNaN(bitsLowerBoundInclusive) || isNaN(bitsUpperBoundInclusive)) return argument; boolean positiveLowerBoundInclusive=((bitsLowerBoundInclusive & 0x80000000)==0); boolean positiveUpperBoundInclusive=((bitsUpperBoundInclusive & 0x80000000)==0); int magnitudeLowerBoundInclusive=(bitsLowerBoundInclusive & 0x7fffffff); int magnitudeUpperBoundInclusive=(bitsUpperBoundInclusive & 0x7fffffff); // Check whether the given interval is correctly oriented. if (!isSmallerEqual(positiveLowerBoundInclusive,magnitudeLowerBoundInclusive,positiveUpperBoundInclusive,magnitudeUpperBoundInclusive)) return argument; // Now determine the number of elements. This works even if 'lowerBoundInclusive' or 'upperBoundInclusive' is +INF or -INF. if (positiveLowerBoundInclusive && positiveUpperBoundInclusive) { // It must be that magnitudeLowerBoundInclusive<magnitudeUpperBoundInclusive. int size=magnitudeUpperBoundInclusive-magnitudeLowerBoundInclusive+1; return Math.max(argument-size,0); } else if (!positiveLowerBoundInclusive && !positiveUpperBoundInclusive) { // It must be that magnitudeUpperBoundInclusive<magnitudeLowerBoundInclusive. int size=magnitudeLowerBoundInclusive-magnitudeUpperBoundInclusive+1; return Math.max(argument-size,0); } else if (!positiveLowerBoundInclusive && positiveUpperBoundInclusive) { // the number of values from 'lowerBoundInclusive' to -0 int startToMinusZero=magnitudeLowerBoundInclusive+1; if (startToMinusZero>=argument) return 0; argument=argument-startToMinusZero; // The number of values from +0 to 'upperBoundInclusive'. int plusZeroToEnd=1+magnitudeUpperBoundInclusive; if (plusZeroToEnd>=argument) return 0; return argument-plusZeroToEnd; } else // if (positiveLowerBoundInclusive && !positiveUpperBoundInclusiev) is impossible at this point throw new IllegalStateException(); } public static boolean contains(float startInclusive,float endInclusive,float value) { int bitsStart=Float.floatToIntBits(startInclusive); int bitsEnd=Float.floatToIntBits(endInclusive); int bitsValue=Float.floatToIntBits(value); if (isNaN(bitsStart) || isNaN(bitsEnd) || isNaN(bitsValue)) return false; boolean positiveStart=((bitsStart & 0x80000000)==0); boolean positiveEnd=((bitsEnd & 0x80000000)==0); boolean positiveValue=((bitsValue & 0x80000000)==0); int magnitudeStart=(bitsStart & 0x7fffffff); int magnitudeEnd=(bitsEnd & 0x7fffffff); int magnitudeValue=(bitsValue & 0x7fffffff); return isSmallerEqual(positiveStart,magnitudeStart,positiveValue,magnitudeValue) && isSmallerEqual(positiveValue,magnitudeValue,positiveEnd,magnitudeEnd); } public static boolean isSmallerEqual(float value1,float value2) { int bitsValue1=Float.floatToIntBits(value1); int bitsValue2=Float.floatToIntBits(value2); if (isNaN(bitsValue1) || isNaN(bitsValue2)) return false; boolean positiveValue1=((bitsValue1 & 0x80000000)==0); boolean positiveValue2=((bitsValue2 & 0x80000000)==0); int magnitudeValue1=(bitsValue1 & 0x7fffffff); int magnitudeValue2=(bitsValue2 & 0x7fffffff); return isSmallerEqual(positiveValue1,magnitudeValue1,positiveValue2,magnitudeValue2); } public static boolean isSmallerEqual(boolean positive1,int magnitude1,boolean positive2,int magnitude2) { if (positive1 && positive2) return magnitude1<=magnitude2; else if (!positive1 && positive2) return true; else if (positive1 && !positive2) return false; else // if (!positive1 && !positive2) return magnitude1>=magnitude2; } }