001: // Copyright (c) 2001 Per M.A. Bothner and Brainfood Inc.
002: // This is free software; for terms and warranty disclaimer see ./COPYING.
003:
004: package gnu.xquery.util;
005:
006: import gnu.math.*;
007: import gnu.mapping.*;
008: import java.math.BigDecimal;
009: import gnu.kawa.functions.Arithmetic;
010: import gnu.kawa.xml.*;
011: import gnu.xml.TextUtils;
012:
013: public class NumberValue extends Procedure1 {
014: public static final NumberValue numberValue = new NumberValue();
015:
016: public static final Double NaN = new Double(Double.NaN);
017:
018: public static boolean isNaN(Object arg) {
019: return ((arg instanceof Double || arg instanceof Float || arg instanceof DFloNum) && Double
020: .isNaN(((Number) arg).doubleValue()));
021: }
022:
023: public Object apply1(Object arg) {
024: if (arg != Values.empty && arg != null) {
025: try {
026: return numberValue(arg);
027: } catch (Throwable ex) {
028: // fall through to return NaN;
029: }
030: }
031: return NaN;
032: }
033:
034: public static Number numberCast(Object value) {
035: if (value == Values.empty || value == null)
036: return null;
037: if (value instanceof Values) {
038: Values vals = (Values) value;
039: int ipos = vals.startPos();
040: int count = 0;
041: while ((ipos = vals.nextPos(ipos)) != 0) {
042: if (count > 0)
043: throw new ClassCastException(
044: "non-singleton sequence cast to number");
045: value = vals.getPosPrevious(ipos);
046: count++;
047: }
048: }
049: if (value instanceof KNode || value instanceof UntypedAtomic)
050: return (Double) XDataType.doubleType.valueOf(TextUtils
051: .stringValue(value));
052: return (Number) value;
053: }
054:
055: public static Object numberValue(Object value) {
056: value = KNode.atomicValue(value);
057: double d;
058: if (value instanceof UntypedAtomic || value instanceof String) {
059: try {
060: return XDataType.doubleType.valueOf(TextUtils
061: .stringValue(value));
062: } catch (Throwable ex) {
063: d = Double.NaN;
064: }
065: } else if (value instanceof Number
066: && (value instanceof RealNum || !(value instanceof Numeric)))
067: d = (((Number) value).doubleValue());
068: else
069: d = Double.NaN;
070: return XDataType.makeDouble(d);
071: }
072:
073: public static Object abs(Object value) {
074: if (value == null || value == Values.empty)
075: return value;
076: value = numberCast(value);
077: if (value instanceof Double) {
078: Double d = (Double) value;
079: double x = d.doubleValue();
080: long bits = Double.doubleToRawLongBits(x);
081: if (bits >= 0)
082: return d;
083: bits &= 0x7fffffffffffffffL;
084: x = Double.longBitsToDouble(bits);
085: /* #ifdef JAVA5 */
086: // return Double.valueOf(x);
087: /* #else */
088: return new Double(x);
089: /* #endif */
090: }
091: if (value instanceof Float) {
092: Float d = (Float) value;
093: float x = d.floatValue();
094: int bits = Float.floatToRawIntBits(x);
095: if (bits >= 0)
096: return d;
097: bits &= 0x7fffffff;
098: x = Float.intBitsToFloat(bits);
099: /* #ifdef JAVA5 */
100: // return Float.valueOf(x) ;
101: /* #else */
102: return new Float(x);
103: /* #endif */
104: }
105: if (value instanceof BigDecimal) {
106: BigDecimal dec = (BigDecimal) value;
107: if (dec.signum() < 0)
108: dec = dec.negate();
109: return dec;
110: }
111: return ((Numeric) value).abs();
112: }
113:
114: public static Object floor(Object val) {
115: Number value = numberCast(val);
116: if (value == null)
117: return val;
118: if (value instanceof Double)
119: return XDataType.makeDouble(Math.floor(((Double) value)
120: .doubleValue()));
121: if (value instanceof Float)
122: return XDataType.makeFloat((float) Math
123: .floor(((Float) value).floatValue()));
124: if (value instanceof BigDecimal) {
125: BigDecimal dec = (BigDecimal) value;
126: return Arithmetic.asIntNum(dec.divide(
127: XDataType.DECIMAL_ONE, 0, BigDecimal.ROUND_FLOOR)
128: .toBigInteger());
129: }
130: return ((RealNum) value).toInt(Numeric.FLOOR);
131: }
132:
133: public static Object ceiling(Object val) {
134: Number value = numberCast(val);
135: if (value == null)
136: return val;
137: if (value instanceof Double)
138: return XDataType.makeDouble(Math.ceil(((Double) value)
139: .doubleValue()));
140: if (value instanceof Float)
141: return XDataType.makeFloat((float) Math
142: .ceil(((Float) value).floatValue()));
143: if (value instanceof BigDecimal) {
144: BigDecimal dec = (BigDecimal) value;
145: return Arithmetic.asIntNum(dec.divide(
146: XDataType.DECIMAL_ONE, 0, BigDecimal.ROUND_CEILING)
147: .toBigInteger());
148: }
149: return ((RealNum) value).toInt(Numeric.CEILING);
150: }
151:
152: public static Object round(Object arg) {
153: Number value = numberCast(arg);
154: if (value == null)
155: return arg;
156: if (value instanceof Double) {
157: double val = ((Double) value).doubleValue();
158: if (val >= -0.5 && val <= 0.0
159: && (val < 0.0 || Double.doubleToLongBits(val) < 0))
160: val = -0.0;
161: else
162: val = Math.floor(val + 0.5);
163: return XDataType.makeDouble(val);
164: }
165: if (value instanceof Float) {
166: float val = ((Float) value).floatValue();
167: if (val >= -0.5 && val <= 0.0
168: && (val < 0.0 || Float.floatToIntBits(val) < 0))
169: val = (float) (-0.0);
170: else
171: val = (float) Math.floor(val + 0.5);
172: return XDataType.makeFloat(val);
173: }
174: if (value instanceof BigDecimal) {
175: BigDecimal dec = (BigDecimal) value;
176: int mode = dec.signum() >= 0 ? BigDecimal.ROUND_HALF_UP
177: : BigDecimal.ROUND_HALF_DOWN;
178: dec = dec.divide(XDataType.DECIMAL_ONE, 0, mode);
179: return Arithmetic.asIntNum(dec.toBigInteger());
180: }
181: return ((RealNum) value).toInt(Numeric.ROUND);
182: }
183:
184: public static Object roundHalfToEven(Object value, IntNum precision) {
185: Number number = numberCast(value);
186: if (number == null)
187: return value;
188: BigDecimal dec = (BigDecimal) XDataType.decimalType
189: .cast(number);
190: int prec = precision.intValue();
191: /* #ifndef JAVA5 */
192: if (prec < 0) {
193: BigDecimal power = null;
194: int shift = -prec;
195: if (shift >= 6) {
196: BigDecimal million = BigDecimal.valueOf(1000000);
197: power = million;
198: while ((shift -= 6) >= 6)
199: power = power.multiply(million);
200: }
201: if (shift > 0) {
202: int i = 10;
203: while (--shift > 0)
204: i = 10 * i;
205: BigDecimal tens = BigDecimal.valueOf(i);
206: power = power == null ? tens : power.multiply(tens);
207: }
208: dec = dec.divide(power, 0, BigDecimal.ROUND_HALF_EVEN);
209: dec = dec.multiply(power);
210: } else
211: /* #endif */
212: dec = dec.setScale(prec, BigDecimal.ROUND_HALF_EVEN);
213: if (number instanceof Double)
214: return XDataType.makeDouble(dec.doubleValue());
215: if (number instanceof Float)
216: return XDataType.makeFloat(dec.floatValue());
217: if (number instanceof IntNum)
218: return XIntegerType.integerType.cast(dec);
219: return dec;
220: }
221:
222: public static Object roundHalfToEven(Object value) {
223: return roundHalfToEven(value, IntNum.zero());
224: }
225: }
|