KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > kawa > functions > NumberCompare


1 package gnu.kawa.functions;
2 import gnu.math.*;
3 import gnu.mapping.*;
4 import gnu.bytecode.*;
5 import gnu.expr.*;
6 import java.math.*;
7
8 /** This implements the numeric comparison relations: <, <=, etc. */
9
10 public class NumberCompare extends ProcedureN implements CanInline, Inlineable
11 {
12   Language language;
13
14   // Return codes from Numeric.compare:
15
static final int RESULT_GRT = 1;
16   static final int RESULT_EQU = 0;
17   static final int RESULT_LSS = -1;
18   static final int RESULT_NAN = -2;
19   static final int RESULT_NEQ = -3;
20
21   // One flag bit for each of the above RESULT_XXX codes:
22
public static final int TRUE_IF_GRT = 1 << (RESULT_GRT + 3);
23   public static final int TRUE_IF_EQU = 1 << (RESULT_EQU + 3);
24   public static final int TRUE_IF_LSS = 1 << (RESULT_LSS + 3);
25   public static final int TRUE_IF_NAN = 1 << (RESULT_NAN + 3);
26   public static final int TRUE_IF_NEQ = 1 << (RESULT_NEQ + 3);
27   int flags;
28
29   public int numArgs() { return (-1 << 12) | 2; }
30
31   public static boolean $Eq(Object JavaDoc arg1, Object JavaDoc arg2)
32   {
33     return apply2(TRUE_IF_EQU, arg1, arg2);
34   }
35
36   public static boolean $Gr(Object JavaDoc arg1, Object JavaDoc arg2)
37   {
38     return apply2(TRUE_IF_GRT, arg1, arg2);
39   }
40
41   public static boolean $Gr$Eq(Object JavaDoc arg1, Object JavaDoc arg2)
42   {
43     return apply2(TRUE_IF_GRT|TRUE_IF_EQU, arg1, arg2);
44   }
45
46   public static boolean $Ls(Object JavaDoc arg1, Object JavaDoc arg2)
47   {
48     return apply2(TRUE_IF_LSS, arg1, arg2);
49   }
50
51   public static boolean $Ls$Eq(Object JavaDoc arg1, Object JavaDoc arg2)
52   {
53     return apply2(TRUE_IF_LSS|TRUE_IF_EQU, arg1, arg2);
54   }
55  
56   public static boolean $Eq$V (Object JavaDoc arg1, Object JavaDoc arg2,
57                    Object JavaDoc arg3, Object JavaDoc[] rest)
58   {
59     return ($Eq(arg1, arg2) && $Eq(arg2, arg3)
60         && (rest.length == 0
61         || ($Eq(arg3, rest[0]) && applyN(TRUE_IF_EQU, rest))));
62   }
63
64   public static boolean $Gr$V (Object JavaDoc arg1, Object JavaDoc arg2,
65                    Object JavaDoc arg3, Object JavaDoc[] rest)
66   {
67     return ($Gr(arg1, arg2) && $Gr(arg2, arg3)
68         && (rest.length == 0
69         || ($Gr(arg3, rest[0]) && applyN(TRUE_IF_GRT, rest))));
70   }
71
72   public static boolean $Gr$Eq$V (Object JavaDoc arg1, Object JavaDoc arg2,
73                    Object JavaDoc arg3, Object JavaDoc[] rest)
74   {
75     return ($Gr$Eq(arg1, arg2) && $Gr$Eq(arg2, arg3)
76         && (rest.length == 0
77         || ($Gr$Eq(arg3, rest[0])
78             && applyN(TRUE_IF_GRT|TRUE_IF_EQU, rest))));
79   }
80
81   public static boolean $Ls$V (Object JavaDoc arg1, Object JavaDoc arg2,
82                    Object JavaDoc arg3, Object JavaDoc[] rest)
83   {
84     return ($Ls(arg1, arg2) && $Ls(arg2, arg3)
85         && (rest.length == 0
86         || ($Ls(arg3, rest[0]) && applyN(TRUE_IF_LSS, rest))));
87   }
88
89   public static boolean $Ls$Eq$V (Object JavaDoc arg1, Object JavaDoc arg2,
90                    Object JavaDoc arg3, Object JavaDoc[] rest)
91   {
92     return ($Ls$Eq(arg1, arg2) && $Ls$Eq(arg2, arg3)
93         && (rest.length == 0
94         || ($Ls$Eq(arg3, rest[0])
95             && applyN(TRUE_IF_LSS|TRUE_IF_EQU, rest))));
96   }
97
98   public static NumberCompare make(Language language, String JavaDoc name, int flags)
99   {
100     NumberCompare proc = new NumberCompare();
101     proc.language = language;
102     proc.setName(name);
103     proc.flags = flags;
104     return proc;
105   }
106
107   protected final Language getLanguage ()
108   {
109     return language;
110   }
111
112   public Object JavaDoc apply2 (Object JavaDoc arg1, Object JavaDoc arg2)
113   {
114     return getLanguage().booleanObject(apply2(flags, arg1, arg2));
115   }
116
117   static public boolean apply2 (int flags, Object JavaDoc arg1, Object JavaDoc arg2)
118   {
119     return ((1 << (3 + compare(arg1, arg2, true))) & flags) != 0;
120   }
121   
122   public static boolean checkCompareCode (int code, int flags)
123   {
124     return ((1 << (3 + code)) & flags) != 0;
125   }
126
127   static public boolean applyWithPromotion (int flags, Object JavaDoc arg1, Object JavaDoc arg2)
128   {
129     return checkCompareCode(compare(arg1, arg2, false), flags);
130   }
131   
132   /** Compare two numbers.
133    * @param exact true if we should compare exact/inexact numbers exactly
134    * (by converting the inexact number to exact), or inexactly (by
135    * "promoting" the exact to inexact) (as required for XQuery).
136    * @return 1 if {@code arg1>arg2}; 0 if {@code arg1==arg2};
137    * -1 if {@code arg1<arg2}; -2 if either is {@code NaN};
138    * -3 if not comparable (either is not a number). */

139   static public int compare (Object JavaDoc arg1, Object JavaDoc arg2, boolean exact)
140   {
141     int code1 = Arithmetic.classifyValue(arg1);
142     int code2 = Arithmetic.classifyValue(arg2);
143     return compare(arg1, code1, arg2, code2, exact);
144   }
145
146   static public int compare (Object JavaDoc arg1, int code1,
147                              Object JavaDoc arg2, int code2,
148                              boolean exact)
149   {
150     if (code1 < 0 || code2 < 0)
151       return -3;
152     int code = code1 < code2 ? code2 : code1;
153     int comp; // A Numeric.compare return code: -1, 0, 1, or rarely: -2, or -3.
154
switch (code)
155       {
156       case Arithmetic.INT_CODE:
157     int i1 = Arithmetic.asInt(arg1);
158     int i2 = Arithmetic.asInt(arg2);
159         comp = i1 < i2 ? -1 : i1 > i2 ? 1 : 0;
160     break;
161       case Arithmetic.LONG_CODE:
162     long l1 = Arithmetic.asLong(arg1);
163     long l2 = Arithmetic.asLong(arg2);
164         comp = l1 < l2 ? -1 : l1 > l2 ? 1 : 0;
165         break;
166       case Arithmetic.BIGINTEGER_CODE:
167     BigInteger bi1 = Arithmetic.asBigInteger(arg1);
168     BigInteger bi2 = Arithmetic.asBigInteger(arg2);
169     comp = bi1.compareTo(bi2);
170         break;
171       case Arithmetic.INTNUM_CODE:
172     comp = IntNum.compare(Arithmetic.asIntNum(arg1),
173                               Arithmetic.asIntNum(arg2));
174         break;
175       case Arithmetic.BIGDECIMAL_CODE:
176     BigDecimal bd1 = Arithmetic.asBigDecimal(arg1);
177     BigDecimal bd2 = Arithmetic.asBigDecimal(arg2);
178     comp = bd1.compareTo(bd2);
179         break;
180       case Arithmetic.RATNUM_CODE:
181     comp = RatNum.compare(Arithmetic.asRatNum(arg1),
182                               Arithmetic.asRatNum(arg2));
183         break;
184       case Arithmetic.FLOAT_CODE:
185         if (! exact
186             || (code1 > Arithmetic.RATNUM_CODE
187                 && code2 > Arithmetic.RATNUM_CODE))
188           {
189             float f1 = Arithmetic.asFloat(arg1);
190             float f2 = Arithmetic.asFloat(arg2);
191             comp = f1 > f2 ? 1 : f1 < f2 ? -1 : f1 == f2 ? 0 : -2;
192             break;
193           }
194         // else fall through, to handle exact-inexact comparison
195
case Arithmetic.DOUBLE_CODE:
196       case Arithmetic.FLONUM_CODE:
197         if (! exact
198             || (code1 > Arithmetic.RATNUM_CODE
199                 && code2 > Arithmetic.RATNUM_CODE))
200           {
201             double d1 = Arithmetic.asDouble(arg1);
202             double d2 = Arithmetic.asDouble(arg2);
203             comp = d1 > d2 ? 1 : d1 < d2 ? -1 : d1 == d2 ? 0 : -2;
204             break;
205           }
206         // else fall through, to handle exact-inexact comparison
207
default:
208     Numeric num1 = Arithmetic.asNumeric(arg1);
209     Numeric num2 = Arithmetic.asNumeric(arg2);
210         comp = ((Numeric) num1).compare(num2);
211       }
212     return comp;
213   }
214
215   static boolean applyN (int flags, Object JavaDoc[] args)
216   {
217     // if (args.length < 2)
218
// throw new WrongArguments(this.name(),2,"(< x1 x2 ...)");
219
for (int i = 0; i < args.length - 1; i++)
220       {
221     Object JavaDoc arg1 = args[i];
222     Object JavaDoc arg2 = args[i+1];
223     if (! apply2(flags, arg1, arg2))
224       return false;
225       }
226     return true;
227   }
228
229   public Object JavaDoc applyN (Object JavaDoc[] args)
230   {
231     // if (args.length < 2)
232
// throw new WrongArguments(this.name(),2,"(< x1 x2 ...)");
233
return getLanguage().booleanObject(applyN(flags, args));
234   }
235
236   public Expression inline (ApplyExp exp, ExpWalker walker)
237   {
238     Expression folded = exp.inlineIfConstant(this, walker);
239     if (folded != exp)
240       return folded;
241     return exp;
242   }
243
244   public void compile (ApplyExp exp, Compilation comp, Target target)
245   {
246     Expression[] args = exp.getArgs();
247     if (args.length == 2)
248       {
249     Expression arg0 = args[0];
250     Expression arg1 = args[1];
251     int kind0 = classify(arg0);
252     int kind1 = classify(arg1);
253     CodeAttr code = comp.getCode();
254     if (kind0 >= RealNum_KIND && kind1 >= RealNum_KIND
255         // Don't optimize if both operands are fractions.
256
&& (kind0 != RealNum_KIND || kind1 != RealNum_KIND))
257       {
258         if (! (target instanceof ConditionalTarget))
259           {
260         IfExp.compile(exp, QuoteExp.trueExp, QuoteExp.falseExp,
261                   comp, target);
262         return;
263           }
264         int mask = flags;
265         if (mask == TRUE_IF_NEQ)
266           mask = TRUE_IF_GRT|TRUE_IF_LSS;
267         if (kind0 >= IntNum_KIND && kind1 >= IntNum_KIND
268         && (kind0 < long_KIND || kind1 < long_KIND))
269           {
270         Type[] ctypes = new Type[2];
271         ctypes[0] = AddOp.typeIntNum;
272         if (kind1 >= long_KIND)
273           {
274             ctypes[1] = Type.long_type;
275           }
276         else if (kind0 >= long_KIND
277              // Simple check to avoid re-ordering side-effects.
278
&& (arg0 instanceof QuoteExp
279                  || arg1 instanceof QuoteExp
280                  || arg0 instanceof ReferenceExp
281                  || arg1 instanceof ReferenceExp))
282           {
283             ctypes[1] = Type.long_type;
284             args = new Expression[2];
285             args[0] = arg1;
286             args[1] = arg0;
287             if (mask != TRUE_IF_EQU && mask != TRUE_IF_GRT+TRUE_IF_LSS)
288               mask ^= TRUE_IF_GRT|TRUE_IF_LSS;
289           }
290         else
291           ctypes[1] = AddOp.typeIntNum;
292         Method cmeth
293           = AddOp.typeIntNum.getDeclaredMethod("compare", ctypes);
294         PrimProcedure compare = new PrimProcedure(cmeth);
295         arg0 = new ApplyExp(compare, args);
296         arg1 = new QuoteExp(IntNum.zero());
297         kind0 = kind1 = int_KIND;
298           }
299         Type commonType;
300         if (kind0 >= int_KIND && kind1 >= int_KIND)
301           commonType = Type.int_type;
302         else if (kind0 >= long_KIND && kind1 >= long_KIND)
303           commonType = Type.long_type;
304         else
305           commonType = Type.double_type;
306         StackTarget subTarget = new StackTarget(commonType);
307         ConditionalTarget ctarget = (ConditionalTarget) target;
308         
309         int opcode;
310         if (arg0 instanceof QuoteExp && ! (arg1 instanceof QuoteExp))
311           {
312         Expression tmp = arg1; arg1 = arg0; arg0 = tmp;
313         if (mask != TRUE_IF_EQU && mask != TRUE_IF_GRT+TRUE_IF_LSS)
314           mask ^= TRUE_IF_GRT|TRUE_IF_LSS;
315           }
316         Label label1 = ctarget.trueBranchComesFirst ? ctarget.ifFalse : ctarget.ifTrue;
317         if (ctarget.trueBranchComesFirst)
318           mask ^= TRUE_IF_GRT|TRUE_IF_LSS|TRUE_IF_EQU;
319         switch (mask)
320           {
321           case TRUE_IF_GRT: opcode = 157 /*ifgt*/; break;
322           case TRUE_IF_EQU: opcode = 153 /*ifeq*/; break;
323           case TRUE_IF_LSS: opcode = 155 /*iflt*/; break;
324           case TRUE_IF_GRT|TRUE_IF_LSS: opcode = 154 /*ifne*/; break;
325           case TRUE_IF_GRT|TRUE_IF_EQU: opcode = 156 /*ifge*/; break;
326           case TRUE_IF_LSS|TRUE_IF_EQU: opcode = 158 /*ifle*/; break;
327           default:
328         opcode = 0;
329           }
330         arg0.compile(comp, subTarget);
331         Object JavaDoc value;
332         if (kind0 >= int_KIND && kind1 >= int_KIND
333         && arg1 instanceof QuoteExp
334         && (value = ((QuoteExp) arg1).getValue()) instanceof IntNum
335         && ((IntNum) value).isZero())
336           {
337         code.emitGotoIfCompare1(label1, opcode);
338           }
339         else
340           {
341         arg1.compile(comp, subTarget);
342         code.emitGotoIfCompare2(label1, opcode);
343           }
344         ctarget.emitGotoFirstBranch(code);
345         return;
346       }
347       }
348     ApplyExp.compile(exp, comp, target);
349   }
350
351   // Return a code indicate type of number:
352
private static final int Unknown_KIND = 0; // unknown or invalid type
353
private static final int Number_KIND = 1; // java.lang.Number - not used
354
private static final int Numeric_KIND = 2; // gnu.math.Numeric
355
private static final int RealNum_KIND = 3; // exact or unknown real
356
private static final int double_KIND = 4; // inexact real (double or DFloNum)
357
private static final int IntNum_KIND = 5; // gnu.math.IntNum
358
private static final int long_KIND = 6; // long
359
private static final int int_KIND = 7; // int
360

361   static int classify (Expression exp)
362   {
363     Type type = exp.getType();
364     int kind = classify(type);
365     Object JavaDoc value;
366     if (kind == IntNum_KIND && exp instanceof QuoteExp
367     && (value = ((QuoteExp) exp).getValue()) instanceof IntNum)
368       {
369     int ilength = ((IntNum) value).intLength();
370     if (ilength < 32)
371       return int_KIND;
372     if (ilength < 64)
373       return long_KIND;
374       }
375     return kind;
376   }
377
378   static int classify (Type type)
379   {
380     if (type instanceof PrimType)
381       {
382     char sig = type.getSignature().charAt(0);
383     if (sig == 'V' || sig == 'Z' || sig == 'C')
384       return Unknown_KIND;
385     if (sig == 'D' || sig == 'F')
386       return double_KIND;
387     if (sig == 'J')
388       return long_KIND;
389     return int_KIND;
390       }
391      if (type.isSubtype(AddOp.typeIntNum))
392        return IntNum_KIND;
393      if (type.isSubtype(AddOp.typeDFloNum))
394        return double_KIND;
395      if (type.isSubtype(AddOp.typeRealNum))
396        return RealNum_KIND;
397      if (type.isSubtype(AddOp.typeNumeric))
398        return Numeric_KIND;
399     return Unknown_KIND;
400   }
401
402   public Type getReturnType (Expression[] args)
403   {
404     return Compilation.scmBooleanType;
405   }
406 }
407
Popular Tags