/*license*\ XBN-Java: Copyright (C) 2014, Jeff Epstein (aliteralmind __DASH__ github __AT__ yahoo __DOT__ com) This software is dual-licensed under the: - Lesser General Public License (LGPL) version 3.0 or, at your option, any later version; - Apache Software License (ASL) version 2.0. Either license may be applied at your discretion. More information may be found at - http://en.wikipedia.org/wiki/Multi-licensing. The text of both licenses is available in the root directory of this project, under the names "LICENSE_lgpl-3.0.txt" and "LICENSE_asl-2.0.txt". The latest copies may be downloaded at: - LGPL 3.0: https://www.gnu.org/licenses/lgpl-3.0.txt - ASL 2.0: http://www.apache.org/licenses/LICENSE-2.0.txt \*license*/ package com.github.xbn.number; import java.util.List; import java.util.Collections; import java.util.Arrays; /** * <p>Get the median of two ints, determine a long's digit-length, retrieve * random values, and other number-related utilities.</p> * * @author Copyright (C) 2014, Jeff Epstein ({@code aliteralmind __DASH__ github __AT__ yahoo __DOT__ com}), * dual-licensed under the LGPL (version 3.0 or later) or the ASL (version * 2.0). See source code for details. * <a href="http://xbnjava.aliteralmind.com">{@code http://xbnjava.aliteralmind.com}</a>, * <a href="https://github.com/aliteralmind/xbnjava">{@code https://github.com/aliteralmind/xbnjava}</a> * @since 0.1.0 */ public class NumberUtil { /** * * <p>The infinity character: <code>'∞'</code></p> * * <p>In html: {@code "∞"} or {@code "∞"}</p> * * <p><i>With thanks to * <a href="http://stackoverflow.com/users/1093528/fge">fge</a> on * stackoverflow.</i></p> * * @see <code><a href="http://www.fileformat.info/info/unicode/char/221e/index.htm">http://www.fileformat.info/info/unicode/char/221e/index.htm</a></code></i> * @see <code><a href="http://stackoverflow.com/questions/2254913/infinity-symbol-with-html">http://stackoverflow.com/questions/2254913/infinity-symbol-with-html</a></code> */ public static final char INFINITY_CHAR = '\u221E'; /** * <p>For representing up to the number 62 with a single character. This * is an unmodifiable character list of digits (0-9), followed by * lowercase letters (a-z), uppercase letters (A-Z), and finally the * infinity character (∞).</p> * * @see #getCharForNumber0Through62(int) */ public static final List<Character> CHAR_LIST_FOR_NUMBERS_0_THROUGH_62 = Collections. unmodifiableList(Arrays.asList(new Character[]{ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', INFINITY_CHAR})); /** * <p>Get a character representing a number, using {@code CHAR_LIST_FOR_NUMBERS_0_THROUGH_62}.</p> * * @return If {@code num} is<ul> * <li>Negative: {@code '-'}</li> * <li>1 through 62: <code>{@link #CHAR_LIST_FOR_NUMBERS_0_THROUGH_62}.{@link java.util.List#get(int) get}(num)</code></li> * <li>63 or greater: {@link #INFINITY_CHAR}</li> * </ul> */ public static final char getCharForNumber0Through62(int num) { return ((num < 0) ? '-' : (num > 62 ? INFINITY_CHAR : CHAR_LIST_FOR_NUMBERS_0_THROUGH_62.get(num))); } /** * <p>Get the integer in the middle of two others.</p> * * <p>From * <br/>     {@code http://stackoverflow.com/questions/2707605/java-arraylist-middle} * <br/>(User {@code polygenelubricants}, downloaded 11/13/2013) * <br/>"Generally, if you need to find the middle of items between * index low (inclusive) and high (exclusive), it's mathematically * <br/>     {@code int mid = (low + high) / 2} * <br/>But due to arithmetic overflow in limited-precision integer, the * proper formula is * <br/>     {@code int mid = (low + high) >>> 1}"</p> * * <p>{@code low} <i>should</i> be less-than-or-equal-to {@code high}.</p> */ public static final int getMiddleInt(int low, int high) { return (low + high) >>> 1; } /** * <p>Is the int in the int-array?.</p> * * @return <code>({@link #getFoundIdx(int, int[]) getFoundIdx}(num, ints) != -1)</code> */ public static final boolean isIn(int num, int[] ints) { return (getFoundIdx(num, ints) != -1); } /** * <p>Is the int in the int-array?.</p> * * @return <code>({@link #getFoundIdx(int, int[], boolean) getFoundIdx}(num, ints, do_orderAsc) != -1)</code> */ public static final boolean isIn(int num, int[] ints, boolean do_orderAsc) { return (getFoundIdx(num, ints, do_orderAsc) != -1); } /** * <p>Get the (first) index at which a int exists in a int-array.</p> * * @return {@link #getFoundIdx(int, int[], boolean) getFoundIdx(num, ints, true)} */ public static final int getFoundIdx(int num, int[] ints) { return getFoundIdx(num, ints, true); } /** * <p>Get the (first) index at which a int exists in a int-array.</p> * * @param num The int to analyze. * @param ints The array which {@code num} should be in. May not be null, and, if {@code do_orderAsc} is true, <i>should</i> be non-empty, unique, and sorted ascending. If not, this function will not work properly. * @param do_orderAsc If true, then <code>{@link java.util.Arrays}.{@link java.util.Arrays#binarySearch(char[], char) binarySearch}(c[],c)</code> is used to search the array. If false, a for loop is used. * @return The first index in {@code ints} at which {@code num} exists. * <br/>{@code <b>-1</b>} If it doesn't. */ public static final int getFoundIdx(int num, int[] ints, boolean do_orderAsc) { if(ints == null) { throw new NullPointerException("ints"); } if(do_orderAsc) { return Arrays.binarySearch(ints, num); } for(int i = 0; i < ints.length; i++) { if(num == ints[i]) { return i; } } return -1; } /** * <p>How many digits in length is the provided number?.</p> * * <p>An alternative method for determining the number of digits is to * convert the number to a string, and then get the string's length * (although you need to anticipate the possible dash, with negative * numbers):</p> * * <pre>((new Long(num)).toString()).length()</pre> * * <p><FONT SIZE="-1"><i>The answer to "how many digits does a * number contain?" is "how many times can you divide ten into * it?...plus one".</i></FONT></p> * * @param num The number you want to know the amount of digits in. * Trailing zeros (zeros on the left side of the number) are ignored, * however, the number zero is considered a one-digit number. * @return The number of digits in num. For example:<ul> * <li><b>10:</b> Returns <b>2</b>.</li> * <li><b>-94:</b> Returns <b>2</b>.</li> * <li><b>000037:</b> Returns <b>2</b>.</li> * <li><b>0:</b> Returns <b>1</b></li> * <li><b>687482:</b> Returns <b>6</b></li> * </ul> */ public static int getDigitLength(long num) { //How many digits does this number contain? It contains at least one. int iDigits = 1; if(num < 0) { //The number is less than zero. The below divide-by-ten //will never work unless we positive-ize it. num = (num * -1); } //A temporary variable that holds the value of the divide-by-ten //answer. We don't care what the value is, as long as it's //GTOET 10. long lAnswerTEMP = num; while(lAnswerTEMP >= 10) { //There's another digit. lAnswerTEMP = lAnswerTEMP / 10; iDigits++; } return iDigits; } /** * <p>Get a string-version of a double, with a specific-decimal precision.</p> * * @param num The double. * @param decimalPlace_count The number of decimal places to return. * May not be less than one. * @param do_rightZeroPad Should zeros be padded to the right side of * the returned string (to ensure the returned number always contains * {@code decimalPlace_count} decimal places)? If true, yes. If false, * no. */ public static final String getPreciseDbl(double num, int decimalPlace_count, boolean do_rightZeroPad) { if(decimalPlace_count < 1) { throw new IllegalArgumentException("decimalPlace_count (" + decimalPlace_count + ") is less than one."); } String sDbl = (new Double(num)).toString(); int ixDec = sDbl.indexOf("."); if(ixDec == -1) { return do_rightZeroPad ? sDbl + getDuped("0", decimalPlace_count) : sDbl; } int iDecPlacesNow = sDbl.length() - ixDec - 1; String sDblChopped = null; if(decimalPlace_count > iDecPlacesNow) { //Not enough precision anyway. sDblChopped = sDbl; } else { //Too precise. Less precision necessary. sDblChopped = sDbl.substring(0, (ixDec + 1 + decimalPlace_count)); } Double DChopped = new Double(sDblChopped); String sdAfterConvert = DChopped.toString(); // double dChopped = DChopped.doubleValue(); if(!do_rightZeroPad) { return sDblChopped; } iDecPlacesNow = sdAfterConvert.length() - sdAfterConvert.indexOf(".") - 1; return sDblChopped + getDuped("0", (decimalPlace_count - iDecPlacesNow)); } private static String getDuped(String to_duplicate, int total_dups) { if(total_dups == 0) { return ""; } StringBuilder sb = new StringBuilder(); for(int i = 0; i < total_dups; i++) { sb.append(to_duplicate); } return sb.toString(); } public static final boolean isEven(int num) { return ((num % 2) == 0); } public static final boolean isOdd(int num) { return ((num % 2) == 1); } /** * <p>Get a random int.</p> * * @return {@link #getRandomIntBetweenInclusive(int, int) getRandomIntBetweenInclusive(0, max)} */ public static final int getRandomInt(int max) { return getRandomIntBetweenInclusive(0, max); } /** * @deprecated Use {@link #getRandomIntBetweenInclusive(int, int) getRandomIntBetweenInclusive}{@code (i,i)}. * @since 0.1.5 */ public static final int getRandomBetweenInclusive(int min_inclusive, int max) { return getRandomIntBetweenInclusive(min_inclusive, max); } /** * <p>Get a random int between (or equal to) two bounds.</p> * * @param min_inclusive The minimum possible int to return. <i>Should</i> * be less than {@code max}. * @param max The maximum possible int to return. * @return <code>(min_inclusive + (int)({@link java.lang.Math Math}.{@link java.lang.Math#random() random}() * ((max - min_inclusive) + 1)))</code> * @see <code><!-- GENERIC PARAMETERS FAIL IN @link --><a href="http://stackoverflow.com/questions/363681/generating-random-numbers-in-a-range-with-java">http://stackoverflow.com/questions/363681/generating-random-numbers-in-a-range-with-java</a></code> * @since 0.1.5 */ public static final int getRandomIntBetweenInclusive(int min_inclusive, int max) { return (min_inclusive + (int)(Math.random() * ((max - min_inclusive) + 1))); /* //Alternative: if(min_inclusive > max) { throw new IllegalArgumentStateException("min_inclusive (" + min_inclusive + ") must be less than or equal to max (" + max + ")."); } int i = ((new Double(Math.random() * 100000000)).intValue()); try { i = i % (max + 1 - min_inclusive); } catch(ArithmeticException ax) { throw new IllegalArgumentException("max (" + max + ") equals -1. Original exception: " + ax.toString()); } return (i + min_inclusive); */ } /** * <p>Get a random hexidecimal number as a String, using * {@code Math.random()} at its core.</p> * * * @param digit_count The number of digits the returned number should * be. May not be less than zero. * @param do_useUpperLetters If true, then all numbers above 9 * (A, B, C, D, E, F) are returned as uppercase. If false, lowercase. */ public static String getRandomHex(int digit_count, boolean do_useUpperLetters) { if(digit_count < 0) { throw new IllegalArgumentException("digit_count (currently " + digit_count + ") is less than zero."); } char[] acHEX = null; if(do_useUpperLetters) { acHEX = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; } else { acHEX = new char[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'}; } StringBuilder sb = new StringBuilder(); for(int i = 0; i < digit_count; i++) { sb.append(acHEX[getRandomIntBetweenInclusive(0, 15)]); } return sb.toString(); } /** * <p>Is the provided number evenly divisible only by itself and one?.</p> * * <p>This analyzes every odd number starting with three, the number's * square root. If <code>num</code> is evenly divisible by any, this * returns <code>false</code>.</p> * * @param num The number that may or may not be prime. * @return <code>true</code> if the <code>num</code> is prime. * @since 0.1.5 * @see <code><a href="http://www.mkyong.com/java/how-to-determine-a-prime-number-in-java">http://www.mkyong.com/java/how-to-determine-a-prime-number-in-java</a></code> */ public static final boolean isPrime(long num) { int sqrt = new Double(Math.sqrt(num)).intValue(); //System.out.println("num=" + num + ", highestOddBelowSqrt=" + highestOddBelowSqrt); for(int i = 3; i <= sqrt; i += 2) { if(num % i == 0) { return false; } } return true; } private NumberUtil() { throw new IllegalStateException("Do not instantiate"); } }