KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > armedbear > lisp > Ratio


1 /*
2  * Ratio.java
3  *
4  * Copyright (C) 2003-2004 Peter Graves
5  * $Id: Ratio.java,v 1.46 2004/07/29 23:25:47 piso Exp $
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
20  */

21
22 package org.armedbear.lisp;
23
24 import java.math.BigInteger JavaDoc;
25
26 public final class Ratio extends LispObject
27 {
28     private BigInteger JavaDoc numerator;
29     private BigInteger JavaDoc denominator;
30
31     public Ratio(BigInteger JavaDoc numerator, BigInteger JavaDoc denominator)
32     {
33         this.numerator = numerator;
34         this.denominator = denominator;
35     }
36
37     public BigInteger JavaDoc numerator()
38     {
39         return numerator;
40     }
41
42     public LispObject NUMERATOR()
43     {
44         return number(numerator);
45     }
46
47     public BigInteger JavaDoc denominator()
48     {
49         return denominator;
50     }
51
52     public LispObject DENOMINATOR()
53     {
54         return number(denominator);
55     }
56
57     public LispObject typeOf()
58     {
59         return Symbol.RATIO;
60     }
61
62     public LispClass classOf()
63     {
64         return BuiltInClass.RATIO;
65     }
66
67     public LispObject typep(LispObject type) throws ConditionThrowable
68     {
69         if (type == Symbol.RATIO)
70             return T;
71         if (type == Symbol.RATIONAL)
72             return T;
73         if (type == Symbol.REAL)
74             return T;
75         if (type == Symbol.NUMBER)
76             return T;
77         if (type == BuiltInClass.RATIO)
78             return T;
79         return super.typep(type);
80     }
81
82     public LispObject NUMBERP()
83     {
84         return T;
85     }
86
87     public boolean numberp()
88     {
89         return true;
90     }
91
92     public boolean rationalp()
93     {
94         return true;
95     }
96
97     public boolean realp()
98     {
99         return true;
100     }
101
102     public boolean eql(LispObject obj)
103     {
104         if (this == obj)
105             return true;
106         if (obj instanceof Ratio) {
107             return numerator.equals(((Ratio)obj).numerator) &&
108                 denominator.equals(((Ratio)obj).denominator);
109         }
110         return false;
111     }
112
113     public boolean equal(LispObject obj)
114     {
115         return eql(obj);
116     }
117
118     public boolean equalp(LispObject obj)
119     {
120         if (obj instanceof Ratio) {
121             return numerator.equals(((Ratio)obj).numerator) &&
122                 denominator.equals(((Ratio)obj).denominator);
123         }
124         if (obj instanceof LispFloat) {
125             return floatValue() == ((LispFloat)obj).getValue();
126         }
127         return false;
128     }
129
130     public LispObject ABS()
131     {
132         if (numerator.signum() > 0 && denominator.signum() > 0)
133             return this;
134         if (numerator.signum() < 0 && denominator.signum() < 0)
135             return this;
136         return new Ratio(numerator.negate(), denominator);
137     }
138
139     public boolean plusp()
140     {
141         return numerator.signum() == denominator.signum();
142     }
143
144     public boolean minusp()
145     {
146         return numerator.signum() != denominator.signum();
147     }
148
149     public boolean zerop()
150     {
151         return false;
152     }
153
154     public double floatValue()
155     {
156         double result = numerator.doubleValue() / denominator.doubleValue();
157         if (result != 0 && !Double.isNaN(result) && !Double.isInfinite(result))
158             return result;
159         final boolean negative = numerator.signum() < 0;
160         final BigInteger JavaDoc num = negative ? numerator.negate() : numerator;
161         final BigInteger JavaDoc den = denominator;
162         final int numLen = num.bitLength();
163         final int denLen = den.bitLength();
164         int length = Math.min(numLen, denLen);
165         if (length <= 1)
166             return result;
167         BigInteger JavaDoc n = num;
168         BigInteger JavaDoc d = den;
169         final int digits = 54;
170         if (length > digits) {
171             n = n.shiftRight(length - digits);
172             d = d.shiftRight(length - digits);
173             length -= digits;
174         } else {
175             n = n.shiftRight(1);
176             d = d.shiftRight(1);
177             --length;
178         }
179         for (int i = 0; i < length; i++) {
180             result = n.doubleValue() / d.doubleValue();
181             if (result != 0 && !Double.isNaN(result) && !Double.isInfinite(result))
182                 break;
183             n = n.shiftRight(1);
184             d = d.shiftRight(1);
185         }
186         return negative ? -result : result;
187     }
188
189     public final LispObject incr() throws ConditionThrowable
190     {
191         return new Ratio(numerator.add(denominator), denominator);
192     }
193
194     public final LispObject decr() throws ConditionThrowable
195     {
196         return new Ratio(numerator.subtract(denominator), denominator);
197     }
198
199     public LispObject add(LispObject obj) throws ConditionThrowable
200     {
201         if (obj instanceof Fixnum) {
202             BigInteger JavaDoc n =
203                 numerator.add(BigInteger.valueOf(((Fixnum)obj).getValue()).multiply(denominator));
204             return number(n, denominator);
205         }
206         if (obj instanceof Bignum) {
207             BigInteger JavaDoc n = ((Bignum)obj).getValue();
208             return number(numerator.add(n.multiply(denominator)),
209                 denominator);
210         }
211         if (obj instanceof Ratio) {
212             BigInteger JavaDoc n = ((Ratio)obj).numerator;
213             BigInteger JavaDoc d = ((Ratio)obj).denominator;
214             if (denominator.equals(d))
215                 return number(numerator.add(n), denominator);
216             BigInteger JavaDoc common = denominator.multiply(d);
217             return number(numerator.multiply(d).add(n.multiply(denominator)),
218                 common);
219         }
220         if (obj instanceof LispFloat) {
221             return new LispFloat(floatValue() + ((LispFloat)obj).getValue());
222         }
223         if (obj instanceof Complex) {
224             Complex c = (Complex) obj;
225             return Complex.getInstance(add(c.getRealPart()), c.getImaginaryPart());
226         }
227         return signal(new TypeError(obj, "number"));
228     }
229
230     public LispObject subtract(LispObject obj) throws ConditionThrowable
231     {
232         if (obj instanceof Fixnum) {
233             BigInteger JavaDoc n =
234                 numerator.subtract(BigInteger.valueOf(((Fixnum)obj).getValue()).multiply(denominator));
235             return number(n, denominator);
236         }
237         if (obj instanceof Bignum) {
238             BigInteger JavaDoc n = ((Bignum)obj).getValue();
239             return number(numerator.subtract(n.multiply(denominator)),
240                 denominator);
241         }
242         if (obj instanceof Ratio) {
243             BigInteger JavaDoc n = ((Ratio)obj).numerator;
244             BigInteger JavaDoc d = ((Ratio)obj).denominator;
245             if (denominator.equals(d))
246                 return number(numerator.subtract(n), denominator);
247             BigInteger JavaDoc common = denominator.multiply(d);
248             return number(numerator.multiply(d).subtract(n.multiply(denominator)),
249                 common);
250         }
251         if (obj instanceof LispFloat) {
252             return new LispFloat(floatValue() - ((LispFloat)obj).getValue());
253         }
254         if (obj instanceof Complex) {
255             Complex c = (Complex) obj;
256             return Complex.getInstance(subtract(c.getRealPart()),
257                                        Fixnum.ZERO.subtract(c.getImaginaryPart()));
258         }
259         return signal(new TypeError(obj, "number"));
260     }
261
262     public LispObject multiplyBy(LispObject obj) throws ConditionThrowable
263     {
264         if (obj instanceof Fixnum) {
265             BigInteger JavaDoc n = ((Fixnum)obj).getBigInteger();
266             return number(numerator.multiply(n), denominator);
267         }
268         if (obj instanceof Bignum) {
269             BigInteger JavaDoc n = ((Bignum)obj).getValue();
270             return number(numerator.multiply(n), denominator);
271         }
272         if (obj instanceof Ratio) {
273             BigInteger JavaDoc n = ((Ratio)obj).numerator;
274             BigInteger JavaDoc d = ((Ratio)obj).denominator;
275             return number(numerator.multiply(n), denominator.multiply(d));
276         }
277         if (obj instanceof LispFloat) {
278             return new LispFloat(floatValue() * ((LispFloat)obj).getValue());
279         }
280         return signal(new TypeError(obj, "number"));
281     }
282
283     public LispObject divideBy(LispObject obj) throws ConditionThrowable
284     {
285         if (obj instanceof Fixnum) {
286             BigInteger JavaDoc n = ((Fixnum)obj).getBigInteger();
287             return number(numerator, denominator.multiply(n));
288         }
289         if (obj instanceof Bignum) {
290             BigInteger JavaDoc n = ((Bignum)obj).getValue();
291             return number(numerator, denominator.multiply(n));
292         }
293         if (obj instanceof Ratio) {
294             BigInteger JavaDoc n = ((Ratio)obj).numerator;
295             BigInteger JavaDoc d = ((Ratio)obj).denominator;
296             return number(numerator.multiply(d), denominator.multiply(n));
297         }
298         if (obj instanceof LispFloat) {
299             if (obj.zerop())
300                 return signal(new DivisionByZero());
301             return new LispFloat(floatValue() / ((LispFloat)obj).getValue());
302         }
303         return signal(new TypeError(obj, "number"));
304     }
305
306     public boolean isEqualTo(LispObject obj) throws ConditionThrowable
307     {
308         if (obj instanceof Ratio)
309             return (numerator.equals(((Ratio)obj).numerator) &&
310                     denominator.equals(((Ratio)obj).denominator));
311         if (obj instanceof LispFloat)
312             return isEqualTo(((LispFloat)obj).rational());
313         if (obj.numberp())
314             return false;
315         signal(new TypeError(obj, "number"));
316         // Not reached.
317
return false;
318     }
319
320     public boolean isNotEqualTo(LispObject obj) throws ConditionThrowable
321     {
322         return !isEqualTo(obj);
323     }
324
325     public boolean isLessThan(LispObject obj) throws ConditionThrowable
326     {
327         if (obj instanceof Fixnum) {
328             BigInteger JavaDoc n2 = ((Fixnum)obj).getBigInteger().multiply(denominator);
329             return numerator.compareTo(n2) < 0;
330         }
331         if (obj instanceof Bignum) {
332             BigInteger JavaDoc n = ((Bignum)obj).getValue().multiply(denominator);
333             return numerator.compareTo(n) < 0;
334         }
335         if (obj instanceof Ratio) {
336             BigInteger JavaDoc n1 = numerator.multiply(((Ratio)obj).denominator);
337             BigInteger JavaDoc n2 = ((Ratio)obj).numerator.multiply(denominator);
338             return n1.compareTo(n2) < 0;
339         }
340         if (obj instanceof LispFloat)
341             return isLessThan(((LispFloat)obj).rational());
342         signal(new TypeError(obj, Symbol.REAL));
343         // Not reached.
344
return false;
345     }
346
347     public boolean isGreaterThan(LispObject obj) throws ConditionThrowable
348     {
349         if (obj instanceof Fixnum) {
350             BigInteger JavaDoc n2 = ((Fixnum)obj).getBigInteger().multiply(denominator);
351             return numerator.compareTo(n2) > 0;
352         }
353         if (obj instanceof Bignum) {
354             BigInteger JavaDoc n = ((Bignum)obj).getValue().multiply(denominator);
355             return numerator.compareTo(n) > 0;
356         }
357         if (obj instanceof Ratio) {
358             BigInteger JavaDoc n1 = numerator.multiply(((Ratio)obj).denominator);
359             BigInteger JavaDoc n2 = ((Ratio)obj).numerator.multiply(denominator);
360             return n1.compareTo(n2) > 0;
361         }
362         if (obj instanceof LispFloat)
363             return isGreaterThan(((LispFloat)obj).rational());
364         signal(new TypeError(obj, Symbol.REAL));
365         // Not reached.
366
return false;
367     }
368
369     public boolean isLessThanOrEqualTo(LispObject obj) throws ConditionThrowable
370     {
371         if (obj instanceof Fixnum) {
372             BigInteger JavaDoc n2 = ((Fixnum)obj).getBigInteger().multiply(denominator);
373             return numerator.compareTo(n2) <= 0;
374         }
375         if (obj instanceof Bignum) {
376             BigInteger JavaDoc n = ((Bignum)obj).getValue().multiply(denominator);
377             return numerator.compareTo(n) <= 0;
378         }
379         if (obj instanceof Ratio) {
380             BigInteger JavaDoc n1 = numerator.multiply(((Ratio)obj).denominator);
381             BigInteger JavaDoc n2 = ((Ratio)obj).numerator.multiply(denominator);
382             return n1.compareTo(n2) <= 0;
383         }
384         if (obj instanceof LispFloat)
385             return isLessThanOrEqualTo(((LispFloat)obj).rational());
386         signal(new TypeError(obj, Symbol.REAL));
387         // Not reached.
388
return false;
389     }
390
391     public boolean isGreaterThanOrEqualTo(LispObject obj) throws ConditionThrowable
392     {
393         if (obj instanceof Fixnum) {
394             BigInteger JavaDoc n2 = ((Fixnum)obj).getBigInteger().multiply(denominator);
395             return numerator.compareTo(n2) >= 0;
396         }
397         if (obj instanceof Bignum) {
398             BigInteger JavaDoc n = ((Bignum)obj).getValue().multiply(denominator);
399             return numerator.compareTo(n) >= 0;
400         }
401         if (obj instanceof Ratio) {
402             BigInteger JavaDoc n1 = numerator.multiply(((Ratio)obj).denominator);
403             BigInteger JavaDoc n2 = ((Ratio)obj).numerator.multiply(denominator);
404             return n1.compareTo(n2) >= 0;
405         }
406         if (obj instanceof LispFloat)
407             return isGreaterThanOrEqualTo(((LispFloat)obj).rational());
408         signal(new TypeError(obj, Symbol.REAL));
409         // Not reached.
410
return false;
411     }
412
413     public LispObject truncate(LispObject obj) throws ConditionThrowable
414     {
415         if (obj instanceof LispFloat)
416             return new LispFloat(floatValue()).truncate(obj);
417         BigInteger JavaDoc n, d;
418     try {
419       if (obj instanceof Fixnum) {
420             n = ((Fixnum)obj).getBigInteger();
421             d = BigInteger.ONE;
422       } else if (obj instanceof Bignum) {
423             n = ((Bignum)obj).getValue();
424             d = BigInteger.ONE;
425       } else if (obj instanceof Ratio) {
426             n = ((Ratio)obj).numerator();
427             d = ((Ratio)obj).denominator();
428       } else {
429             return signal(new TypeError(obj, "number"));
430       }
431       // Invert and multiply.
432
BigInteger JavaDoc num = numerator.multiply(d);
433       BigInteger JavaDoc den = denominator.multiply(n);
434       BigInteger JavaDoc quotient = num.divide(den);
435       // Multiply quotient by divisor.
436
LispObject product = number(quotient.multiply(n), d);
437       // Subtract to get remainder.
438
LispObject remainder = subtract(product);
439           return LispThread.currentThread().setValues(number(quotient), remainder);
440         }
441         catch (ArithmeticException JavaDoc e) {
442             if (obj.zerop())
443                 return signal(new DivisionByZero());
444             return signal(new ArithmeticError(e.getMessage()));
445         }
446     }
447
448     public int hashCode()
449     {
450         return numerator.hashCode() ^ denominator.hashCode();
451     }
452
453     public String JavaDoc writeToString() throws ConditionThrowable
454     {
455         final LispThread thread = LispThread.currentThread();
456         int base = Fixnum.getValue(_PRINT_BASE_.symbolValue(thread));
457         StringBuffer JavaDoc sb = new StringBuffer JavaDoc(numerator.toString(base));
458         sb.append('/');
459         sb.append(denominator.toString(base));
460         String JavaDoc s = sb.toString().toUpperCase();
461         if (_PRINT_RADIX_.symbolValue(thread) != NIL) {
462             sb.setLength(0);
463             switch (base) {
464                 case 2:
465                     sb.append("#b");
466                     sb.append(s);
467                     break;
468                 case 8:
469                     sb.append("#o");
470                     sb.append(s);
471                     break;
472                 case 10:
473                     sb.append("#10r");
474                     sb.append(s);
475                     break;
476                 case 16:
477                     sb.append("#x");
478                     sb.append(s);
479                     break;
480                 default:
481                     sb.append('#');
482                     sb.append(String.valueOf(base));
483                     sb.append('r');
484                     sb.append(s);
485                     break;
486             }
487             s = sb.toString();
488         }
489         return s;
490     }
491 }
492
Popular Tags