import java.util.*; public class UtilIan { /* Hide the constructor, since this is a utility class. */ private UtilIan() { } /** Convert a char to a String. * @param c The Character to conver to a String. * @return A String of length 1, corresponding to c. */ public static String charToString( Character c ) { return c.toString(); } /** Convert an Integer into to a double. Same as casting (but w/o new syntax.) * @param i The Integer to convert to a double. * @return The double corresponding to i. */ public static double intToDouble( Integer i ) { return i.doubleValue(); } /** Convert a Double to an int. Same as casting (but w/o new syntax.) * @param d The Double to convert to an int. * @return The int corresponding to d. */ public static int doubleToInt( Double d ) { return (int)d.intValue(); } /** Round a Double to the nearest int. Same as Math.round, but returns an int. * (Does *not* round-to-even, since java.lang.Math.round doesn't.) * @param x The Double to round. * @return The int nearest x (rounded as per Math.round). */ public static int roundToInt( double x ) { return (int)Math.round(x); } /** The smallest int ≥ to x (same as Math.ceil, but returns int.) * @param d The double to find the ceiling of. * @return The smallest int ≥ x. */ public static int ceil( double x) { return (int)Math.ceil(x); } /** The largest int ≤ to x (same as Math.floor, but returns int.) * @param x The double to find the floor of. * @return The larest int ≤ x. */ public static int floor( double x ) { return (int)Math.floor(x); } /** Round a number to a certain number of decimal places. * @param x The number to round. * @param places The number of decimal places to round to. Can be negative. * @return The double corresponding to i. */ public static double roundTo( double x, int places ) { double scale = Math.pow(10,places); return Math.round(x*scale)/scale; } private static final double TOLERANCE = 0.0000001; /** Return whether two doubles are equal (approximately). * This function is symmetric. * TODO: detail what happens if d1 or d2 is zero. * @param d1 A double to compare. * @param d2 A double to compare. * @return true iff d1 is close to d2 (within a factor of {UtilIan.TOLERANCE}). */ public static boolean equalsApprox( double d1, double d2 ) { return UtilIan.equalsApprox(d1,d2,0.0000001); } public static boolean equalsApprox( double d1, double d2, double relativeTolerance ) { double tol = relativeTolerance * Math.max(Math.abs(d1), Math.abs(d2)); // TO FIX: 0.0 is never approx-equal to any non-zero value. Is this fixable? // Take exp() of both numbers? return (d1-tol <= d2 && d2 <= d1+tol) || (d2-tol <= d1 && d1 <= d2+tol); } /** Is the next character from a scanner's input (skipping whitespace)? * This method may advances the scanner over any whitespace. * @param s The scanner to read from. * @param c The char to read. * @return Whether c is the next (non-white) char at the front of s. */ public static boolean hasNextChar( Scanner s, char c ) { UtilIan.skipWhitespace(s); String target = java.util.regex.Pattern.quote(UtilIan.charToString(c)); return s.hasNext( target + ".*" ); } /** Is there a next (non-white) character to read from a scanner? * Same as hasNext(); provided for completeness. * @param s The scanner to read from. * @return Whether s has any (non-white) input to read. */ public static boolean hasNextChar( Scanner s ) { return s.hasNext(); } /** Read the given character from a scanner's input (skipping whitespace). * @param s The scanner to read from. * @param c The char to read. * @return new Character(c), or null if c is not at the front of s's input (skipping whitespace). */ public static Character nextChar( Scanner s, char c ) { UtilIan.skipWhitespace(s); String target = java.util.regex.Pattern.quote(UtilIan.charToString(c)); // Will return null if there is only whitespace. return (target==null) ? null : (s.findWithinHorizon( target, 1)).charAt(0); } /** Read the next char from a scanner's input (skipping whitespace). * @param s The scanner to read from. * @return true iff c is at the front of s's input (skipping whitespace). */ public static Character nextChar( Scanner s ) { UtilIan.skipWhitespace(s); return (s.findWithinHorizon( ".", 1)).charAt(0); } /** Skip over the whitespace in a Scanner. Not helpful unless you use methods which * ignore delimiters (such as Scanner.findWithinHorizon). * @param s The scanner to skip over whitespace. */ public static void skipWhitespace( Scanner s ) { s.skip( "(" + s.delimiter().toString() + ")*" ); } /** Return the next match (skipping initial whitespace) of a pattern. * Note: there is no corresponding 'hasNextMatch' method; this method either returns * the matched String, or null. * * @param s The scanner to read from. * @param pat The pattern to look for. * @return The String matching the given pattern; if the front of the input doesn't * match the pattern then null is returned and the scanner is does not consume any input. * (N.B. A *large* amount of input might be buffered, depending on the pattern.) */ public static String nextMatch( Scanner s, String pat ) { UtilIan.skipWhitespace(s); // This sets 'end of previous match' to front of the input. return s.findWithinHorizon( "\\G" + pat, 0 ); // \G is 'end of previous match'. } /** Return the next match (skipping initial whitespace) of a pattern. * Note: there is no corresponding 'hasNextMatch' method; this method either returns * (and consumes) the matched String, or null. * * @param s The scanner to read from. * @param pat The pattern to look for. * @return The String matching the given pattern; if the front of the input doesn't * match the pattern then null is returned and the scanner is does not consume any input. * (N.B. A *large* amount of input might be buffered, depending on the pattern.) */ public static String nextMatch( Scanner s, java.util.regex.Pattern pat ) { return UtilIan.nextMatch( s, pat.toString() ); } /** Return the maximum item in a Collection. * @param ts A collection of comparable objects. * @return the (first) largest element in ts. */ public static > T max( Collection ts ) { Iterator ti = ts.iterator(); assert ti.hasNext() : "Cannot take max of an empty collection."; T maxSoFar = ti.next(); while (ti.hasNext()) { T t = ti.next(); if (maxSoFar.compareTo(t) < 0) maxSoFar = t; } return maxSoFar; } /** Return the minimum item in a Collection. * @param ts A collection of comparable objects. * @return the (first) smallest element in ts. */ public static > T min( Collection ts ) { Iterator ti = ts.iterator(); assert ti.hasNext() : "Cannot take min of an empty collection."; T maxSoFar = ti.next(); while (ti.hasNext()) { T t = ti.next(); if (maxSoFar.compareTo(t) > 0) maxSoFar = t; } return maxSoFar; } /** A var-args version of max(Collection). * @see UtilIan.max(Collection). */ public static > T max( T... ts ) { return UtilIan.max(Arrays.asList(ts)); } /** A var-args version of min(Collection). * @see UtilIan.min(Collection). */ public static > T min( T... ts ) { return UtilIan.min(Arrays.asList(ts)); } }