/* * @(#) src/net/sf/ivmaidns/util/UnsignedInt.java -- * Class for unsigned integer wrappers. ** * Copyright (c) 2000 Ivan Maidanski <ivmai@mail.ru> * All rights reserved. */ /* * This 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 2, or (at your option) * any later version. ** * This software 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 (GPL) for more details. ** * Linking this library statically or dynamically with other modules is * making a combined work based on this library. Thus, the terms and * conditions of the GNU General Public License cover the whole * combination. ** * As a special exception, the copyright holders of this library give you * permission to link this library with independent modules to produce an * executable, regardless of the license terms of these independent * modules, and to copy and distribute the resulting executable under * terms of your choice, provided that you also meet, for each linked * independent module, the terms and conditions of the license of that * module. An independent module is a module which is not derived from * or based on this library. If you modify this library, you may extend * this exception to your version of the library, but you are not * obligated to do so. If you do not wish to do so, delete this * exception statement from your version. */ package net.sf.ivmaidns.util; import java.io.EOFException; import java.io.InputStream; import java.io.IOException; import java.io.OutputStream; /** * Class for unsigned integer wrappers. ** * This class wraps a primitive unsigned <CODE>int</CODE> value * (like <CODE>Integer</CODE> class). The class also contains * <CODE>static</CODE> methods for the unsigned integer arithmetic: * comparison, median, multiplication (simple and modular), * division, remainder, power, logarithm, factorial, modular * inversion, 'greatest common divisor', conversion to/from a byte * array (in the direct and reversed orders), stream bits * writing/reading, conversion to/from a string (in some given * radix, using Roman notation, or according to a given list of * mnemonics/abbreviations). ** * @see UnsignedLong * @see IntVector * @see ByteVector * @see PseudoRandom * @see JavaConsts ** * @version 2.0 * @author Ivan Maidanski */ public final class UnsignedInt extends Number implements Immutable, ReallyCloneable, Sortable { /** * The class version unique identifier for serialization * interoperability. ** * @since 1.1 */ private static final long serialVersionUID = 1932227259095163224L; /** * The Roman digits string specifier. ** * This constant string (not <CODE>null</CODE>) is used internally * by the corresponding conversion methods. Important notes: the * digits are all latin upper-case characters; the digits are * specified starting from the most significant one (the last digit * has the weight of <CODE>1</CODE>, the previous one has the weight * of <CODE>(('9' - '0') / 2 + 1)</CODE>, the digit before it has * the weight of <CODE>('9' - '0' + 1)</CODE>, and so on). ** * @see #toRomanString(int, boolean, int) * @see #parseRoman(java.lang.String, int, int) ** * @since 2.0 */ public static final String ROMAN_DIGITS = "MDCLXVI"; /** * The wrapped (encapsulated) unsigned <CODE>int</CODE> value. ** * Important notes: this value is constant. ** * @serial ** * @see UnsignedInt#UnsignedInt(int) * @see #valueOf(java.lang.String) * @see #clone() * @see #hashCode() * @see #intValue() * @see #longValue() * @see #floatValue() * @see #doubleValue() * @see #equals(java.lang.Object) * @see #greaterThan(java.lang.Object) * @see #toString() */ protected int unsignedValue; /** * Constructs a new object that represents the specified primitive * unsigned <CODE>int</CODE> value. ** * @param unsignedValue * the unsigned value to be wrapped. ** * @see #valueOf(java.lang.String) * @see #clone() * @see #intValue() * @see #longValue() * @see #equals(java.lang.Object) * @see #greaterThan(java.lang.Object) * @see #toString() */ public UnsignedInt(int unsignedValue) { this.unsignedValue = unsignedValue; } /** * Tests whether the first specified unsigned integer is greater * than the second one. ** * @param unsignedA * the first compared unsigned value. * @param unsignedB * the second compared unsigned value. * @return * <CODE>true</CODE> if and only if <VAR>unsignedA</VAR> is greater * than <VAR>unsignedB</VAR> (in the unsigned manner). ** * @see #greaterOrEqual(int, int) * @see #compare(int, int) * @see #min(int, int) * @see #max(int, int) * @see #median(int, int, int) * @see #greaterThan(java.lang.Object) */ public static final boolean greater(int unsignedA, int unsignedB) { if ((unsignedA ^ unsignedB) >= 0) unsignedA = unsignedB - unsignedA; return unsignedA < 0; } /** * Tests whether the first specified unsigned integer is greater or * equal to the second one. ** * @param unsignedA * the first compared unsigned value. * @param unsignedB * the second compared unsigned value. * @return * <CODE>true</CODE> if and only if <VAR>unsignedA</VAR> is not less * than <VAR>unsignedB</VAR> (in the unsigned manner). ** * @see #greater(int, int) * @see #compare(int, int) * @see #min(int, int) * @see #max(int, int) * @see #median(int, int, int) * @see #equals(java.lang.Object) * @see #greaterThan(java.lang.Object) */ public static final boolean greaterOrEqual(int unsignedA, int unsignedB) { if ((unsignedA ^ unsignedB) >= 0) unsignedB = unsignedA - unsignedB; return unsignedB >= 0; } /** * Compares two given unsigned integer values. ** * This method returns a signed integer indicating * 'less-equal-greater' relation between the specified * <CODE>int</CODE> values. ** * @param unsignedA * the first compared unsigned value. * @param unsignedB * the second compared unsigned value. * @return * a negative integer, zero, or a positive integer as * <VAR>valueA</VAR> is less than, equal to, or greater than * <VAR>valueB</VAR> (in the unsigned manner). ** * @see #signedCompare(int, int) * @see #greater(int, int) * @see #greaterOrEqual(int, int) * @see #min(int, int) * @see #max(int, int) * @see #median(int, int, int) * @see #equals(java.lang.Object) * @see #greaterThan(java.lang.Object) */ public static final int compare(int unsignedA, int unsignedB) { int cmp = unsignedB | 1; if ((unsignedA ^ unsignedB) >= 0) cmp = unsignedA - unsignedB; return cmp; } /** * Compares two given (signed) integer values. ** * This method returns a signed integer indicating * 'less-equal-greater' relation between the specified * <CODE>int</CODE> values. ** * @param valueA * the first compared (signed) value. * @param valueB * the second compared (signed) value. * @return * a negative integer, zero, or a positive integer as * <VAR>valueA</VAR> is less than, equal to, or greater than * <VAR>valueB</VAR>. ** * @see #compare(int, int) * @see #signedMedian(int, int, int) ** * @since 2.0 */ public static final int signedCompare(int valueA, int valueB) { int cmp = valueA | 1; if ((valueA ^ valueB) >= 0) cmp = valueA - valueB; return cmp; } /** * Returns the minimum of two given unsigned integer values. ** * @param unsignedA * the first unsigned value. * @param unsignedB * the second unsigned value. * @return * <VAR>unsignedA</VAR> if <VAR>unsignedA</VAR> is less (in the * unsigned manner) than <VAR>unsignedB</VAR>, else * <VAR>unsignedB</VAR>. ** * @see #max(int, int) * @see #median(int, int, int) * @see #greater(int, int) * @see #greaterOrEqual(int, int) * @see #compare(int, int) */ public static final int min(int unsignedA, int unsignedB) { int delta = unsignedB; if ((unsignedA ^ unsignedB) >= 0) delta = unsignedA - unsignedB; if (delta >= 0) unsignedA = unsignedB; return unsignedA; } /** * Returns the maximum of two given unsigned integer values. ** * @param unsignedA * the first unsigned value. * @param unsignedB * the second unsigned value. * @return * <VAR>unsignedA</VAR> if <VAR>unsignedA</VAR> is greater (in the * unsigned manner) than <VAR>unsignedB</VAR>, else * <VAR>unsignedB</VAR>. ** * @see #min(int, int) * @see #median(int, int, int) * @see #greater(int, int) * @see #greaterOrEqual(int, int) * @see #compare(int, int) */ public static final int max(int unsignedA, int unsignedB) { int delta = unsignedB; if ((unsignedA ^ unsignedB) >= 0) delta = unsignedA - unsignedB; if (delta >= 0) unsignedB = unsignedA; return unsignedB; } /** * Returns the 'median' (middle value) of three given unsigned * integer values. ** * @param unsignedA * the first unsigned value. * @param unsignedB * the second unsigned value. * @param unsignedC * the third unsigned value. * @return * <VAR>unsignedA</VAR>, <VAR>unsignedB</VAR> or * <VAR>unsignedC</VAR> according to which one of these values is * between (in the unsigned manner) the other values. ** * @see #signedMedian(int, int, int) * @see #min(int, int) * @see #max(int, int) * @see #greater(int, int) * @see #greaterOrEqual(int, int) * @see #compare(int, int) ** * @since 1.1 */ public static final int median(int unsignedA, int unsignedB, int unsignedC) { int delta; if (((delta = unsignedA) ^ unsignedB) >= 0) delta = unsignedB - unsignedA; if (delta >= 0) { delta = unsignedA; unsignedA = unsignedB; unsignedB = delta; } if (((delta = unsignedC) ^ unsignedA) >= 0) delta = unsignedA - unsignedC; if (delta >= 0) { if (((unsignedA = unsignedB) ^ unsignedC) >= 0) unsignedB = unsignedC - unsignedA; if (unsignedB >= 0) unsignedA = unsignedC; } return unsignedA; } /** * Returns the 'median' (middle value) of three given (signed) * integer values. ** * @param valueA * the first (signed) value. * @param valueB * the second (signed) value. * @param valueC * the third (signed) value. * @return * <VAR>valueA</VAR>, <VAR>valueB</VAR> or <VAR>valueC</VAR> * according to which one of these values is between the other * values. ** * @see #median(int, int, int) * @see #signedCompare(int, int) ** * @since 1.1 */ public static final int signedMedian(int valueA, int valueB, int valueC) { if (valueA <= valueB) { int delta = valueA; valueA = valueB; valueB = delta; } if (valueA >= valueC && (valueA = valueB) <= valueC) valueA = valueC; return valueA; } /** * Returns the highest half of 'long' (full) product of two given * unsigned integers. ** * @param unsignedA * the first unsigned value. * @param unsignedB * the second unsigned value. * @return * the (unsigned) top half of <VAR>unsignedA</VAR> multiplied by * <VAR>unsignedB</VAR>. ** * @see #divHigh(int, int, int) * @see #mulLow(int, int) * @see #mul(int, int) * @see #mulDiv(int, int, int, boolean) * @see #mulMod(int, int, int) * @see #power(int, int) * @see #factorial(int) */ public static final int mulHigh(int unsignedA, int unsignedB) { if (JavaConsts.LONG_SIZE >> 1 >= JavaConsts.INT_SIZE) return (int)(((unsignedA & JavaConsts.INT_LMASK) * (unsignedB & JavaConsts.INT_LMASK)) >>> JavaConsts.INT_SIZE); int highA = unsignedA >>> (JavaConsts.INT_SIZE >> 1); int highB = unsignedB >>> (JavaConsts.INT_SIZE >> 1); unsignedA &= ~(-1 << (JavaConsts.INT_SIZE >> 1)); unsignedB &= ~(-1 << (JavaConsts.INT_SIZE >> 1)); unsignedA = ((unsignedA * unsignedB) >>> (JavaConsts.INT_SIZE >> 1)) + unsignedA * highB; unsignedA += unsignedB *= highA; highA = highA * highB + (unsignedA >>> (JavaConsts.INT_SIZE >> 1)); if ((unsignedA ^ unsignedB) >= 0) unsignedB = unsignedA - unsignedB; if (unsignedB < 0) highA -= -1 << (JavaConsts.INT_SIZE >> 1); return highA; } /** * Returns the lowest half of 'long' (full) product of two given * unsigned integers. ** * @param unsignedA * the first unsigned value. * @param unsignedB * the second unsigned value. * @return * the (unsigned) bottom half of <VAR>unsignedA</VAR> multiplied by * <VAR>unsignedB</VAR>. ** * @see #divLow(int, int, int) * @see #remLow(int, int, int) * @see #mulHigh(int, int) * @see #mul(int, int) * @see #mulDiv(int, int, int, boolean) * @see #mulMod(int, int, int) * @see #power(int, int) * @see #factorial(int) */ public static final int mulLow(int unsignedA, int unsignedB) { return unsignedA * unsignedB; } /** * Returns the product of two given unsigned <CODE>int</CODE> values * extended to <CODE>long</CODE> type. ** * @param unsignedA * the first unsigned value. * @param unsignedB * the second unsigned value. * @return * the unsigned <CODE>long</CODE> result of <VAR>unsignedA</VAR> * multiplied by <VAR>unsignedB</VAR>. ** * @see #div(long, int) * @see #divHigh(long, int) * @see #divLow(long, int) * @see #rem(long, int) * @see #mulHigh(int, int) * @see #mulLow(int, int) * @see #mulDiv(int, int, int, boolean) * @see #mulMod(int, int, int) */ public static final long mul(int unsignedA, int unsignedB) { return (unsignedA & JavaConsts.INT_LMASK) * (unsignedB & JavaConsts.INT_LMASK); } /** * Returns the result of integer division of one given unsigned * value by another one. ** * @param unsignedA * the first unsigned value. * @param unsignedB * the second unsigned value. * @return * the unsigned result of <VAR>unsignedA</VAR> divided by * <VAR>unsignedB</VAR>. * @exception ArithmeticException * if <VAR>unsignedB</VAR> is <CODE>0</CODE>. ** * @see #mulLow(int, int) * @see #rem(int, int) * @see #div(long, int) * @see #divHigh(int, int, int) * @see #divLow(int, int, int) * @see #mulDiv(int, int, int, boolean) * @see #gcd(int, int) * @see #inverseMod(int, int) */ public static final int div(int unsignedA, int unsignedB) throws ArithmeticException { int unsignedRes = 0; if (unsignedA >= 0) { if (unsignedB >= 0) unsignedRes = unsignedA / unsignedB; } else if (unsignedB >= 0 && (unsignedA -= (unsignedRes = ((unsignedA >>> 1) / unsignedB) << 1) * unsignedB) < 0 || unsignedA >= unsignedB) unsignedRes++; return unsignedRes; } /** * Returns the result of integer division of one given unsigned * <CODE>long</CODE> value by another unsigned <CODE>int</CODE> * value. ** * @param unsignedLongA * the first unsigned value. * @param unsignedB * the second unsigned value. * @return * the unsigned result of <VAR>unsignedLongA</VAR> divided by * <VAR>unsignedB</VAR>. * @exception ArithmeticException * if <VAR>unsignedB</VAR> is <CODE>0</CODE>. ** * @see #div(int, int) * @see #mul(int, int) * @see #rem(long, int) * @see #divHigh(long, int) * @see #divLow(long, int) ** * @since 1.1 */ public static final long div(long unsignedLongA, int unsignedB) throws ArithmeticException { long unsignedLongRes, longB = unsignedB & JavaConsts.INT_LMASK; if (unsignedLongA >= 0L) unsignedLongRes = unsignedLongA / longB; else if ((unsignedLongA -= (unsignedLongRes = ((unsignedLongA >>> 1) / longB) << 1) * longB) < 0L || unsignedLongA >= longB) unsignedLongRes++; return unsignedLongRes; } /** * Returns the highest half of the result of integer division of * join of two given halves of unsigned value by another one. ** * The result is the same as of * <CODE>div(unsignedHighA, unsignedB)</CODE>. ** * @param unsignedHighA * the top half of the first unsigned value. * @param unsignedLowA * the bottom half of the first unsigned value. * @param unsignedB * the second unsigned value. * @return * the top half of the unsigned result of joined * <VAR>unsignedHighA</VAR>:<VAR>unsignedLowA</VAR> divided by * <VAR>unsignedB</VAR>. * @exception ArithmeticException * if <VAR>unsignedB</VAR> is <CODE>0</CODE>. ** * @see #divLow(int, int, int) * @see #mulHigh(int, int) * @see #mulLow(int, int) * @see #div(int, int) * @see #div(long, int) * @see #divHigh(long, int) * @see #mulDiv(int, int, int, boolean) */ public static final int divHigh(int unsignedHighA, int unsignedLowA, int unsignedB) throws ArithmeticException { return div(unsignedHighA, unsignedB); } /** * Returns the highest half of the result of integer division of one * given unsigned <CODE>long</CODE> value by another unsigned * <CODE>int</CODE> value. ** * @param unsignedLongA * the first unsigned value. * @param unsignedB * the second unsigned value. * @return * the top half of the unsigned result of <VAR>unsignedLongA</VAR> * divided by <VAR>unsignedB</VAR>. * @exception ArithmeticException * if <VAR>unsignedB</VAR> is <CODE>0</CODE>. ** * @see #divHigh(int, int, int) * @see #divLow(long, int) * @see #mul(int, int) * @see #div(long, int) * @see #rem(long, int) ** * @since 1.1 */ public static final int divHigh(long unsignedLongA, int unsignedB) throws ArithmeticException { return (int)(div(unsignedLongA, unsignedB) >>> JavaConsts.INT_SIZE); } /** * Returns the lowest half of the result of integer division of join * of two given halves of unsigned value by another one. ** * @param unsignedHighA * the top half of the first unsigned value. * @param unsignedLowA * the bottom half of the first unsigned value. * @param unsignedB * the second unsigned value. * @return * the bottom half of the unsigned result of joined * <VAR>unsignedHighA</VAR>:<VAR>unsignedLowA</VAR> divided by * <VAR>unsignedB</VAR>. * @exception ArithmeticException * if <VAR>unsignedB</VAR> is <CODE>0</CODE>. ** * @see #divHigh(int, int, int) * @see #remLow(int, int, int) * @see #mulHigh(int, int) * @see #mulLow(int, int) * @see #div(int, int) * @see #div(long, int) * @see #divLow(long, int) * @see #mulDiv(int, int, int, boolean) * @see #gcd(int, int) */ public static final int divLow(int unsignedHighA, int unsignedLowA, int unsignedB) throws ArithmeticException { if (JavaConsts.LONG_SIZE >> 1 >= JavaConsts.INT_SIZE) return (int)div(((unsignedHighA & JavaConsts.INT_LMASK) << JavaConsts.INT_SIZE) | unsignedLowA & JavaConsts.INT_LMASK, unsignedB); if ((unsignedHighA = rem(unsignedHighA, unsignedB)) == 0) return div(unsignedLowA, unsignedB); int unsignedRes; if ((unsignedB & (-1 << (JavaConsts.INT_SIZE >> 1))) == 0) { unsignedRes = div(unsignedHighA = (unsignedHighA << (JavaConsts.INT_SIZE >> 1)) | (unsignedLowA >>> (JavaConsts.INT_SIZE >> 1)), unsignedB); return (unsignedRes << (JavaConsts.INT_SIZE >> 1)) | div(((unsignedHighA - unsignedRes * unsignedB) << (JavaConsts.INT_SIZE >> 1)) | unsignedLowA & ~(-1 << (JavaConsts.INT_SIZE >> 1)), unsignedB); } if ((unsignedB & ~(-1 << (JavaConsts.INT_SIZE >> 1))) == 0) { unsignedB >>>= JavaConsts.INT_SIZE >> 1; return (div(unsignedHighA, unsignedB) << (JavaConsts.INT_SIZE >> 1)) | div((rem(unsignedHighA, unsignedB) << (JavaConsts.INT_SIZE >> 1)) | (unsignedLowA >>> (JavaConsts.INT_SIZE >> 1)), unsignedB); } unsignedRes = 0; for (int shift = JavaConsts.INT_SIZE; shift-- > 0; unsignedLowA <<= 1) { int oldHighA = unsignedHighA; unsignedHighA <<= 1; if (unsignedLowA < 0) unsignedHighA++; unsignedRes <<= 1; if (oldHighA < 0 || ((unsignedHighA ^ unsignedB) >= 0 ? unsignedHighA - unsignedB : unsignedB) >= 0) { unsignedHighA -= unsignedB; unsignedRes++; } } return unsignedRes; } /** * Returns the lowest half of the result of integer division of one * given unsigned <CODE>long</CODE> value by another unsigned * <CODE>int</CODE> value. ** * The result is the same as of * <CODE>(int)div(unsignedLongA, unsignedB)</CODE>. ** * @param unsignedLongA * the first unsigned value. * @param unsignedB * the second unsigned value. * @return * the bottom half of the unsigned result of * <VAR>unsignedLongA</VAR> divided by <VAR>unsignedB</VAR>. * @exception ArithmeticException * if <VAR>unsignedB</VAR> is <CODE>0</CODE>. ** * @see #divLow(int, int, int) * @see #divHigh(long, int) * @see #mul(int, int) * @see #div(long, int) * @see #rem(long, int) ** * @since 1.1 */ public static final int divLow(long unsignedLongA, int unsignedB) throws ArithmeticException { return (int)div(unsignedLongA, unsignedB); } /** * Returns the remainder of integer division of one given unsigned * value by another one. ** * The result is the same as of * <CODE>(unsignedA - div(unsignedA, unsignedB) * unsignedB)</CODE>. ** * @param unsignedA * the first unsigned value. * @param unsignedB * the second unsigned value. * @return * the unsigned remainder when <VAR>unsignedA</VAR> is divided by * <VAR>unsignedB</VAR>. * @exception ArithmeticException * if <VAR>unsignedB</VAR> is <CODE>0</CODE>. ** * @see #mulLow(int, int) * @see #div(int, int) * @see #rem(long, int) * @see #remLow(int, int, int) * @see #inverseMod(int, int) */ public static final int rem(int unsignedA, int unsignedB) throws ArithmeticException { if (unsignedA >= 0) { if (unsignedB >= 0) unsignedA %= unsignedB; } else if (unsignedB >= 0 && (unsignedA = (((unsignedA >>> 1) % unsignedB) << 1) | unsignedA & 1) < 0 || unsignedA >= unsignedB) unsignedA -= unsignedB; return unsignedA; } /** * Returns the remainder of integer division of one given unsigned * <CODE>long</CODE> value by another unsigned <CODE>int</CODE> * value. ** * @param unsignedLongA * the first unsigned value. * @param unsignedB * the second unsigned value. * @return * the unsigned remainder when <VAR>unsignedLongA</VAR> is divided * by <VAR>unsignedB</VAR>. * @exception ArithmeticException * if <VAR>unsignedB</VAR> is <CODE>0</CODE>. ** * @see #rem(int, int) * @see #remLow(int, int, int) * @see #mul(int, int) * @see #div(long, int) ** * @since 1.1 */ public static final int rem(long unsignedLongA, int unsignedB) throws ArithmeticException { long longB = unsignedB & JavaConsts.INT_LMASK; if ((unsignedLongA = (((unsignedLongA >>> 1) % longB) << 1) | unsignedLongA & 1L) < 0L || unsignedLongA >= longB) unsignedLongA -= longB; return (int)unsignedLongA; } /** * Returns the remainder of integer division of join of two given * halves of unsigned value by another one. ** * @param unsignedHighA * the top half of the first unsigned value. * @param unsignedLowA * the bottom half of the first unsigned value. * @param unsignedB * the second unsigned value. * @return * the unsigned remainder when joined * <VAR>unsignedHighA</VAR>:<VAR>unsignedLowA</VAR> is divided by * <VAR>unsignedB</VAR>. * @exception ArithmeticException * if <VAR>unsignedB</VAR> is <CODE>0</CODE>. ** * @see #rem(int, int) * @see #rem(long, int) * @see #divLow(int, int, int) * @see #mulHigh(int, int) * @see #mulLow(int, int) * @see #mulMod(int, int, int) */ public static final int remLow(int unsignedHighA, int unsignedLowA, int unsignedB) throws ArithmeticException { if (JavaConsts.LONG_SIZE >> 1 >= JavaConsts.INT_SIZE) return rem(((unsignedHighA & JavaConsts.INT_LMASK) << JavaConsts.INT_SIZE) | unsignedLowA & JavaConsts.INT_LMASK, unsignedB); if ((unsignedHighA = rem(unsignedHighA, unsignedB)) == 0) return rem(unsignedLowA, unsignedB); if ((unsignedB & (-1 << (JavaConsts.INT_SIZE >> 1))) == 0) return rem((rem((unsignedHighA << (JavaConsts.INT_SIZE >> 1)) | (unsignedLowA >>> (JavaConsts.INT_SIZE >> 1)), unsignedB) << (JavaConsts.INT_SIZE >> 1)) | unsignedLowA & ~(-1 << (JavaConsts.INT_SIZE >> 1)), unsignedB); if ((unsignedB & ~(-1 << (JavaConsts.INT_SIZE >> 1))) == 0) { unsignedB >>>= JavaConsts.INT_SIZE >> 1; return (rem((rem(unsignedHighA, unsignedB) << (JavaConsts.INT_SIZE >> 1)) | (unsignedLowA >>> (JavaConsts.INT_SIZE >> 1)), unsignedB) << (JavaConsts.INT_SIZE >> 1)) | unsignedLowA & ~(-1 << (JavaConsts.INT_SIZE >> 1)); } for (int shift = JavaConsts.INT_SIZE; shift-- > 0; unsignedLowA <<= 1) { int oldHighA = unsignedHighA; unsignedHighA <<= 1; if (unsignedLowA < 0) unsignedHighA++; if (oldHighA < 0 || ((unsignedHighA ^ unsignedB) >= 0 ? unsignedHighA - unsignedB : unsignedB) >= 0) unsignedHighA -= unsignedB; } return unsignedHighA; } /** * Returns a given value involved to the power of the specified * degree. ** * Overflow is not checked. If <VAR>degree</VAR> is negative then * <CODE>0</CODE> is returned. Important notes: <VAR>value</VAR> may * be signed or unsigned. ** * @param value * the signed/unsigned value to be involved to the power. * @param degree * the degree of the power. * @return * the signed/unsigned result of involving <VAR>value</VAR> to the * power of <VAR>degree</VAR>. ** * @see #mulLow(int, int) * @see #binLog(int) * @see #factorial(int) ** * @since 1.1 */ public static final int power(int value, int degree) { int res = 0; if (degree >= 0) if (((2 - value) | value) < 0) { for (res = 1; degree > 0; value *= value, degree >>= 1) if ((degree & 1) != 0) res *= value; } else if (degree == 0 || value != 0) { res = 1; if (value == 2) if (degree < JavaConsts.INT_SIZE) res <<= degree; else res = 0; } return res; } /** * Returns the integer part of binary logarithm of a given unsigned * value. ** * If <VAR>unsignedValue</VAR> is zero then <CODE>-1</CODE> is * returned, else the result is in the range from <CODE>0</CODE> to * <CODE>(JavaConsts INT_SIZE - 1)</CODE>, inclusive. ** * @param unsignedValue * the unsigned argument of the logarithm. * @return * the result of logarithm computation for <VAR>unsignedValue</VAR>. ** * @see #power(int, int) * @see #factorial(int) ** * @since 1.2 */ public static final int binLog(int unsignedValue) { int res = -1; while (unsignedValue != 0) { unsignedValue >>>= 1; res++; } return res; } /** * Computes the factorial of a given value. ** * Overflow is not checked. If <VAR>value</VAR> is negative or zero * then <CODE>0</CODE> is returned. ** * @param value * the factorial argument. * @return * the unsigned result of the factorial computation for * <VAR>value</VAR>. ** * @see #mulLow(int, int) * @see #power(int, int) * @see #binLog(int) ** * @since 1.1 */ public static final int factorial(int value) { int unsignedRes = 0; if (value > 0) for (unsignedRes = 1; value > 1; unsignedRes *= value--); return unsignedRes; } /** * Computes the greatest 'common divisor' (gcd) of two given * unsigned non-zero values. ** * Important notes: zero value (for any argument or result) is * treated as the largest unsigned <CODE>int</CODE> value plus one. ** * @param unsignedA * the first unsigned value. * @param unsignedB * the second unsigned value. * @return * the unsigned greatest common divisor of both <VAR>unsignedA</VAR> * and <VAR>unsignedB</VAR>. ** * @see #inverseMod(int, int) * @see #mulMod(int, int, int) * @see #mulDiv(int, int, int, boolean) * @see #binLog(int) ** * @since 1.1 */ public static final int gcd(int unsignedA, int unsignedB) { int shift = 0, delta; if (unsignedA == 0 || unsignedB == 0) if ((unsignedA & 1) == 0) { unsignedA = ((unsignedA - 1) >>> 1) + 1; if ((unsignedB & 1) == 0) { shift = 1; unsignedB = ((unsignedB - 1) >>> 1) + 1; } } else unsignedB = ~(-1 >>> 1); if (unsignedA != 1) while (unsignedA != unsignedB) if ((unsignedA & 1) == 0) { unsignedA >>>= 1; if ((unsignedB & 1) == 0) { shift++; unsignedB >>>= 1; } } else if ((unsignedB & 1) == 0) unsignedB >>>= 1; else if ((delta = (unsignedA >>> 1) - (unsignedB >>> 1)) > 0) unsignedA = delta; else unsignedB = -delta; return unsignedA << shift; } /** * Computes the modular 'inversion' of a given unsigned value. ** * It is the inverse operation for modular multiplication. That is, * if both <VAR>unsignedA</VAR> and <VAR>unsignedMax</VAR> are * non-zero and <CODE>gcd(unsignedA, unsignedMax + 1) == 1</CODE> * then <CODE>mulMod(result, unsignedA, unsignedMax)</CODE> is * <CODE>1</CODE>. The result of modular inversion is in the range * from <CODE>1</CODE> to <CODE>max(unsignedMax, 1)</CODE>, * inclusive. ** * @param unsignedA * the unsigned value to inverse. * @param unsignedMax * the unsigned maximum for modular multiplication. * @return * the unsigned result (not zero) of modular inversion of * <VAR>unsignedA</VAR> with respect to <VAR>unsignedMax</VAR>. ** * @see #mulMod(int, int, int) * @see #gcd(int, int) * @see #div(int, int) * @see #rem(int, int) ** * @since 1.1 */ public static final int inverseMod(int unsignedA, int unsignedMax) { int unsignedB, unsignedRes = 1; if (unsignedA < 0) { if (++unsignedMax > 0 && (unsignedA = (((unsignedA >>> 1) % unsignedMax) << 1) | unsignedA & 1) < 0 || unsignedA >= unsignedMax) unsignedA -= unsignedMax; } else if (++unsignedMax > 0) unsignedA %= unsignedMax; if (unsignedA != 0 && (unsignedB = unsignedMax - unsignedA) != unsignedA) { int unsignedQ = 0, unsignedDiv, max = unsignedMax; if (unsignedA < 0) { unsignedMax = unsignedA; unsignedRes = -1; unsignedB = unsignedMax - (unsignedA = unsignedB); unsignedQ = 1; } if ((unsignedB = unsignedMax - (unsignedDiv = (((unsignedB >>> 1) / unsignedA) << 1) + 1) * unsignedA) < 0 || unsignedB >= unsignedA) { unsignedB -= unsignedA; unsignedDiv++; } while (unsignedB > 0) { unsignedMax = unsignedA; unsignedA = unsignedB; unsignedRes = unsignedQ - (unsignedB = unsignedRes) * unsignedDiv; unsignedQ = unsignedB; unsignedB = unsignedMax - (unsignedDiv = unsignedMax / unsignedA) * unsignedA; } if (unsignedRes < 0) unsignedRes += max; } return unsignedRes; } /** * Computes the modular 'multiplication' of two given unsigned * values. ** * This method returns the remainder of the result of integer * division of 'long' (full) product of <VAR>unsignedA</VAR> and * <VAR>unsignedB</VAR> by (<VAR>unsignedMax</VAR> plus one). The * result is in the range from <CODE>0</CODE> to * <VAR>unsignedMax</VAR>, inclusive. ** * @param unsignedA * the first unsigned value to multiply. * @param unsignedB * the second unsigned value to multiply. * @param unsignedMax * the unsigned maximum value for the result to have. * @return * the unsigned result of modular multiplication of * <VAR>unsignedA</VAR> and <VAR>unsignedB</VAR> with respect to * <VAR>unsignedMax</VAR>. ** * @see #inverseMod(int, int) * @see #gcd(int, int) * @see #mulDiv(int, int, int, boolean) * @see #mulHigh(int, int) * @see #remLow(int, int, int) ** * @since 1.1 */ public static final int mulMod(int unsignedA, int unsignedB, int unsignedMax) { int unsignedRes = 0; if (unsignedA != 0 && unsignedB != 0) { unsignedRes = unsignedA * unsignedB; if (++unsignedMax != 0) unsignedRes = remLow(mulHigh(unsignedA, unsignedB), unsignedRes, unsignedMax); } return unsignedRes; } /** * Returns the lowest half of the result of integer division of * 'long' (full) product of the first two given unsigned non-zero * values by the third given unsigned non-zero value. ** * Important notes: zero value (for any argument) is treated as * the largest unsigned <CODE>int</CODE> value plus one. ** * @param unsignedA * the first unsigned value. * @param unsignedB * the second unsigned value. * @param unsignedC * the unsigned divisor value. * @param roundUp * <CODE>true</CODE> if the result of division is rounded upwards * (to the nearest greater integer value), else it is rounded * towards zero. * @return * the bottom half of the unsigned result of <VAR>unsignedA</VAR> * multiplied by <VAR>unsignedB</VAR> and divided by * <VAR>unsignedC</VAR>. ** * @see #mul(int, int) * @see #mulHigh(int, int) * @see #mulLow(int, int) * @see #divLow(long, int) * @see #divLow(int, int, int) * @see #gcd(int, int) * @see #mulMod(int, int, int) * @see #inverseMod(int, int) */ public static final int mulDiv(int unsignedA, int unsignedB, int unsignedC, boolean roundUp) { int unsignedHigh; if (unsignedA == 0 || unsignedA == unsignedC) { unsignedHigh = unsignedB; unsignedB = unsignedA; unsignedA = unsignedHigh; } if (unsignedB != unsignedC) { if (unsignedB != 0) { unsignedHigh = mulHigh(unsignedA, unsignedB); unsignedB *= unsignedA; unsignedA = unsignedHigh; } if (roundUp) { if (unsignedB == 0) unsignedA--; unsignedB--; } else if ((unsignedA | unsignedB) == 0) { unsignedA = -1; unsignedB = -unsignedC; roundUp = true; } if (unsignedC != 0) unsignedA = divLow(unsignedA, unsignedB, unsignedC); if (roundUp) unsignedA++; } return unsignedA; } /** * Puts a given value into the specified byte array. ** * This method splits <VAR>unsignedValue</VAR> to separate bytes and * puts them into <VAR>bytes</VAR> array sequentially (the last put * byte is the lowest of <VAR>unsignedValue</VAR>), starting at * <VAR>offset</VAR>. Negative <VAR>len</VAR> is treated as zero. If * an exception is thrown then <VAR>bytes</VAR> remains changed. * Else <VAR>bytes</VAR> content is altered. Important notes: if * <VAR>len</VAR> is greater than <CODE>JavaConsts INT_LENGTH</CODE> * then <VAR>unsignedValue</VAR> is zero-extended. ** * @param bytes * the byte array (must be non-<CODE>null</CODE>) to put to. * @param offset * the first array index (must be in the range) to put at. * @param unsignedValue * the value, containing the bytes (in its lowest part) to be put. * @param len * the amount of bytes to put. * @exception NullPointerException * if <VAR>bytes</VAR> is <CODE>null</CODE>. * @exception ArrayIndexOutOfBoundsException * if <VAR>len</VAR> is positive and (<VAR>offset</VAR> is negative * or is greater than <CODE>length</CODE> of <VAR>bytes</VAR> minus * <VAR>len</VAR>). ** * @see #toByteArray(int, int) * @see #getFromByteArray(byte[], int, int) * @see #putToIntelArray(byte[], int, int, int) * @see #writeBits(java.io.OutputStream, int, int) ** * @since 1.1 */ public static final void putToByteArray(byte[] bytes, int offset, int unsignedValue, int len) throws NullPointerException, ArrayIndexOutOfBoundsException { if (len > 0) { byte temp; for (temp = bytes[offset + len - 1]; len > JavaConsts.INT_LENGTH; bytes[offset++] = 0, len--); len *= JavaConsts.BYTE_SIZE; while ((len -= JavaConsts.BYTE_SIZE) >= 0) bytes[offset++] = (byte)(unsignedValue >>> len); } len = bytes.length; } /** * Converts a given value into a byte array. ** * This method splits <VAR>unsignedValue</VAR> to separate bytes and * sequentially puts them into a newly created byte array (the last * put byte is the lowest of <VAR>unsignedValue</VAR>) of * <VAR>len</VAR> length. Negative <VAR>len</VAR> is treated as * zero. Important notes: if <VAR>len</VAR> is greater than * <CODE>JavaConsts INT_LENGTH</CODE> then <VAR>unsignedValue</VAR> * is zero-extended. ** * @param unsignedValue * the value, containing the bytes (in its lowest part) to be put. * @param len * the amount of bytes to put (<CODE>length</CODE> of the array to * create). * @return * a newly created byte array (not <CODE>null</CODE>, with * <CODE>length</CODE> the same as non-negative <VAR>len</VAR>), * containing the bytes of <VAR>unsignedValue</VAR>. * @exception OutOfMemoryError * if there is not enough memory. ** * @see #putToByteArray(byte[], int, int, int) * @see #getFromByteArray(byte[], int, int) * @see #toIntelArray(int, int) * @see #writeBits(java.io.OutputStream, int, int) ** * @since 1.1 */ public static final byte[] toByteArray(int unsignedValue, int len) { if (len <= 0) len = 0; byte[] bytes = new byte[len]; putToByteArray(bytes, 0, unsignedValue, len); return bytes; } /** * Converts the specified region of a given byte array into an * unsigned value. ** * This method gets the elements of <VAR>bytes</VAR> array * sequentially starting at <VAR>offset</VAR> and joins them into an * unsigned value (the last got byte is the lowest of the result). * Negative <VAR>len</VAR> is treated as zero. <VAR>bytes</VAR> * content is not modified. ** * @param bytes * the byte array (must be non-<CODE>null</CODE>) to get from. * @param offset * the first array index (must be in the range) to get at. * @param len * the amount of bytes to get. * @return * an unsigned value, containing the got bytes (in its lowest part). * @exception NullPointerException * if <VAR>bytes</VAR> is <CODE>null</CODE>. * @exception ArrayIndexOutOfBoundsException * if <VAR>len</VAR> is positive and (<VAR>offset</VAR> is negative * or is greater than <CODE>length</CODE> of <VAR>bytes</VAR> minus * <VAR>len</VAR>). ** * @see #putToByteArray(byte[], int, int, int) * @see #toByteArray(int, int) * @see #getFromIntelArray(byte[], int, int) * @see #readBits(java.io.InputStream, int) ** * @since 1.1 */ public static final int getFromByteArray(byte[] bytes, int offset, int len) throws NullPointerException, ArrayIndexOutOfBoundsException { int unsignedValue = 0; if (len > 0) do { unsignedValue = (unsignedValue << JavaConsts.BYTE_SIZE) | bytes[offset++] & JavaConsts.BYTE_MASK; } while (--len > 0); len = bytes.length; return unsignedValue; } /** * Puts a given value into the specified byte array in the reversed * order. ** * This method splits <VAR>unsignedValue</VAR> to separate bytes and * puts them into <VAR>bytes</VAR> array sequentially but in the * reversed ('Intel') order (the first put byte is the lowest of * <VAR>unsignedValue</VAR>), starting at <VAR>offset</VAR> (and * moving forward). Negative <VAR>len</VAR> is treated as zero. If * an exception is thrown then <VAR>bytes</VAR> remains changed. * Else <VAR>bytes</VAR> content is altered. Important notes: if * <VAR>len</VAR> is greater than <CODE>JavaConsts INT_LENGTH</CODE> * then <VAR>unsignedValue</VAR> is zero-extended. ** * @param bytes * the byte array (must be non-<CODE>null</CODE>) to put to. * @param offset * the first array index (must be in the range) to put at. * @param unsignedValue * the value, containing the bytes (in its lowest part) to be put. * @param len * the amount of bytes to put. * @exception NullPointerException * if <VAR>bytes</VAR> is <CODE>null</CODE>. * @exception ArrayIndexOutOfBoundsException * if <VAR>len</VAR> is positive and (<VAR>offset</VAR> is negative * or is greater than <CODE>length</CODE> of <VAR>bytes</VAR> minus * <VAR>len</VAR>). ** * @see #toIntelArray(int, int) * @see #getFromIntelArray(byte[], int, int) * @see #putToByteArray(byte[], int, int, int) ** * @since 2.0 */ public static final void putToIntelArray(byte[] bytes, int offset, int unsignedValue, int len) throws NullPointerException, ArrayIndexOutOfBoundsException { if (len > 0) { byte temp; temp = bytes[offset + len - 1]; do { bytes[offset++] = (byte)unsignedValue; if (--len <= 0) break; unsignedValue >>>= JavaConsts.BYTE_SIZE; } while (true); } len = bytes.length; } /** * Converts a given value in the reversed order into a byte array. ** * This method splits <VAR>unsignedValue</VAR> to separate bytes and * sequentially puts them into a newly created byte array but in the * reversed ('Intel') order (the first put byte is the lowest of * <VAR>unsignedValue</VAR>) of <VAR>len</VAR> length. Negative * <VAR>len</VAR> is treated as zero. Important notes: if * <VAR>len</VAR> is greater than <CODE>JavaConsts INT_LENGTH</CODE> * then <VAR>unsignedValue</VAR> is zero-extended. ** * @param unsignedValue * the value, containing the bytes (in its lowest part) to be put. * @param len * the amount of bytes to put (<CODE>length</CODE> of the array to * create). * @return * a newly created byte array (not <CODE>null</CODE>, with * <CODE>length</CODE> the same as non-negative <VAR>len</VAR>), * containing the bytes of <VAR>unsignedValue</VAR>. * @exception OutOfMemoryError * if there is not enough memory. ** * @see #putToIntelArray(byte[], int, int, int) * @see #getFromIntelArray(byte[], int, int) * @see #toByteArray(int, int) ** * @since 2.0 */ public static final byte[] toIntelArray(int unsignedValue, int len) { if (len <= 0) len = 0; byte[] bytes = new byte[len]; putToIntelArray(bytes, 0, unsignedValue, len); return bytes; } /** * Converts the specified region of a given byte array into an * unsigned value in the reversed order. ** * This method gets the elements of <VAR>bytes</VAR> array * sequentially but in the reversed ('Intel') order, starting at * <VAR>offset</VAR> (and moving forward) and joins them into an * unsigned value (the first got byte is the lowest of the result). * Negative <VAR>len</VAR> is treated as zero. <VAR>bytes</VAR> * content is not modified. ** * @param bytes * the byte array (must be non-<CODE>null</CODE>) to get from. * @param offset * the first array index (must be in the range) to get at. * @param len * the amount of bytes to get. * @return * an unsigned value, containing the got bytes (in its lowest part). * @exception NullPointerException * if <VAR>bytes</VAR> is <CODE>null</CODE>. * @exception ArrayIndexOutOfBoundsException * if <VAR>len</VAR> is positive and (<VAR>offset</VAR> is negative * or is greater than <CODE>length</CODE> of <VAR>bytes</VAR> minus * <VAR>len</VAR>). ** * @see #putToIntelArray(byte[], int, int, int) * @see #toIntelArray(int, int) * @see #getFromByteArray(byte[], int, int) ** * @since 2.0 */ public static final int getFromIntelArray(byte[] bytes, int offset, int len) throws NullPointerException, ArrayIndexOutOfBoundsException { int unsignedValue = 0; if (len > 0) { byte temp; temp = bytes[offset + len - 1]; if (len >= JavaConsts.INT_LENGTH) len = JavaConsts.INT_LENGTH; int shift = 0; do { unsignedValue |= (bytes[offset++] & JavaConsts.BYTE_MASK) << shift; if (--len <= 0) break; shift += JavaConsts.BYTE_SIZE; } while (true); } len = bytes.length; return unsignedValue; } /** * Writes a group of bits to a given output stream. ** * Negative <VAR>count</VAR> is treated as zero. Important notes: if * <VAR>count</VAR> is greater than <CODE>JavaConsts INT_SIZE</CODE> * then the specified value (containing the bits to write) is * zero-extended; <VAR>out</VAR> is a byte-oriented stream, so given * bits are padded with zeros (on the most significant side); the * bits are written starting from the most significant one. ** * @param out * the stream (must be non-<CODE>null</CODE>) to write to. * @param unsignedValue * the unsigned value, containing bits (in its lowest part) to be * written. * @param count * the amount of bits to be written. * @exception NullPointerException * if <VAR>out</VAR> is <CODE>null</CODE>. * @exception IOException * if an I/O error occurs. ** * @see #readBits(java.io.InputStream, int) * @see #readByte(java.io.InputStream) ** * @since 1.1 */ public static final void writeBits(OutputStream out, int unsignedValue, int count) throws NullPointerException, IOException { out.equals(out); if (count > 0) { int shift; if ((shift = count % JavaConsts.BYTE_SIZE) > 0) out.write((count -= shift) >= JavaConsts.INT_SIZE ? 0 : (unsignedValue >>> count) & ~(-1 << shift)); while (count > JavaConsts.INT_SIZE) { out.write(0); count -= JavaConsts.BYTE_SIZE; } while ((count -= JavaConsts.BYTE_SIZE) >= 0) out.write(unsignedValue >>> count); } } /** * Reads a group of bits from a given input stream. ** * Negative <VAR>count</VAR> is treated as zero. If the * end-of-stream is detected then <CODE>EOFException</CODE> * (subclass of <CODE>IOException</CODE>) is thrown. Important * notes: if <VAR>count</VAR> is greater than * <CODE>JavaConsts INT_SIZE</CODE> then the result contains only * tail (the least significant) read bits portion fit the result; * <VAR>in</VAR> is a byte-oriented stream, so padding bits are read * but set to zero (on the most significant side); the bits are read * starting from the most significant one. ** * @param in * the stream (must be non-<CODE>null</CODE>) to read from. * @param count * the amount of bits to be read. * @return * an unsigned value, containing read bits (in its lowest part, the * highest part of the result is set to zero if <VAR>count</VAR> is * less than <CODE>JavaConsts INT_SIZE</CODE>). * @exception NullPointerException * if <VAR>in</VAR> is <CODE>null</CODE>. * @exception IOException * if the end-of-stream has been reached or an I/O error occurs. ** * @see #writeBits(java.io.OutputStream, int, int) * @see #readByte(java.io.InputStream) ** * @since 1.1 */ public static final int readBits(InputStream in, int count) throws NullPointerException, IOException { in.equals(in); int unsignedValue = 0, shift; if (count > 0) { if ((shift = count % JavaConsts.BYTE_SIZE) > 0) { if ((unsignedValue = in.read()) < 0) throw new EOFException(); unsignedValue &= ~(-1 << shift); count -= shift; } while ((count -= JavaConsts.BYTE_SIZE) >= 0) if ((shift = in.read()) >= 0) unsignedValue = shift & JavaConsts.BYTE_MASK | (unsignedValue << JavaConsts.BYTE_SIZE); else throw new EOFException(); } return unsignedValue; } /** * Reads one input <CODE>byte</CODE> as an unsigned value. ** * If the end-of-stream is detected then <CODE>EOFException</CODE> * (subclass of <CODE>IOException</CODE>) is thrown. ** * @param in * the stream (must be non-<CODE>null</CODE>) to read from. * @return * an unsigned value read from the stream in the range from * <CODE>0</CODE> to <CODE>JavaConsts BYTE_MASK</CODE>, inclusive. * @exception NullPointerException * if <VAR>in</VAR> is <CODE>null</CODE>. * @exception IOException * if the end-of-stream has been reached or an I/O error occurs. ** * @see #writeBits(java.io.OutputStream, int, int) * @see #readBits(java.io.InputStream, int) */ public static final int readByte(InputStream in) throws NullPointerException, IOException { int unsignedByte; if ((unsignedByte = in.read()) < 0) throw new EOFException(); return unsignedByte & JavaConsts.BYTE_MASK; } /** * Converts a given signed/unsigned value into its string * representation in the specified radix. ** * <VAR>value</VAR> is unsigned only if <VAR>isUnsigned</VAR> and * not <VAR>forceSign</VAR>. If <VAR>forceSign</VAR> then result * always has a sign (if <VAR>isUnsigned</VAR> then the positive * sign is space else '+' character) else result has a sign ('-' * character) if <VAR>value</VAR> is negative. The result is * left-padded with spaces (before the sign prefix) if * <VAR>minLength</VAR> is negative else with '0' characters (after * the sign prefix). The absolute value of <VAR>minLength</VAR> * specifies the minimal length of the result (anyhow, the result * contains at least one digit). The full digits character set is * '0' through '9', 'A' through 'Z' and 'a' through 'z'. If the * specified radix is invalid (less than two or too big) then it is * corrected to the nearest valid one. ** * @param value * the signed/unsigned value to be converted. * @param isUnsigned * <CODE>true</CODE> if <VAR>value</VAR> must be treated as an * unsigned value (but only if not <VAR>forceSign</VAR>), else * <VAR>value</VAR> is signed. * @param forceSign * <CODE>true</CODE> if and only if the result must always have a * sign (positive or negative). * @param radix * the radix (any value) to be used as a base of the value string * format. * @param upperCase * <CODE>true</CODE> if and only if (digit) characters in the result * are in the upper case. * @param minLength * the minimal length of the result (absolute value) and pad prefix * specifier (if negative then space padding else zero padding). * @return * the string representation (not <CODE>null</CODE>, with * <CODE>length()</CODE> not less than * <CODE>max(abs(minLength), 1)</CODE>) of <VAR>value</VAR> in the * specified radix. * @exception OutOfMemoryError * if there is not enough memory. ** * @see #toBinaryString(int, int) * @see #toOctalString(int, int) * @see #toString(int, boolean) * @see #toHexString(int, boolean, int) * @see #toRomanString(int, boolean, int) * @see #toAbbreviation(int, java.lang.String) * @see #filledString(char, int) * @see #parse(java.lang.String, int, int, boolean, int) * @see #decode(java.lang.String, int, int) */ public static final String toString(int value, boolean isUnsigned, boolean forceSign, int radix, boolean upperCase, int minLength) { char[] chars; int offset, zeroPrefix; if (radix <= 2) radix = 2; if (radix >= ('9' - '0' + 1) + ('Z' - 'A' + 1)) radix = ('9' - '0' + 1) + ('Z' - 'A' + 1); if ((zeroPrefix = minLength) < 0 && (minLength = -minLength) < 0) minLength--; if ((offset = (JavaConsts.INT_SIZE + 1) - minLength) > 0) minLength = JavaConsts.INT_SIZE + 1; else offset = 0; chars = new char[minLength]; if (forceSign || !isUnsigned) if (value < 0) { isUnsigned = forceSign = false; value = -value; } else if (!forceSign) isUnsigned = true; int digit = value; if ((digit -= (value = ((value >>> 1) / radix) << 1) * radix) >= radix) { digit -= radix; value++; } do { if (digit > '9' - '0') { digit += 'a' - '9' - 1; if (upperCase) digit -= 'a' - 'A'; } chars[--minLength] = (char)(digit + '0'); if ((digit = value) <= 0) break; digit -= (value /= radix) * radix; } while (true); if (zeroPrefix > 0) { if ((forceSign || !isUnsigned) && offset + 1 > 0) offset++; while (offset < minLength) chars[--minLength] = '0'; } if (!isUnsigned) chars[--minLength] = (char)(forceSign ? '+' : '-'); else if (forceSign) chars[--minLength] = ' '; while (offset < minLength) chars[--minLength] = ' '; return new String(chars, minLength, chars.length - minLength); } /** * Converts a given signed/unsigned value into its decimal string * representation. ** * @param value * the signed/unsigned value to be converted. * @param isUnsigned * <CODE>true</CODE> if <VAR>value</VAR> must be treated as an * unsigned value, else <VAR>value</VAR> is signed. * @return * the string representation (not <CODE>null</CODE>, with non-zero * <CODE>length()</CODE>) of <VAR>value</VAR> in the decimal radix. * @exception OutOfMemoryError * if there is not enough memory. ** * @see #toString(int, boolean, boolean, int, boolean, int) * @see #toBinaryString(int, int) * @see #toOctalString(int, int) * @see #toHexString(int, boolean, int) * @see #toRomanString(int, boolean, int) * @see #toAbbreviation(int, java.lang.String) * @see #filledString(char, int) * @see #parse(java.lang.String, int, int, boolean, int) * @see #decode(java.lang.String, int, int) */ public static final String toString(int value, boolean isUnsigned) { int minLength; char[] chars = new char[minLength = (JavaConsts.INT_SIZE - 1) / 3 + 2]; if (!isUnsigned) if (value < 0) value = -value; else isUnsigned = true; int digit = value; if ((digit -= (value = ((value >>> 1) / ('9' - '0' + 1)) << 1) * ('9' - '0' + 1)) > '9' - '0') { digit -= '9' - '0' + 1; value++; } do { chars[--minLength] = (char)(digit + '0'); if ((digit = value) <= 0) break; digit -= (value /= '9' - '0' + 1) * ('9' - '0' + 1); } while (true); if (!isUnsigned) chars[--minLength] = '-'; return new String(chars, minLength, chars.length - minLength); } /** * Converts a given unsigned value into its binary string * representation. ** * The result is left-padded with spaces if <VAR>minLength</VAR> is * negative else with '0' characters. The absolute value of * <VAR>minLength</VAR> specifies the minimal length of the result * (anyhow, the result contains at least one digit). ** * @param unsignedValue * the unsigned value to be converted. * @param minLength * the minimal length of the result (absolute value) and pad prefix * specifier (if negative then space padding else zero padding). * @return * the string representation (not <CODE>null</CODE>, with * <CODE>length()</CODE> not less than * <CODE>max(abs(minLength), 1)</CODE>) of <VAR>unsignedValue</VAR> * in the binary radix. * @exception OutOfMemoryError * if there is not enough memory. ** * @see #toString(int, boolean, boolean, int, boolean, int) * @see #toOctalString(int, int) * @see #toString(int, boolean) * @see #toHexString(int, boolean, int) * @see #parse(java.lang.String, int, int, boolean, int) */ public static final String toBinaryString(int unsignedValue, int minLength) { char[] chars; int offset; char prefix = '0'; if (minLength < 0) if ((minLength = -minLength) < 0) minLength--; else prefix = ' '; if ((offset = JavaConsts.INT_SIZE - minLength) > 0) minLength = JavaConsts.INT_SIZE; else offset = 0; chars = new char[minLength]; do { chars[--minLength] = (char)((unsignedValue & 1) + '0'); } while ((unsignedValue >>>= 1) != 0); while (offset < minLength) chars[--minLength] = prefix; return new String(chars, minLength, chars.length - minLength); } /** * Converts a given unsigned value into its octal string * representation. ** * The result is left-padded with spaces if <VAR>minLength</VAR> is * negative else with '0' characters. The absolute value of * <VAR>minLength</VAR> specifies the minimal length of the result * (anyhow, the result contains at least one digit). ** * @param unsignedValue * the unsigned value to be converted. * @param minLength * the minimal length of the result (absolute value) and pad prefix * specifier (if negative then space padding else zero padding). * @return * the string representation (not <CODE>null</CODE>, with * <CODE>length()</CODE> not less than * <CODE>max(abs(minLength), 1)</CODE>) of <VAR>unsignedValue</VAR> * in the octal radix. * @exception OutOfMemoryError * if there is not enough memory. ** * @see #toString(int, boolean, boolean, int, boolean, int) * @see #toBinaryString(int, int) * @see #toString(int, boolean) * @see #toHexString(int, boolean, int) * @see #parse(java.lang.String, int, int, boolean, int) * @see #decode(java.lang.String, int, int) */ public static final String toOctalString(int unsignedValue, int minLength) { char[] chars; int offset; char prefix = '0'; if (minLength < 0) if ((minLength = -minLength) < 0) minLength--; else prefix = ' '; if ((offset = ((JavaConsts.INT_SIZE - 1) / 3 + 1) - minLength) > 0) minLength = (JavaConsts.INT_SIZE - 1) / 3 + 1; else offset = 0; chars = new char[minLength]; do { chars[--minLength] = (char)((unsignedValue & ((1 << 3) - 1)) + '0'); } while ((unsignedValue >>>= 3) != 0); while (offset < minLength) chars[--minLength] = prefix; return new String(chars, minLength, chars.length - minLength); } /** * Converts a given unsigned value into its hexadecimal string * representation. ** * The result is left-padded with spaces if <VAR>minLength</VAR> is * negative else with '0' characters. The absolute value of * <VAR>minLength</VAR> specifies the minimal length of the result * (anyhow, the result contains at least one digit). ** * @param unsignedValue * the unsigned value to be converted. * @param upperCase * <CODE>true</CODE> if and only if (digit) characters in the result * are in the upper case. * @param minLength * the minimal length of the result (absolute value) and pad prefix * specifier (if negative then space padding else zero padding). * @return * the string representation (not <CODE>null</CODE>, with * <CODE>length()</CODE> not less than * <CODE>max(abs(minLength), 1)</CODE>) of <VAR>unsignedValue</VAR> * in the hexadecimal radix. * @exception OutOfMemoryError * if there is not enough memory. ** * @see #toString(int, boolean, boolean, int, boolean, int) * @see #toBinaryString(int, int) * @see #toOctalString(int, int) * @see #toString(int, boolean) * @see #parse(java.lang.String, int, int, boolean, int) * @see #decode(java.lang.String, int, int) */ public static final String toHexString(int unsignedValue, boolean upperCase, int minLength) { char[] chars; int digit, offset; char prefix = '0'; if (minLength < 0) if ((minLength = -minLength) < 0) minLength--; else prefix = ' '; if ((offset = (((JavaConsts.INT_SIZE - 1) >> 2) + 1) - minLength) > 0) minLength = ((JavaConsts.INT_SIZE - 1) >> 2) + 1; else offset = 0; chars = new char[minLength]; do { if ((digit = unsignedValue & ((1 << 4) - 1)) > '9' - '0') { digit += 'a' - '9' - 1; if (upperCase) digit -= 'a' - 'A'; } chars[--minLength] = (char)(digit + '0'); } while ((unsignedValue >>>= 4) != 0); while (offset < minLength) chars[--minLength] = prefix; return new String(chars, minLength, chars.length - minLength); } /** * Parses a given string region as a signed/unsigned integer in the * specified radix. ** * Leading spaces (before the sign prefix) are ignored. Sign prefix * ('+' or '-') is permitted only if not <VAR>isUnsigned</VAR>. Any * leading '0' characters (after the sign prefix or leading spaces) * are ignored too. The next characters in the string region must * all be digits of the specified radix (the full digits character * set is '0' through '9', 'A' through 'Z' and 'a' through 'z'). * Number overflow is checked properly (<CODE>ParserException</CODE> * is thrown if overflow occurs). If the specified radix is invalid * (less than two or too big) then it is corrected to the nearest * valid one. Important notes: use <CODE>('9' - '0' + 1)</CODE> to * parse a decimal number. ** * @param str * the string (must be non-<CODE>null</CODE>), which region to * parse. * @param beginIndex * the string region beginning index (must be in the range), * inclusive. * @param endIndex * the string region ending index (must be in the range), exclusive. * @param isUnsigned * <CODE>true</CODE> if and only if the result must be an unsigned * value. * @param radix * the radix (any value) to be used as a base of the value string * format. * @return * a signed/unsigned integer value represented by <VAR>str</VAR> * region. * @exception NullPointerException * if <VAR>str</VAR> is <CODE>null</CODE>. * @exception StringIndexOutOfBoundsException * if <VAR>beginIndex</VAR> is negative, or if <VAR>endIndex</VAR> * is less than <VAR>beginIndex</VAR> or is greater than * <CODE>length()</CODE> of <VAR>str</VAR>. * @exception ParserException * if <VAR>str</VAR> region cannot be parsed as a signed/unsigned * integer (<VAR>error</VAR> is set to <CODE>1</CODE>, * <CODE>2</CODE> or <CODE>3</CODE> in the exception, meaning an * illegal character is found, number overflow occurs or unexpected * end of region is encountered at <VAR>index</VAR>, respectively). ** * @see #toString(int, boolean, boolean, int, boolean, int) * @see #toBinaryString(int, int) * @see #toOctalString(int, int) * @see #toString(int, boolean) * @see #toHexString(int, boolean, int) * @see #decode(java.lang.String, int, int) * @see #valueOf(java.lang.String) * @see #parseRoman(java.lang.String, int, int) * @see #parseAbbreviation(java.lang.String, int, int, * java.lang.String) */ public static final int parse(String str, int beginIndex, int endIndex, boolean isUnsigned, int radix) throws NullPointerException, StringIndexOutOfBoundsException, ParserException { int value = str.length(); if (beginIndex < 0) throw new StringIndexOutOfBoundsException(beginIndex); if (endIndex < beginIndex || endIndex > value) throw new StringIndexOutOfBoundsException(endIndex); if (radix <= 2) radix = 2; if (radix >= ('9' - '0' + 1) + ('Z' - 'A' + 1)) radix = ('9' - '0' + 1) + ('Z' - 'A' + 1); beginIndex--; char ch = ' '; while (++beginIndex < endIndex && (ch = str.charAt(beginIndex)) == ' '); boolean negative = false; if (!isUnsigned) { if (ch == '-') { negative = true; beginIndex++; } if (ch == '+') beginIndex++; } if (beginIndex < endIndex) { int limit; if (~((limit = ((-1 >>> 1) / radix) << 1) * radix) >= radix) limit++; value = 0; do { if ((ch = (char)(str.charAt(beginIndex) - '0')) > '9' - '0') { ch -= 'A' - '0'; if (ch >= 'a' - 'A') ch -= 'a' - 'A'; if (ch < (char)-('9' - '0' + 1)) ch += '9' - '0' + 1; } if (ch >= radix || (value = value * radix + ch) >= 0 && value < ch) break; if (++beginIndex >= endIndex) { if (!isUnsigned) { beginIndex--; if (negative) { if ((value = -value) > 0) break; } else if (value < 0) break; } return value; } } while (((limit - value) | value) >= 0); } throw new ParserException(str, beginIndex, beginIndex < endIndex ? (ch >= radix ? 1 : 2) : 3); } /** * Decodes a given string region as an unsigned * octal/decimal/hexadecimal integer value. ** * The following unsigned <CODE>int</CODE> value formats are * accepted: decimal, hexadecimal (with '0x', '0X' or '#' prefix) * and octal (with '0' prefix). Leading spaces (before the prefix) * are ignored. Sign prefix is not permitted. Leading '0' characters * (after the prefix) are ignored too. ** * @param str * the string (must be non-<CODE>null</CODE>), which region to * parse. * @param beginIndex * the string region beginning index (must be in the range), * inclusive. * @param endIndex * the string region ending index (must be in the range), exclusive. * @return * an unsigned integer value represented by <VAR>str</VAR> region. * @exception NullPointerException * if <VAR>str</VAR> is <CODE>null</CODE>. * @exception StringIndexOutOfBoundsException * if <VAR>beginIndex</VAR> is negative, or if <VAR>endIndex</VAR> * is less than <VAR>beginIndex</VAR> or is greater than * <CODE>length()</CODE> of <VAR>str</VAR>. * @exception ParserException * if <VAR>str</VAR> region cannot be parsed (decoded) as an * unsigned integer (<VAR>error</VAR> is set to <CODE>1</CODE>, * <CODE>2</CODE> or <CODE>3</CODE> in the exception, meaning an * illegal character is found, number overflow occurs or unexpected * end of region is encountered at <VAR>index</VAR>, respectively). ** * @see #parse(java.lang.String, int, int, boolean, int) * @see #toString(int, boolean, boolean, int, boolean, int) * @see #toOctalString(int, int) * @see #toString(int, boolean) * @see #toHexString(int, boolean, int) * @see #valueOf(java.lang.String) * @see #parseRoman(java.lang.String, int, int) * @see #parseAbbreviation(java.lang.String, int, int, * java.lang.String) */ public static final int decode(String str, int beginIndex, int endIndex) throws NullPointerException, StringIndexOutOfBoundsException, ParserException { char ch = ' '; int radix = '9' - '0' + 1; if (((str.length() - endIndex) | beginIndex) >= 0) { beginIndex--; while (++beginIndex < endIndex && (ch = str.charAt(beginIndex)) == ' '); if (ch == '#' || ch == '0' && beginIndex + 1 < endIndex) { radix = 1 << 3; if (ch == '#' || (ch = str.charAt(++beginIndex)) == 'X' || ch == 'x') { radix = 1 << 4; if (++beginIndex < endIndex) ch = str.charAt(beginIndex); } if (ch == ' ') beginIndex--; } } return parse(str, beginIndex, endIndex, true, radix); } /** * Converts a given value into its Roman notation. ** * Zero value is represented as a single "-". If value is negative * then "-" is prepended before Roman digits. Spaces are prepended * to the result if needed (according to the absolute value of * <VAR>minLength</VAR>). The list of upper-case Roman digits is * specified by <CODE>ROMAN_DIGITS</CODE> built-in constant string * (the digits are ordered by their weight in it). ** * @param value * the signed value to be converted. * @param upperCase * <CODE>true</CODE> if and only if (digit) characters in the result * are in the upper case. * @param minLength * the minimal length of the result (absolute value). * @return * the Roman string representation (not <CODE>null</CODE>, with * <CODE>length()</CODE> not less than * <CODE>max(abs(minLength), 1)</CODE>) of <VAR>value</VAR>. * @exception OutOfMemoryError * if there is not enough memory. ** * @see #ROMAN_DIGITS * @see #parseRoman(java.lang.String, int, int) * @see #toString(int, boolean, boolean, int, boolean, int) * @see #toString(int, boolean) * @see #toAbbreviation(int, java.lang.String) ** * @since 2.0 */ public static final String toRomanString(int value, boolean upperCase, int minLength) { int offset = 1, len, digit; String digits; if ((len = (digits = ROMAN_DIGITS).length() - 1) < 0) value = 0; boolean negative = true; if (value != 0) { if (value > 0) { value = -value; negative = false; } digit = (('9' - '0') >> 1) + 1; if ((len & 1) == 0) digit = 1; for (offset = len >> 1; offset-- > 0; digit *= '9' - '0' + 1); if ((offset = ((len + 1) >> 1) * (('9' - '0' - 1) >> 1) - value / digit + 1) <= 0) offset = -1 >>> 1; } if (minLength < 0 && (minLength = -minLength) < 0) minLength--; if ((offset -= minLength) > 0) minLength += offset; else offset = 0; char[] chars = new char[minLength]; while ((digit = value) != 0) { char ch, nextCh; if (len <= 1) { ch = digits.charAt(0); if (!upperCase) ch += 'a' - 'A'; if (len > 0) { if ((digit = (value /= (('9' - '0') >> 1) + 1) * ((('9' - '0') >> 1) + 1) - digit) >= ('9' - '0') >> 1) { chars[--minLength] = ch; digit = 1; } if (digit > 0) { nextCh = digits.charAt(1); if (!upperCase) nextCh += 'a' - 'A'; do { chars[--minLength] = nextCh; } while (--digit > 0); } if (value >= 0) break; } do { chars[--minLength] = ch; } while (++value < 0); break; } if ((digit = (value /= '9' - '0' + 1) * ('9' - '0' + 1) - digit) > 0) { boolean half = false; if (digit >= ('9' - '0') >> 1) { if ((digit -= (('9' - '0') >> 1) + 1) >= ('9' - '0' - 1) >> 1) digit = -2; half = true; } ch = digits.charAt(len); if (!upperCase) ch += 'a' - 'A'; while (digit-- > 0) chars[--minLength] = ch; if (half) { nextCh = digits.charAt((digit >> 1) + len); if (!upperCase) nextCh += 'a' - 'A'; chars[--minLength] = nextCh; if (digit < -1) chars[--minLength] = ch; } } len -= 2; } if (negative) chars[--minLength] = '-'; while (offset < minLength) chars[--minLength] = ' '; return new String(chars, minLength, chars.length - minLength); } /** * Parses a given string region as an integer in the Roman notation. ** * Leading spaces (before a possible sign prefix) are ignored. The * permitted sign prefix is only either '+' or '-'. The next * characters (if present) in the string region must all be Roman * digits (which are specified by <CODE>ROMAN_DIGITS</CODE>). The * order checking for the digits (in the string region) is relaxed * here. But number overflow is checked properly * (<CODE>ParserException</CODE> is thrown if overflow occurs). ** * @param str * the string (must be non-<CODE>null</CODE>), which region to * parse. * @param beginIndex * the string region beginning index (must be in the range), * inclusive. * @param endIndex * the string region ending index (must be in the range), exclusive. * @return * a signed integer value represented by <VAR>str</VAR> region. * @exception NullPointerException * if <VAR>str</VAR> is <CODE>null</CODE>. * @exception StringIndexOutOfBoundsException * if <VAR>beginIndex</VAR> is negative, or if <VAR>endIndex</VAR> * is less than <VAR>beginIndex</VAR> or is greater than * <CODE>length()</CODE> of <VAR>str</VAR>. * @exception ParserException * if <VAR>str</VAR> region cannot be parsed as an integer value in * the Roman notation (<VAR>error</VAR> is set to <CODE>1</CODE>, * <CODE>2</CODE> or <CODE>3</CODE> in the exception, meaning an * illegal character is found, number overflow occurs or unexpected * end of region is encountered at <VAR>index</VAR>, respectively). ** * @see #ROMAN_DIGITS * @see #toRomanString(int, boolean, int) * @see #parse(java.lang.String, int, int, boolean, int) * @see #decode(java.lang.String, int, int) * @see #parseAbbreviation(java.lang.String, int, int, * java.lang.String) ** * @since 2.0 */ public static final int parseRoman(String str, int beginIndex, int endIndex) throws NullPointerException, StringIndexOutOfBoundsException, ParserException { int value = str.length(), pos = 0; if (beginIndex < 0) throw new StringIndexOutOfBoundsException(beginIndex); if (endIndex < beginIndex || endIndex > value) throw new StringIndexOutOfBoundsException(endIndex); beginIndex--; char ch = ' '; while (++beginIndex < endIndex && (ch = str.charAt(beginIndex)) == ' '); if (beginIndex < endIndex) { boolean negative = false; if (ch == '-') { negative = true; beginIndex++; } if (ch != '+') beginIndex--; String digits; int len = (digits = ROMAN_DIGITS).length() - 1; int sum = 0, last = 0, digit = -1; value = 0; do { if (++beginIndex >= endIndex) { if ((~(value = sum - value) & sum) >= 0 && (negative || (value = -value) != ~(-1 >>> 1))) return value; beginIndex--; break; } if ((char)((ch = str.charAt(beginIndex)) - 'a') <= 'z' - 'a') ch -= 'a' - 'A'; if (ch != digit) { if ((pos = digits.lastIndexOf(ch, len)) < 0) break; digit = (('9' - '0') >> 1) + 1; if (((pos = len - pos) & 1) == 0) digit = 1; if ((pos >>= 1) > 0) { do { digit *= '9' - '0' + 1; } while (--pos > 0); } if ((last < digit ? (value += sum) & ~sum : ~(value = sum - value) & sum) < 0) break; sum = value; value = 0; last = digit; digit = ch; } } while ((value += last) > 0); } throw new ParserException(str, beginIndex, beginIndex < endIndex ? (pos < 0 ? 1 : 2) : 3); } /** * Converts a given value into its abbreviation according to the * specified packed list of abbreviations. ** * If <VAR>value</VAR> has the corresponding string abbreviation * (specified in <VAR>paddedAbbrevsList</VAR>) then it is returned, * else the decimal string representation for <VAR>value</VAR> (with * '-' sign if negative) concatenated with the prefix and postfix * (specified in <VAR>paddedAbbrevsList</VAR> too) is returned. As * mentioned, all abbreviations are specified in a single * <VAR>paddedAbbrevsList</VAR> string which consists of zero or * more 'blocks' concatenated together. All blocks have the same * some length (the blocks are padded on the right to be of the same * length). The first block is as follows: its first character * denotes the separator character (used to pad/align * abbreviations), the next (zero or more) characters till * (exclusively) the next separator specifies the prefix string for * values without an assigned abbreviation, the following (zero or * more) characters till (exclusively) the next separator specifies * the postfix string (for values without an assigned abbreviation), * the next (zero or more) separators are appended to pad the block. * The second block (if present) must contain at the beginning at * least one non-separator character (the offset of this character * is, in fact, the length of each block). Every block, which ends * with the separator and does not start with the separator, * specifies a single abbreviation for a non-negative integer equal * to block number minus two. Important notes: * <VAR>paddedAbbrevsList</VAR> string is checked for the described * format, but no exception is thrown if the format string is bad * (in this case, the ordinary signed decimal integer string * representation is returned). ** * @param value * the signed value to be converted. * @param paddedAbbrevsList * the string (must be non-<CODE>null</CODE>), which specifies * abbreviations list (in the form of concatenation of right-padded * abbreviations ordered by value). * @return * an abbreviation string representation (not <CODE>null</CODE>, * with non-zero <CODE>length()</CODE>) of <VAR>value</VAR>. * @exception NullPointerException * if <VAR>paddedAbbrevsList</VAR> is <CODE>null</CODE>. * @exception OutOfMemoryError * if there is not enough memory. ** * @see #toString(int, boolean, boolean, int, boolean, int) * @see #toRomanString(int, boolean, int) * @see #filledString(char, int) * @see #parse(java.lang.String, int, int, boolean, int) * @see #decode(java.lang.String, int, int) * @see #parseAbbreviation(java.lang.String, int, int, * java.lang.String) ** * @since 2.0 */ public static final String toAbbreviation(int value, String paddedAbbrevsList) throws NullPointerException { int prefix, postfix, index; String prepend = null; if ((postfix = prefix = paddedAbbrevsList.length()) > 1) { char separator; if ((index = paddedAbbrevsList.indexOf(separator = paddedAbbrevsList.charAt(0), 1)) > 0 && (index = paddedAbbrevsList.indexOf(separator, (prefix = index) + 1)) > 0) { int len = postfix; postfix = index; if (value >= 0) { while (++index < len && paddedAbbrevsList.charAt(index) == separator); if ((len - 1) / index > value) { index *= value + 1; if ((len = paddedAbbrevsList.indexOf(separator, index)) > index) return paddedAbbrevsList.substring(index, len); } } } if (prefix > 1) prepend = paddedAbbrevsList.substring(1, prefix); prefix++; } String str = toString(value, false); if (prepend != null) str = prepend + str; if (prefix < postfix) str += paddedAbbrevsList.substring(prefix, postfix); return str; } /** * Parses a given string region as an integer value abbreviation * according to the specified packed list of abbreviations. ** * This is the opposite to <CODE>toAbbreviation(int, String)</CODE> * method. Leading spaces are ignored. All abbreviations are * case-insensitive. If the specified string region is recognized as * an abbreviation (specified in <VAR>sortedRefAbbrevsList</VAR>) * then its integer value (which stands for it) is returned, else * the string region is tried to be parsed as a signed decimal * integer representation with (or without) the prefix string and * with (or without) the postfix string (specified in * <VAR>sortedRefAbbrevsList</VAR> too) - its value is returned on * success, <CODE>ParserException</CODE> is thrown otherwise. As * mentioned, all abbreviations are specified in a single * <VAR>sortedRefAbbrevsList</VAR> string which either has the same * format as <VAR>paddedAbbrevsList</VAR> for * <CODE>toAbbreviation(int, String)</CODE> method or has the * following preferred format (which allows fast binary search of an * abbreviation). <VAR>sortedRefAbbrevsList</VAR> consists of zero * or more 'blocks' concatenated together. All the blocks have the * same some length. The first block is as follows: its first * character denotes the separator character (used to pad/align * abbreviations), the next (zero or more) characters till * (exclusively) the next separator specifies the prefix string for * values without an assigned abbreviation, the following (zero or * more) characters till (exclusively) the next separator specifies * the postfix string (again, for values without an assigned * abbreviation), the next (zero or more) separators are appended to * pad the block. The second block (if present) must contain at the * beginning at least one non-separator character (the offset of * this character is, in fact, the length of each block). Every * block (except for the first one) starts with a single * abbreviation (which the block specifies) followed with one or * more separator characters (to pad the block), and ends with a * non-negative decimal integer number (which stands for the denoted * abbreviation) followed with a single separator character. All the * blocks (except for the first one) are ordered alphabetically * ignoring characters case. Important notes: * <VAR>sortedRefAbbrevsList</VAR> string is checked to be of one of * these two described formats, if the format string is bad then the * specified string region is only tried to be parsed as a signed * decimal integer representation. ** * @param str * the string (must be non-<CODE>null</CODE>), which region to * parse. * @param beginIndex * the string region beginning index (must be in the range), * inclusive. * @param endIndex * the string region ending index (must be in the range), exclusive. * @param sortedRefAbbrevsList * the string (must be non-<CODE>null</CODE>), which specifies valid * abbreviations list (in the form of concatenation of right-padded * abbreviations ordered by value or in the form of concatenation of * center-padded abbreviation-value pairs sorted alphabetically * ignoring case). * @return * a signed integer value represented by <VAR>str</VAR> region. * @exception NullPointerException * if <VAR>str</VAR> is <CODE>null</CODE> or * <VAR>sortedRefAbbrevsList</VAR> is <CODE>null</CODE>. * @exception StringIndexOutOfBoundsException * if <VAR>beginIndex</VAR> is negative, or if <VAR>endIndex</VAR> * is less than <VAR>beginIndex</VAR> or is greater than * <CODE>length()</CODE> of <VAR>str</VAR>. * @exception ParserException * if <VAR>str</VAR> region cannot be parsed as one among the * specified abbreviations or as a signed integer (<VAR>error</VAR> * is set to <CODE>1</CODE>, <CODE>2</CODE> or <CODE>3</CODE> in the * exception, meaning an unknown abbreviation is encountered, number * overflow occurs or unexpected end of region is encountered at * <VAR>index</VAR>, respectively). ** * @see #toAbbreviation(int, java.lang.String) * @see #toString(int, boolean, boolean, int, boolean, int) * @see #parse(java.lang.String, int, int, boolean, int) * @see #decode(java.lang.String, int, int) * @see #parseRoman(java.lang.String, int, int) ** * @since 2.0 */ public static final int parseAbbreviation(String str, int beginIndex, int endIndex, String sortedRefAbbrevsList) throws NullPointerException, StringIndexOutOfBoundsException, ParserException { int prefix = sortedRefAbbrevsList.length(); if (((str.length() - endIndex) | (prefix - 2) | beginIndex) >= 0) { beginIndex--; while (++beginIndex < endIndex && str.charAt(beginIndex) == ' '); if (beginIndex < endIndex) { char separator; int postfix = 0, len = prefix; int strLen = endIndex - beginIndex, index; if ((index = sortedRefAbbrevsList.indexOf(separator = sortedRefAbbrevsList.charAt(0), 1)) > 0 && (index = sortedRefAbbrevsList.indexOf(separator, (prefix = index) + 1)) > 0) { postfix = index - prefix - 1; if (str.charAt(beginIndex) != separator && str.charAt(endIndex - 1) != separator) { while (++index < len && sortedRefAbbrevsList.charAt(index) == separator); int delta, value, match; char ch; if ((delta = index) <= len - index && (ch = sortedRefAbbrevsList.charAt(match = (index - 1) << 1)) != separator && (char)(ch - '0') <= '9' - '0' && sortedRefAbbrevsList.lastIndexOf(separator, match - 1) > index) { if (strLen < index) { len = len / index - 1; index = 1; int lowMatch = 0, highMatch = 0; while (index <= len) { int pos = (value = (index + len) >> 1) * delta, cmp; if ((match = lowMatch) >= highMatch) match = highMatch; match--; do { ch = sortedRefAbbrevsList.charAt(++match + pos); if (match < strLen) cmp = str.charAt(beginIndex + match); else if ((cmp = separator) == ch) { index = pos + delta; value--; while (sortedRefAbbrevsList.charAt(--index) == separator); if (pos + match < index) { pos = sortedRefAbbrevsList.lastIndexOf(separator, index - 1); value = 0; do { value = value * ('9' - '0' + 1) + sortedRefAbbrevsList.charAt(++pos) - '0'; } while (pos < index); } return value; } } while (((cmp -= ch) == 0 || (cmp = Character.toUpperCase((char)(cmp + ch)) - Character.toUpperCase(ch)) == 0) && ch != separator); if (cmp > 0) { index = value + 1; lowMatch = match; } else { len = value - 1; highMatch = match; } } } } else for (value = 0; (len -= delta) > 0 && (match = sortedRefAbbrevsList.indexOf(separator, index)) > 0; index += delta, value++) if (index + strLen == match && sortedRefAbbrevsList.regionMatches(true, index, str, beginIndex, strLen)) return value; } } if (--prefix > 0 && strLen > prefix && str.charAt(beginIndex + prefix) != ' ' && sortedRefAbbrevsList.regionMatches(true, 1, str, beginIndex, prefix)) beginIndex += prefix; if (postfix > 0 && endIndex - beginIndex > postfix && sortedRefAbbrevsList.regionMatches(true, prefix + 2, str, endIndex - postfix, postfix)) endIndex -= postfix; } } return parse(str, beginIndex, endIndex, false, '9' - '0' + 1); } /** * Constructs and returns a string filled with a given character. ** * The resulting string has the specified length and is entirely * filled with the specified character. Negative <VAR>len</VAR> is * treated as zero. Important notes: * <CODE>arraycopy(Object, int, Object, int, int)</CODE> method of * <CODE>System</CODE> class is used to fill the content of the * string. ** * @param ch * the character to fill the string with. * @param len * the length of the string which is created and filled. * @return * the filled string (not <CODE>null</CODE>, with * <CODE>length()</CODE> equal to <CODE>max(len, 0)</CODE>). * @exception OutOfMemoryError * if there is not enough memory. ** * @see #toString(int, boolean) * @see #toBinaryString(int, int) * @see #toOctalString(int, int) * @see #toHexString(int, boolean, int) * @see #toAbbreviation(int, java.lang.String) ** * @since 2.0 */ public static final String filledString(char ch, int len) { if (len <= 0) len = 0; char[] chars = new char[len]; if (ch != 0) { int remain, next = 2, block; if ((remain = len) > 3) remain = 4; while (remain-- > 0) chars[remain] = ch; remain = len - 2; while ((remain -= next) > 0) { if ((block = next <<= 1) >= remain) next = remain; System.arraycopy(chars, 0, chars, block, next); } } return new String(chars, 0, len); } /** * Converts a given string to an instance of this class. ** * This method returns a new <CODE>UnsignedInt</CODE> object * initialized to the unsigned decimal integer value of the * specified string. ** * @param str * the string (must be non-<CODE>null</CODE>, representing a valid * unsigned decimal integer) to be parsed. * @return * a newly constructed <CODE>UnsignedInt</CODE> instance (not * <CODE>null</CODE>) initialized to the value represented by * <VAR>str</VAR>. * @exception NullPointerException * if <VAR>str</VAR> is <CODE>null</CODE>. * @exception ParserException * if <VAR>str</VAR> cannot be parsed as an unsigned integer * (<VAR>error</VAR> is set to <CODE>1</CODE>, <CODE>2</CODE> or * <CODE>3</CODE> in the exception, meaning an illegal character is * found, number overflow occurs or unexpected end of string is * encountered at <VAR>index</VAR>, respectively). * @exception OutOfMemoryError * if there is not enough memory. ** * @see UnsignedInt#UnsignedInt(int) * @see #parse(java.lang.String, int, int, boolean, int) * @see #decode(java.lang.String, int, int) * @see #intValue() * @see #toString() */ public static UnsignedInt valueOf(String str) throws NullPointerException, ParserException { return new UnsignedInt(parse(str, 0, str.length(), true, '9' - '0' + 1)); } /** * Returns the value of <CODE>this</CODE> number as * <CODE>int</CODE>. ** * @return * the numeric <CODE>int</CODE> value represented by the object. ** * @see UnsignedInt#UnsignedInt(int) * @see #longValue() * @see #floatValue() * @see #doubleValue() * @see #toString() */ public int intValue() { return this.unsignedValue; } /** * Returns the value of <CODE>this</CODE> number as * <CODE>long</CODE>. ** * The result is the same as of * <CODE>(intValue() & JavaConsts INT_LMASK)</CODE>. ** * @return * the numeric <CODE>long</CODE> value represented by the object. ** * @see UnsignedInt#UnsignedInt(int) * @see #intValue() * @see #floatValue() * @see #doubleValue() * @see #toString() */ public long longValue() { return this.unsignedValue & JavaConsts.INT_LMASK; } /** * Returns the value of <CODE>this</CODE> number as * <CODE>float</CODE>. ** * The result is the same as of <CODE>(float)doubleValue()</CODE>. * Important notes: this may involve rounding; the result is always * non-negative. ** * @return * the numeric <CODE>float</CODE> value represented by the object. ** * @see UnsignedInt#UnsignedInt(int) * @see #intValue() * @see #longValue() * @see #doubleValue() * @see #toString() */ public float floatValue() { int unsignedValue = this.unsignedValue; return (unsignedValue >>> 1) * 2.0F + (unsignedValue & 1); } /** * Returns the value of <CODE>this</CODE> number as * <CODE>double</CODE>. ** * Important notes: the result is always non-negative. ** * @return * the numeric <CODE>double</CODE> value represented by the object. ** * @see UnsignedInt#UnsignedInt(int) * @see #intValue() * @see #longValue() * @see #floatValue() * @see #toString() */ public double doubleValue() { int unsignedValue = this.unsignedValue; return (unsignedValue >>> 1) * 2.0D + (unsignedValue & 1); } /** * Creates and returns a copy of <CODE>this</CODE> object. ** * The result is the same as of * <CODE>new UnsignedInt(intValue())</CODE>. ** * @return * a copy (not <CODE>null</CODE> and != <CODE>this</CODE>) of * <CODE>this</CODE> instance. * @exception OutOfMemoryError * if there is not enough memory. ** * @see UnsignedInt#UnsignedInt(int) * @see #valueOf(java.lang.String) * @see #intValue() * @see #equals(java.lang.Object) */ public Object clone() { Object obj; try { if ((obj = super.clone()) instanceof UnsignedInt && obj != this) return obj; } catch (CloneNotSupportedException e) {} throw new InternalError("CloneNotSupportedException"); } /** * Returns a hash code value for the object. ** * The hash code value for this object is equal to the primitive * <CODE>int</CODE> value represented by this object. ** * @return * a hash code value for <CODE>this</CODE> object. ** * @see #intValue() * @see #equals(java.lang.Object) */ public int hashCode() { return this.unsignedValue; } /** * Indicates whether <CODE>this</CODE> object is equal to the * specified one. ** * This method returns <CODE>true</CODE> if and only if * <VAR>obj</VAR> is instance of <CODE>this</CODE> class, and the * wrapped values of <CODE>this</CODE> and of <VAR>obj</VAR> are * equal. ** * @param obj * the second compared object (may be <CODE>null</CODE>). * @return * <CODE>true</CODE> if and only if <CODE>this</CODE> value is the * same as <VAR>obj</VAR> value. ** * @see #compare(int, int) * @see #intValue() * @see #hashCode() * @see #greaterThan(java.lang.Object) */ public boolean equals(Object obj) { return obj == this || obj instanceof UnsignedInt && ((UnsignedInt)obj).unsignedValue == this.unsignedValue; } /** * Tests for being semantically greater than the argument. ** * The result is <CODE>true</CODE> if and only if <VAR>obj</VAR> is * instance of <CODE>this</CODE> class and the wrapped value of * <CODE>this</CODE> object is greater (in the unsigned manner) than * the wrapped value of the specified object. ** * @param obj * the second compared object (may be <CODE>null</CODE>). * @return * <CODE>true</CODE> if <VAR>obj</VAR> is comparable with * <CODE>this</CODE> and <CODE>this</CODE> object is greater than * <VAR>obj</VAR>, else <CODE>false</CODE>. ** * @see #greater(int, int) * @see #compare(int, int) * @see #intValue() * @see #equals(java.lang.Object) ** * @since 2.0 */ public boolean greaterThan(Object obj) { int unsignedA = 0; if (obj != this && obj instanceof UnsignedInt) { int unsignedB = ((UnsignedInt)obj).unsignedValue; if (((unsignedA = this.unsignedValue) ^ unsignedB) >= 0) unsignedA = unsignedB - unsignedA; } return unsignedA < 0; } /** * Converts <CODE>this</CODE> object to its 'in-line' string * representation. ** * The wrapped value is converted to its unsigned decimal * representation and returned as a string, exactly as by * <CODE>toString(intValue(), true)</CODE>. ** * @return * the string representation (not <CODE>null</CODE>, with non-zero * <CODE>length()</CODE>) of <CODE>this</CODE> object. * @exception OutOfMemoryError * if there is not enough memory. ** * @see UnsignedInt#UnsignedInt(int) * @see #intValue() * @see #toString(int, boolean) * @see #toString(int, boolean, boolean, int, boolean, int) * @see #toAbbreviation(int, java.lang.String) * @see #valueOf(java.lang.String) */ public String toString() { return toString(this.unsignedValue, true); } }