/** Various utility methods and conversions for handling mixed-mode arithmetic.
* This should possibly be moved to gnu.math. */
package gnu.kawa.functions;
import gnu.math.*;
import java.math.*;
public class Arithmetic
{
/** Promotion code for byte/Byte, short/Short, int/Integer. */
public static final int INT_CODE = 1;
/** Promotion code for long/Long. */
public static final int LONG_CODE = 2;
/** Promotion code for java.math.BigInteger. */
public static final int BIGINTEGER_CODE = 3;
/** Promotion code for gnu.math.IntNum. */
public static final int INTNUM_CODE = 4;
/** Promotion code for java.math.BigDecimal. */
public static final int BIGDECIMAL_CODE = 5;
/** Promotion code for gnu.math.RatNum. */
public static final int RATNUM_CODE = 6;
/** Promotion code float/Float. */
public static final int FLOAT_CODE = 7;
/** Promotion code double/Double. */
public static final int DOUBLE_CODE = 8;
/** Promotion code for gnu.math.FloNum. */
public static final int FLONUM_CODE = 9;
/** Promotion code for other gnu.math.Numeric. */
public static final int NUMERIC_CODE = 10;
public static int classifyValue (Object value)
{
if (value instanceof Numeric)
{
if (value instanceof IntNum)
return INTNUM_CODE;
else if (value instanceof RatNum)
return RATNUM_CODE;
else if (value instanceof DFloNum)
return FLONUM_CODE;
else
return NUMERIC_CODE;
}
else if (value instanceof Number)
{
if (value instanceof Integer || value instanceof Short
|| value instanceof Byte)
return INT_CODE;
else if (value instanceof Long)
return LONG_CODE;
else if (value instanceof Float)
return FLOAT_CODE;
else if (value instanceof Double)
return DOUBLE_CODE;
else if (value instanceof BigInteger)
return BIGINTEGER_CODE;
else if (value instanceof BigDecimal)
return BIGDECIMAL_CODE;
else
return -1;
}
else
return -1;
}
public static int asInt (Object value)
{
return ((Number) value).intValue();
}
public static long asLong (Object value)
{
return ((Number) value).longValue();
}
public static float asFloat (Object value)
{
return ((Number) value).floatValue();
}
public static double asDouble (Object value)
{
return ((Number) value).doubleValue();
}
public static BigInteger asBigInteger (Object value)
{
if (value instanceof BigInteger)
return (BigInteger) value;
if (value instanceof IntNum)
return new BigInteger(value.toString());
return BigInteger.valueOf(((Number) value).longValue());
}
public static IntNum asIntNum (BigDecimal value)
{
return IntNum.valueOf(((BigDecimal) value).toBigInteger().toString(), 10);
}
public static IntNum asIntNum (BigInteger value)
{
return IntNum.valueOf(value.toString(), 10);
}
public static IntNum asIntNum (Object value)
{
if (value instanceof IntNum)
return (IntNum) value;
if (value instanceof BigInteger)
return IntNum.valueOf(value.toString(), 10);
if (value instanceof BigDecimal)
return asIntNum((BigDecimal) value);
return IntNum.make(((Number) value).longValue());
}
public static BigDecimal asBigDecimal (Object value)
{
if (value instanceof BigDecimal)
return (BigDecimal) value;
if (value instanceof BigInteger)
return new BigDecimal((BigInteger) value);
if (value instanceof Long || value instanceof Integer
|| value instanceof Short || value instanceof Byte)
return BigDecimal.valueOf(((Number) value).longValue());
return new BigDecimal(value.toString());
}
public static final IntNum ten_exp_9 = IntNum.make(1000000000);
public static RatNum asRatNum (Object value)
{
if (value instanceof RatNum)
return (RatNum) value;
if (value instanceof BigInteger)
return IntNum.valueOf(value.toString(), 10);
if (value instanceof BigDecimal)
{
BigDecimal d = (BigDecimal) value;
RatNum v = IntNum.valueOf(d.unscaledValue().toString(), 10);
int scale = d.scale();
for (; scale >= 9; scale -= 9)
v = RatNum.divide(v, ten_exp_9);
for (; scale <= -9; scale += 9)
v = RatNum.times(v, ten_exp_9);
IntNum scaleVal;
switch (scale > 0 ? scale : -scale)
{
case 1: scaleVal = IntNum.make(10); break;
case 2: scaleVal = IntNum.make(100); break;
case 3: scaleVal = IntNum.make(1000); break;
case 4: scaleVal = IntNum.make(10000); break;
case 5: scaleVal = IntNum.make(100000); break;
case 6: scaleVal = IntNum.make(1000000); break;
case 7: scaleVal = IntNum.make(10000000); break;
case 8: scaleVal = IntNum.make(100000000); break;
default:
return v;
}
if (scale > 0)
return RatNum.divide(v, scaleVal);
else
return RatNum.times(v, scaleVal);
}
else
return IntNum.make(((Number) value).longValue());
}
public static Numeric asNumeric (Object value)
{
if (! (value instanceof Numeric))
{
if (value instanceof BigInteger || value instanceof Long
|| value instanceof Short || value instanceof Byte
|| value instanceof Integer)
return asIntNum(value);
if (value instanceof BigDecimal)
return asRatNum(value);
if (value instanceof Float || value instanceof Double)
return new DFloNum(asDouble(value));
}
return (Numeric) value;
}
/** Convert a number to a String.
* Handles classes subclasses of gnu.math.Numeric
* as well as standard Java classes.
*/
public static String toString (Object number, int radix)
{
int code = Arithmetic.classifyValue(number);
switch (code)
{
case Arithmetic.INT_CODE:
return Integer.toString(Arithmetic.asInt(number), radix);
case Arithmetic.LONG_CODE:
return Long.toString(Arithmetic.asLong(number), radix);
case Arithmetic.BIGINTEGER_CODE:
return Arithmetic.asBigInteger(number).toString(radix);
case Arithmetic.INTNUM_CODE:
return Arithmetic.asIntNum(number).toString(radix);
case Arithmetic.BIGDECIMAL_CODE:
if (radix == 10)
return Arithmetic.asBigDecimal(number).toString();
// else fall through:
case Arithmetic.FLOAT_CODE:
if (radix == 10)
return Float.toString(Arithmetic.asFloat(number));
// else fall through:
case Arithmetic.DOUBLE_CODE:
case Arithmetic.FLONUM_CODE:
if (radix == 10)
return Double.toString(Arithmetic.asDouble(number));
// else fall through:
case Arithmetic.RATNUM_CODE:
default:
return Arithmetic.asNumeric(number).toString(radix);
}
}
/** Coerce a number to one of the Arithmetic.XXX_CODE types.
* Assumes {@code > Arithmetic.classifyValue(value)}, though
* the converse might also work.
*/
public static Object convert (Object value, int code)
{
switch (code)
{
case Arithmetic.INT_CODE:
if (value instanceof Integer)
return value;
int i = ((Number) value).intValue();
/* #ifdef JAVA5 */
// return Integer.valueOf(i);
/* #else */
return new Integer(i);
/* #endif */
case Arithmetic.LONG_CODE:
if (value instanceof Long)
return value;
long l = ((Number) value).longValue();
/* #ifdef JAVA5 */
// return Long.valueOf(l);
/* #else */
return new Long(l);
/* #endif */
case Arithmetic.BIGINTEGER_CODE:
return Arithmetic.asBigInteger(value);
case Arithmetic.INTNUM_CODE:
return Arithmetic.asIntNum(value);
case Arithmetic.BIGDECIMAL_CODE:
return Arithmetic.asBigDecimal(value);
case Arithmetic.RATNUM_CODE:
return Arithmetic.asRatNum(value);
case Arithmetic.FLOAT_CODE:
if (value instanceof Float)
return value;
float f = Arithmetic.asFloat(value);
/* #ifdef JAVA5 */
// return Float.valueOf(f);
/* #else */
return new Float(f);
/* #endif */
case Arithmetic.DOUBLE_CODE:
if (value instanceof Double)
return value;
double d = Arithmetic.asDouble(value);
/* #ifdef JAVA5 */
// return Double.valueOf(d);
/* #else */
return new Double(d);
/* #endif */
case Arithmetic.FLONUM_CODE:
if (value instanceof DFloNum)
return value;
return DFloNum.make(Arithmetic.asDouble(value));
default:
return (Number) value;
}
}
}
|