package uk.ac.leeds.ccg.andyt.tests.java; import java.math.BigDecimal; public class TestNumber { public TestNumber() { } /** * @param args the command line arguments */ public static void main(String[] args) { double tollerateMin = 1.0d; double tollerateMax = 100.0d; double minTollerance = minTollerance( tollerateMin, tollerateMax ); double maxTollerance = maxTollerance( tollerateMin, tollerateMax ); System.out.println( "minTollerance for double" + minTollerance + " maxTollerance for double" + maxTollerance); BigDecimal tMin = new BigDecimal( tollerateMin ); BigDecimal tMax = new BigDecimal( tollerateMax ); int scale = 100; int roundingMode = BigDecimal.ROUND_DOWN; BigDecimal minT = minTollerance( tMin, tMax, scale, roundingMode ); System.out.println( "minTollerance for BigDecimal() with a scale set to " + scale + " and rounding mode " + roundingMode + " is " + minT ); System.out.println( "I have found that maxTollerance is very very very large for BigDecimal(). In fact I do not know how large, it may even approach infinity!" ); System.out.println( "Consequently BigDecimal() can be used in more instances where precise arithmetic is of key importance!" ); //BigDecimal maxT = maxTollerance(tMin, tMax, scale, roundingMode); //System.out.println( "minTollerance " + minT + " maxTollerance " + maxT ); } /** * Returns the minimum double that can be added to a double in the range [ min, max ] such that * the result is larger than any double in the range. */ public static double minTollerance(double min, double max) { double tolleranceMin = min; double dummyMin = min; double tolleranceMax = max; double dummyMax = max; boolean calculated = false; while (!calculated) { tolleranceMin /= 10.0d; tolleranceMax /= 10.0d; dummyMin = min + tolleranceMin; dummyMax = max + tolleranceMax; if ((dummyMin == min) || (dummyMax == max)) { calculated = true; } } return Math.min(tolleranceMin * 10.0d, tolleranceMax * 10); } /** * Returns the minimum double that can be added to a double in the range [ min, max ] such that * the result is larger than any double in the range. */ public static BigDecimal minTollerance(BigDecimal min, BigDecimal max, int scale, int roundingMode) { BigDecimal tolleranceMin = new BigDecimal(min.doubleValue()); BigDecimal dummyTolleranceMin = new BigDecimal(min.doubleValue()); BigDecimal dummyMin = new BigDecimal(min.doubleValue()); BigDecimal tolleranceMax = new BigDecimal(max.doubleValue()); BigDecimal dummyTolleranceMax = new BigDecimal(max.doubleValue()); BigDecimal dummyMax = new BigDecimal(max.doubleValue()); boolean calculated = false; BigDecimal factor = new BigDecimal(2.0d); while (!calculated) { tolleranceMin = tolleranceMin.divide(factor, scale, roundingMode); tolleranceMax = tolleranceMax.divide(factor, scale, roundingMode); dummyMin = min.add(tolleranceMin); dummyMax = max.add(tolleranceMax); if ((dummyMin.compareTo(min) == 0) || ((dummyMax.compareTo(max)) == 0)) { calculated = true; } else { dummyTolleranceMin = new BigDecimal( tolleranceMin.toString() ); dummyTolleranceMax = new BigDecimal( tolleranceMax.toString() ); } } if (tolleranceMin.compareTo(tolleranceMax) == -1) { return dummyTolleranceMin; } else { return dummyTolleranceMax; } } /** * Returns the maximum double that can be added to a double in the range [ min, max ] such that * it can be taken away again and the same number returned */ public static double maxTollerance(double min, double max) { double tolleranceMin = min; double dummyMin = min; double tolleranceMax = max; double dummyMax = max; boolean calculated = false; while (!calculated) { tolleranceMin *= 10.0d; tolleranceMax *= 10.0d; dummyMin += tolleranceMin; dummyMin -= tolleranceMin; dummyMax += tolleranceMax; dummyMax -= tolleranceMax; if ( ( dummyMin != min ) || ( dummyMax != max ) ) { calculated = true; } } return Math.min( tolleranceMin / 10.0d, tolleranceMax / 10.0d ); } /** * Returns the minimum double that can be added to a double in the range [ min, max ] such that * the result is larger than any double in the range. */ public static BigDecimal maxTollerance(BigDecimal min, BigDecimal max, int scale, int roundingMode) { BigDecimal tolleranceMin = new BigDecimal(min.doubleValue()); BigDecimal dummyTolleranceMin = new BigDecimal(min.doubleValue()); BigDecimal dummyMin = new BigDecimal(min.doubleValue()); BigDecimal tolleranceMax = new BigDecimal(max.doubleValue()); BigDecimal dummyTolleranceMax = new BigDecimal(max.doubleValue()); BigDecimal dummyMax = new BigDecimal(max.doubleValue()); boolean calculated = false; BigDecimal factor = new BigDecimal( 10.0d ); while (!calculated) { tolleranceMin.setScale( scale ); tolleranceMax.setScale( scale ); tolleranceMin = tolleranceMin.multiply( factor ); tolleranceMax = tolleranceMax.multiply( factor ); dummyMin = dummyMin.add( tolleranceMin ); dummyMin = dummyMin.subtract( tolleranceMin ); dummyMax = dummyMax.add( tolleranceMax ); dummyMax = dummyMax.subtract( tolleranceMax ); if ( ( ( dummyMin.compareTo( min ) != 0 ) || ( ( dummyMax.compareTo( max ) ) != 0 ) ) ) { calculated = true; } else { dummyTolleranceMin = new BigDecimal( tolleranceMin.toString() ); dummyTolleranceMax = new BigDecimal( tolleranceMax.toString() ); if ( tolleranceMin.compareTo( tolleranceMax ) == -1 ) { System.out.println( "" + dummyTolleranceMin ); } else { System.out.println( "" + dummyTolleranceMax ); } } } if ( tolleranceMin.compareTo( tolleranceMax ) == -1 ) { return dummyTolleranceMin; } else { return dummyTolleranceMax; } } }