package aima.core.util.math; import java.util.List; /** * For details on <a * href="http://demonstrations.wolfram.com/MixedRadixNumberRepresentations/" * >Mixed Radix Number Representations.</a> * * @author Ciaran O'Reilly * @author Mike Stampone */ public class MixedRadixNumber extends Number { // private static final long serialVersionUID = 1L; // private long value = 0L; private long maxValue = 0L; private int[] radices = null; private int[] currentNumeralValue = null; private boolean recalculate = true; /** * Constructs a mixed radix number with a specified value and a specified * array of radices. * * @param value * the value of the mixed radix number * @param radices * the radices used to represent the value of the mixed radix * number */ public MixedRadixNumber(long value, int[] radices) { this.value = value; this.radices = new int[radices.length]; System.arraycopy(radices, 0, this.radices, 0, radices.length); calculateMaxValue(); } /** * Constructs a mixed radix number with a specified value and a specified * list of radices. * * @param value * the value of the mixed radix number * @param radices * the radices used to represent the value of the mixed radix * number */ public MixedRadixNumber(long value, List<Integer> radices) { this.value = value; this.radices = new int[radices.size()]; for (int i = 0; i < radices.size(); i++) { this.radices[i] = radices.get(i); } calculateMaxValue(); } /** * Constructs a mixed radix number with a specified array of numerals and a * specified array of radices. * * @param radixValues * the numerals of the mixed radix number * @param radices * the radices of the mixed radix number */ public MixedRadixNumber(int[] radixValues, int[] radices) { this(0, radices); setCurrentValueFor(radixValues); } /** * Returns the value of the mixed radix number with the specified array of * numerals and the current array of radices. * * @return the value of the mixed radix number * * @throws IllegalArgumentException * if any of the specified numerals is less than zero, or if any * of the specified numerals is greater than it's corresponding * radix. */ public long getCurrentValueFor(int[] radixValues) { if (radixValues.length != radices.length) { throw new IllegalArgumentException( "Radix values not same size as Radices."); } long cvalue = 0; long mvalue = 1; for (int i = 0; i < radixValues.length; i++) { if (radixValues[i] < 0 || radixValues[i] >= radices[i]) { throw new IllegalArgumentException("Radix value " + i + " is out of range for radix at this position"); } if (i > 0) { mvalue *= radices[i - 1]; } cvalue += mvalue * radixValues[i]; } return cvalue; } /** * Sets the value of the mixed radix number with the specified array of * numerals and the current array of radices. * * @param radixValues * the numerals of the mixed radix number */ public void setCurrentValueFor(int[] radixValues) { this.value = getCurrentValueFor(radixValues); System.arraycopy(radixValues, 0, this.currentNumeralValue, 0, radixValues.length); recalculate = false; } /** * Returns the maximum value which can be represented by the current array * of radices. * * @return the maximum value which can be represented by the current array * of radices. */ public long getMaxAllowedValue() { return maxValue; } /** * Increments the value of the mixed radix number, if the value is less than * the maximum value which can be represented by the current array of * radices. * * @return <code>true</code> if the increment was successful. */ public boolean increment() { if (value < maxValue) { value++; recalculate = true; return true; } return false; } /** * Decrements the value of the mixed radix number, if the value is greater * than zero. * * @return <code>true</code> if the decrement was successful. */ public boolean decrement() { if (value > 0) { value--; recalculate = true; return true; } return false; } /** * Returns the numeral at the specified position. * * @param atPosition * the position of the numeral to return * @return the numeral at the specified position. */ public int getCurrentNumeralValue(int atPosition) { if (atPosition >= 0 && atPosition < radices.length) { if (recalculate) { long quotient = value; for (int i = 0; i < radices.length; i++) { if (0 != quotient) { currentNumeralValue[i] = (int) quotient % radices[i]; quotient = quotient / radices[i]; } else { currentNumeralValue[i] = 0; } } recalculate = false; } return currentNumeralValue[atPosition]; } throw new IllegalArgumentException( "Argument atPosition must be >=0 and < " + radices.length); } // // START-Number @Override public int intValue() { return (int) longValue(); } @Override public long longValue() { return value; } @Override public float floatValue() { return longValue(); } @Override public double doubleValue() { return longValue(); } // END-Number // @Override public String toString() { StringBuilder sb = new StringBuilder(); for (int i = 0; i < radices.length; i++) { sb.append("["); sb.append(this.getCurrentNumeralValue(i)); sb.append("]"); } return sb.toString(); } // // PRIVATE // /** * Sets the maximum value which can be represented by the current array of * radices. * * @throws IllegalArgumentException * if no radices are defined, if any radix is less than two, or * if the current value is greater than the maximum value which * can be represented by the current array of radices. */ private void calculateMaxValue() { if (0 == radices.length) { throw new IllegalArgumentException( "At least 1 radix must be defined."); } for (int i = 0; i < radices.length; i++) { if (radices[i] < 2) { throw new IllegalArgumentException( "Invalid radix, must be >= 2"); } } // Calculate the maxValue allowed maxValue = radices[0]; for (int i = 1; i < radices.length; i++) { maxValue *= radices[i]; } maxValue -= 1; if (value > maxValue) { throw new IllegalArgumentException( "The value [" + value + "] cannot be represented with the radices provided, max value is " + maxValue); } currentNumeralValue = new int[radices.length]; } }