001: /** Various utility methods and conversions for handling mixed-mode arithmetic.
002: * This should possibly be moved to gnu.math. */package gnu.kawa.functions;
003:
004: import gnu.math.*;
005: import java.math.*;
006:
007: public class Arithmetic {
008: /** Promotion code for byte/Byte, short/Short, int/Integer. */
009: public static final int INT_CODE = 1;
010: /** Promotion code for long/Long. */
011: public static final int LONG_CODE = 2;
012: /** Promotion code for java.math.BigInteger. */
013: public static final int BIGINTEGER_CODE = 3;
014: /** Promotion code for gnu.math.IntNum. */
015: public static final int INTNUM_CODE = 4;
016: /** Promotion code for java.math.BigDecimal. */
017: public static final int BIGDECIMAL_CODE = 5;
018: /** Promotion code for gnu.math.RatNum. */
019: public static final int RATNUM_CODE = 6;
020: /** Promotion code float/Float. */
021: public static final int FLOAT_CODE = 7;
022: /** Promotion code double/Double. */
023: public static final int DOUBLE_CODE = 8;
024: /** Promotion code for gnu.math.FloNum. */
025: public static final int FLONUM_CODE = 9;
026: /** Promotion code for other gnu.math.Numeric. */
027: public static final int NUMERIC_CODE = 10;
028:
029: public static int classifyValue(Object value) {
030: if (value instanceof Numeric) {
031: if (value instanceof IntNum)
032: return INTNUM_CODE;
033: else if (value instanceof RatNum)
034: return RATNUM_CODE;
035: else if (value instanceof DFloNum)
036: return FLONUM_CODE;
037: else
038: return NUMERIC_CODE;
039: } else if (value instanceof Number) {
040: if (value instanceof Integer || value instanceof Short
041: || value instanceof Byte)
042: return INT_CODE;
043: else if (value instanceof Long)
044: return LONG_CODE;
045: else if (value instanceof Float)
046: return FLOAT_CODE;
047: else if (value instanceof Double)
048: return DOUBLE_CODE;
049: else if (value instanceof BigInteger)
050: return BIGINTEGER_CODE;
051: else if (value instanceof BigDecimal)
052: return BIGDECIMAL_CODE;
053: else
054: return -1;
055: } else
056: return -1;
057: }
058:
059: public static int asInt(Object value) {
060: return ((Number) value).intValue();
061: }
062:
063: public static long asLong(Object value) {
064: return ((Number) value).longValue();
065: }
066:
067: public static float asFloat(Object value) {
068: return ((Number) value).floatValue();
069: }
070:
071: public static double asDouble(Object value) {
072: return ((Number) value).doubleValue();
073: }
074:
075: public static BigInteger asBigInteger(Object value) {
076: if (value instanceof BigInteger)
077: return (BigInteger) value;
078: if (value instanceof IntNum)
079: return new BigInteger(value.toString());
080: return BigInteger.valueOf(((Number) value).longValue());
081: }
082:
083: public static IntNum asIntNum(BigDecimal value) {
084: return IntNum.valueOf(((BigDecimal) value).toBigInteger()
085: .toString(), 10);
086: }
087:
088: public static IntNum asIntNum(BigInteger value) {
089: return IntNum.valueOf(value.toString(), 10);
090: }
091:
092: public static IntNum asIntNum(Object value) {
093: if (value instanceof IntNum)
094: return (IntNum) value;
095: if (value instanceof BigInteger)
096: return IntNum.valueOf(value.toString(), 10);
097: if (value instanceof BigDecimal)
098: return asIntNum((BigDecimal) value);
099: return IntNum.make(((Number) value).longValue());
100: }
101:
102: public static BigDecimal asBigDecimal(Object value) {
103: if (value instanceof BigDecimal)
104: return (BigDecimal) value;
105: if (value instanceof BigInteger)
106: return new BigDecimal((BigInteger) value);
107: if (value instanceof Long || value instanceof Integer
108: || value instanceof Short || value instanceof Byte)
109: return BigDecimal.valueOf(((Number) value).longValue());
110: return new BigDecimal(value.toString());
111: }
112:
113: public static final IntNum ten_exp_9 = IntNum.make(1000000000);
114:
115: public static RatNum asRatNum(Object value) {
116: if (value instanceof RatNum)
117: return (RatNum) value;
118: if (value instanceof BigInteger)
119: return IntNum.valueOf(value.toString(), 10);
120: if (value instanceof BigDecimal) {
121: BigDecimal d = (BigDecimal) value;
122: RatNum v = IntNum.valueOf(d.unscaledValue().toString(), 10);
123: int scale = d.scale();
124: for (; scale >= 9; scale -= 9)
125: v = RatNum.divide(v, ten_exp_9);
126: for (; scale <= -9; scale += 9)
127: v = RatNum.times(v, ten_exp_9);
128: IntNum scaleVal;
129: switch (scale > 0 ? scale : -scale) {
130: case 1:
131: scaleVal = IntNum.make(10);
132: break;
133: case 2:
134: scaleVal = IntNum.make(100);
135: break;
136: case 3:
137: scaleVal = IntNum.make(1000);
138: break;
139: case 4:
140: scaleVal = IntNum.make(10000);
141: break;
142: case 5:
143: scaleVal = IntNum.make(100000);
144: break;
145: case 6:
146: scaleVal = IntNum.make(1000000);
147: break;
148: case 7:
149: scaleVal = IntNum.make(10000000);
150: break;
151: case 8:
152: scaleVal = IntNum.make(100000000);
153: break;
154: default:
155: return v;
156: }
157: if (scale > 0)
158: return RatNum.divide(v, scaleVal);
159: else
160: return RatNum.times(v, scaleVal);
161: } else
162: return IntNum.make(((Number) value).longValue());
163: }
164:
165: public static Numeric asNumeric(Object value) {
166: if (!(value instanceof Numeric)) {
167: if (value instanceof BigInteger || value instanceof Long
168: || value instanceof Short || value instanceof Byte
169: || value instanceof Integer)
170: return asIntNum(value);
171: if (value instanceof BigDecimal)
172: return asRatNum(value);
173: if (value instanceof Float || value instanceof Double)
174: return new DFloNum(asDouble(value));
175: }
176: return (Numeric) value;
177: }
178:
179: /** Convert a number to a String.
180: * Handles classes subclasses of gnu.math.Numeric
181: * as well as standard Java classes.
182: */
183: public static String toString(Object number, int radix) {
184: int code = Arithmetic.classifyValue(number);
185: switch (code) {
186: case Arithmetic.INT_CODE:
187: return Integer.toString(Arithmetic.asInt(number), radix);
188: case Arithmetic.LONG_CODE:
189: return Long.toString(Arithmetic.asLong(number), radix);
190: case Arithmetic.BIGINTEGER_CODE:
191: return Arithmetic.asBigInteger(number).toString(radix);
192: case Arithmetic.INTNUM_CODE:
193: return Arithmetic.asIntNum(number).toString(radix);
194: case Arithmetic.BIGDECIMAL_CODE:
195: if (radix == 10)
196: return Arithmetic.asBigDecimal(number).toString();
197: // else fall through:
198: case Arithmetic.FLOAT_CODE:
199: if (radix == 10)
200: return Float.toString(Arithmetic.asFloat(number));
201: // else fall through:
202: case Arithmetic.DOUBLE_CODE:
203: case Arithmetic.FLONUM_CODE:
204: if (radix == 10)
205: return Double.toString(Arithmetic.asDouble(number));
206: // else fall through:
207: case Arithmetic.RATNUM_CODE:
208: default:
209: return Arithmetic.asNumeric(number).toString(radix);
210: }
211: }
212:
213: /** Coerce a number to one of the Arithmetic.XXX_CODE types.
214: * Assumes {@code > Arithmetic.classifyValue(value)}, though
215: * the converse might also work.
216: */
217: public static Object convert(Object value, int code) {
218: switch (code) {
219: case Arithmetic.INT_CODE:
220: if (value instanceof Integer)
221: return value;
222: int i = ((Number) value).intValue();
223: /* #ifdef JAVA5 */
224: // return Integer.valueOf(i);
225: /* #else */
226: return new Integer(i);
227: /* #endif */
228: case Arithmetic.LONG_CODE:
229: if (value instanceof Long)
230: return value;
231: long l = ((Number) value).longValue();
232: /* #ifdef JAVA5 */
233: // return Long.valueOf(l);
234: /* #else */
235: return new Long(l);
236: /* #endif */
237: case Arithmetic.BIGINTEGER_CODE:
238: return Arithmetic.asBigInteger(value);
239: case Arithmetic.INTNUM_CODE:
240: return Arithmetic.asIntNum(value);
241: case Arithmetic.BIGDECIMAL_CODE:
242: return Arithmetic.asBigDecimal(value);
243: case Arithmetic.RATNUM_CODE:
244: return Arithmetic.asRatNum(value);
245: case Arithmetic.FLOAT_CODE:
246: if (value instanceof Float)
247: return value;
248: float f = Arithmetic.asFloat(value);
249: /* #ifdef JAVA5 */
250: // return Float.valueOf(f);
251: /* #else */
252: return new Float(f);
253: /* #endif */
254: case Arithmetic.DOUBLE_CODE:
255: if (value instanceof Double)
256: return value;
257: double d = Arithmetic.asDouble(value);
258: /* #ifdef JAVA5 */
259: // return Double.valueOf(d);
260: /* #else */
261: return new Double(d);
262: /* #endif */
263: case Arithmetic.FLONUM_CODE:
264: if (value instanceof DFloNum)
265: return value;
266: return DFloNum.make(Arithmetic.asDouble(value));
267: default:
268: return (Number) value;
269: }
270: }
271: }
|