KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > xquery > util > ArithOp


1 package gnu.xquery.util;
2 import gnu.bytecode.*;
3 import gnu.mapping.*;
4 import gnu.expr.*;
5 import gnu.xml.TextUtils;
6 import gnu.kawa.xml.*;
7 import gnu.kawa.functions.*;
8 import java.math.*;
9 import gnu.math.*;
10
11 public class ArithOp extends Procedure1or2
12   implements CanInline, Inlineable
13 {
14   char op;
15
16   static final BigInteger TEN = BigInteger.valueOf(10);
17
18   public static final ArithOp add = new ArithOp("+", '+', 2);
19   public static final ArithOp sub = new ArithOp("-", '-', 2);
20   public static final ArithOp mul = new ArithOp("*", '*', 2);
21   public static final ArithOp div = new ArithOp("div", 'd', 2);
22   public static final ArithOp idiv = new ArithOp("idiv", 'i', 2);
23   public static final ArithOp mod = new ArithOp("mod", 'm', 2);
24   public static final ArithOp plus = new ArithOp("+", 'P', 1);
25   public static final ArithOp minus = new ArithOp("-", 'M', 1);
26
27   ArithOp (String JavaDoc name, char op, int nargs)
28   {
29     super(name);
30     this.op = op;
31   }
32
33   public Object JavaDoc apply1 (Object JavaDoc arg1)
34     throws java.lang.Throwable JavaDoc
35   {
36     if (arg1 == Values.empty || arg1 == null)
37       return arg1;
38     if (arg1 instanceof KNode || arg1 instanceof UntypedAtomic)
39       arg1 = XDataType.doubleType.valueOf(TextUtils.stringValue(arg1));
40     switch (op)
41       {
42       case 'P':
43         return AddOp.apply2(1, gnu.math.IntNum.zero(), arg1);
44       case 'M':
45         int code1 = Arithmetic.classifyValue(arg1);
46         switch (code1)
47           {
48           case Arithmetic.FLOAT_CODE:
49             return XDataType.makeFloat(- Arithmetic.asFloat(arg1));
50           case Arithmetic.DOUBLE_CODE:
51             return XDataType.makeDouble(- Arithmetic.asDouble(arg1));
52           default:
53             if (arg1 instanceof Numeric)
54               return ((Numeric) arg1).neg();
55             return AddOp.apply2(-1, gnu.math.IntNum.zero(), arg1);
56           }
57       }
58     throw new UnsupportedOperationException JavaDoc(getName());
59   }
60
61   public static BigDecimal div (BigDecimal d1, BigDecimal d2)
62   {
63     /* #ifdef JAVA5 */
64     // return d1.divide(d2, MathContext.DECIMAL128);
65
/* #else */
66     BigDecimal d = d1.divide(d2, 18, BigDecimal.ROUND_HALF_EVEN);
67     /* #ifdef JAVA2 */
68     BigInteger unscaled = d.unscaledValue();
69     if (unscaled.signum() == 0)
70       return BigDecimal.valueOf(0);
71     int sc = 0;
72     while (sc < 18)
73       {
74         BigInteger[] divmod = unscaled.divideAndRemainder(TEN);
75         if (divmod[1].signum() != 0)
76           break;
77         sc++;
78         unscaled = divmod[0];
79       }
80     return sc == 0 ? d : new BigDecimal(unscaled, d.scale() - sc);
81     /* #endif */
82     /* #endif */
83   }
84
85   public Object JavaDoc apply2 (Object JavaDoc arg1, Object JavaDoc arg2)
86     throws java.lang.Throwable JavaDoc
87   {
88     if (arg1 == Values.empty || arg1 == null)
89       return arg1;
90     if (arg2 == Values.empty || arg2 == null)
91       return arg2;
92     if (arg1 instanceof KNode || arg1 instanceof UntypedAtomic)
93       arg1 = XDataType.doubleType.valueOf(TextUtils.stringValue(arg1));
94     if (arg2 instanceof KNode || arg2 instanceof UntypedAtomic)
95       arg2 = XDataType.doubleType.valueOf(TextUtils.stringValue(arg2));
96     switch (op)
97       {
98       case '+':
99         return AddOp.apply2(1, arg1, arg2);
100       case '-':
101         return AddOp.apply2(-1, arg1, arg2);
102       case '*':
103         return MultiplyOp.$St.apply2(arg1, arg2);
104       }
105     int code1 = Arithmetic.classifyValue(arg1);
106     int code2 = Arithmetic.classifyValue(arg2);
107     int code = code1 < code2 ? code2 : code1;
108     switch (op)
109       {
110       case 'd': // 'div'
111
if (code1 < 0 || code2 < 0)
112           break;
113         else if (code <= Arithmetic.RATNUM_CODE)
114           {
115             BigDecimal d1 = (BigDecimal) XDataType.decimalType.cast(arg1);
116             // OR: d1 = Arithmetic.asBigDecimal(arg1);
117
BigDecimal d2 = (BigDecimal) XDataType.decimalType.cast(arg2);
118             // OR: d2 = Arithmetic.asBigDecimal(arg2);
119
return div(d1, d2);
120           }
121         else if (code == Arithmetic.FLOAT_CODE)
122           {
123             return new Float JavaDoc(((Number JavaDoc) arg1).floatValue()
124                              / ((Number JavaDoc) arg2).floatValue());
125           }
126         else if (code == Arithmetic.DOUBLE_CODE)
127           {
128             return new Double JavaDoc(((Number JavaDoc) arg1).doubleValue()
129                              / ((Number JavaDoc) arg2).doubleValue());
130           }
131         else if (arg1 instanceof Duration && arg2 instanceof Duration)
132           {
133             Duration dur1 = (Duration) arg1;
134             Duration dur2 = (Duration) arg2;
135             if (dur1.unit() == Unit.second && dur2.unit() == Unit.second)
136               {
137                 long s1 = dur1.getTotalSeconds();
138                 long s2 = dur2.getTotalSeconds();
139                 int n1 = dur1.getNanoSecondsOnly();
140                 int n2 = dur2.getNanoSecondsOnly();
141                 BigDecimal sec1 = TimeUtils.secondsBigDecimalFromDuration(s1, n1);
142                 BigDecimal sec2 = TimeUtils.secondsBigDecimalFromDuration(s2, n2);
143                 return div(sec1, sec2);
144               }
145             if (dur1.unit() == Unit.month && dur2.unit() == Unit.month)
146               {
147                 BigDecimal m1 = BigDecimal.valueOf(dur1.getTotalMonths());
148                 BigDecimal m2 = BigDecimal.valueOf(dur2.getTotalMonths());
149                 return div(m1, m2);
150               }
151             throw new ArithmeticException JavaDoc("divide of incompatible durations");
152           }
153         else if (code >= 0)
154           return Arithmetic.asNumeric(arg1).div(Arithmetic.asNumeric(arg2));
155       case 'i': // 'idiv'
156
if (code1 < 0 || code2 < 0)
157           break;
158         else if (code <= Arithmetic.INTNUM_CODE)
159           {
160             IntNum i1 = Arithmetic.asIntNum(arg1);
161             IntNum i2 = Arithmetic.asIntNum(arg2);
162             return IntNum.quotient(i1, i2);
163           }
164         else if (code <= Arithmetic.RATNUM_CODE)
165           {
166             BigDecimal d1 = (BigDecimal) XDataType.decimalType.cast(arg1);
167             // OR: d1 = Arithmetic.asBigDecimal(arg1);
168
BigDecimal d2 = (BigDecimal) XDataType.decimalType.cast(arg2);
169             // OR: d2 = Arithmetic.asBigDecimal(arg2);
170
return Arithmetic.asIntNum(d1.divide(d2, 0,
171                                                  BigDecimal.ROUND_DOWN));
172           }
173         else if (code <= Arithmetic.FLOAT_CODE)
174           {
175             float f
176               = ((Number JavaDoc) arg1).floatValue() / ((Number JavaDoc) arg2).floatValue();
177             return RealNum.toExactInt((double) f, RealNum.TRUNCATE);
178           }
179         else
180           {
181             double d
182               = ((Number JavaDoc) arg1).doubleValue() / ((Number JavaDoc) arg2).doubleValue();
183             return RealNum.toExactInt(d, RealNum.TRUNCATE);
184           }
185       case 'm': // 'mod'
186
if (code1 < 0 || code2 < 0)
187           break;
188         else if (code <= Arithmetic.INTNUM_CODE)
189           {
190             IntNum i1 = Arithmetic.asIntNum(arg1);
191             IntNum i2 = Arithmetic.asIntNum(arg2);
192             return IntNum.remainder(i1, i2);
193           }
194         else if (code <= Arithmetic.RATNUM_CODE)
195           {
196             return sub.apply2(arg1, mul.apply2(idiv.apply2(arg1, arg2), arg2));
197           }
198         else if (code <= Arithmetic.FLOAT_CODE)
199           {
200             float f1 = Arithmetic.asFloat(arg1);
201             float f2 = Arithmetic.asFloat(arg2);
202             return gnu.kawa.xml.XDataType.makeFloat(f1 % f2);
203           }
204         else if (code <= Arithmetic.FLONUM_CODE)
205           {
206             double d1 = Arithmetic.asDouble(arg1);
207             double d2 = Arithmetic.asDouble(arg2);
208             double d = d1 % d2;
209             if (code == Arithmetic.FLONUM_CODE)
210               return DFloNum.make(d);
211             else
212               return gnu.kawa.xml.XDataType.makeDouble(d);
213           }
214       }
215     throw new UnsupportedOperationException JavaDoc(getName());
216   }
217
218   public Expression inline (ApplyExp exp, ExpWalker walker)
219   {
220     // FUTURE
221
return exp;
222   }
223
224   public void compile (ApplyExp exp, Compilation comp, Target target)
225   {
226     // FUTURE
227
ApplyExp.compile(exp, comp, target);
228   }
229
230   public Type getReturnType (Expression[] args)
231   {
232     return Type.pointer_type;
233   }
234 }
235
Popular Tags