source: branches/0.22.x/abcl/src/org/armedbear/lisp/Ratio.java

Last change on this file was 12288, checked in by vvoutilainen, 15 years ago

Don't extend Lisp in LispObject, static import Lisp wherever
necessary. Patch by Douglas R. Miles.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 18.9 KB
Line 
1/*
2 * Ratio.java
3 *
4 * Copyright (C) 2003-2005 Peter Graves
5 * $Id: Ratio.java 12288 2009-11-29 22:00:12Z vvoutilainen $
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 * As a special exception, the copyright holders of this library give you
22 * permission to link this library with independent modules to produce an
23 * executable, regardless of the license terms of these independent
24 * modules, and to copy and distribute the resulting executable under
25 * terms of your choice, provided that you also meet, for each linked
26 * independent module, the terms and conditions of the license of that
27 * module.  An independent module is a module which is not derived from
28 * or based on this library.  If you modify this library, you may extend
29 * this exception to your version of the library, but you are not
30 * obligated to do so.  If you do not wish to do so, delete this
31 * exception statement from your version.
32 */
33
34package org.armedbear.lisp;
35
36import static org.armedbear.lisp.Lisp.*;
37
38import java.math.BigInteger;
39
40public final class Ratio extends LispObject
41{
42    private BigInteger numerator;
43    private BigInteger denominator;
44
45    public Ratio(BigInteger numerator, BigInteger denominator)
46    {
47        this.numerator = numerator;
48        this.denominator = denominator;
49    }
50
51    public BigInteger numerator()
52    {
53        return numerator;
54    }
55
56    @Override
57    public LispObject NUMERATOR()
58    {
59        return number(numerator);
60    }
61
62    public BigInteger denominator()
63    {
64        return denominator;
65    }
66
67    @Override
68    public LispObject DENOMINATOR()
69    {
70        return number(denominator);
71    }
72
73    @Override
74    public LispObject typeOf()
75    {
76        return Symbol.RATIO;
77    }
78
79    @Override
80    public LispObject classOf()
81    {
82        return BuiltInClass.RATIO;
83    }
84
85    @Override
86    public LispObject typep(LispObject type)
87    {
88        if (type == Symbol.RATIO)
89            return T;
90        if (type == Symbol.RATIONAL)
91            return T;
92        if (type == Symbol.REAL)
93            return T;
94        if (type == Symbol.NUMBER)
95            return T;
96        if (type == BuiltInClass.RATIO)
97            return T;
98        return super.typep(type);
99    }
100
101    @Override
102    public boolean numberp()
103    {
104        return true;
105    }
106
107    @Override
108    public boolean rationalp()
109    {
110        return true;
111    }
112
113    @Override
114    public boolean realp()
115    {
116        return true;
117    }
118
119    @Override
120    public boolean eql(LispObject obj)
121    {
122        if (this == obj)
123            return true;
124        if (obj instanceof Ratio) {
125            return (numerator.equals(((Ratio)obj).numerator) &&
126                    denominator.equals(((Ratio)obj).denominator));
127        }
128        return false;
129    }
130
131    @Override
132    public boolean equal(LispObject obj)
133    {
134        return eql(obj);
135    }
136
137    @Override
138    public boolean equalp(LispObject obj)
139    {
140        if (obj instanceof Ratio) {
141            return numerator.equals(((Ratio)obj).numerator) &&
142                denominator.equals(((Ratio)obj).denominator);
143        }
144        if (obj instanceof SingleFloat) {
145            return floatValue() == ((SingleFloat)obj).value;
146        }
147        if (obj instanceof DoubleFloat) {
148            return doubleValue() == ((DoubleFloat)obj).value;
149        }
150        return false;
151    }
152
153    @Override
154    public LispObject ABS()
155    {
156        if (numerator.signum() > 0 && denominator.signum() > 0)
157            return this;
158        if (numerator.signum() < 0 && denominator.signum() < 0)
159            return this;
160        return new Ratio(numerator.negate(), denominator);
161    }
162
163    @Override
164    public boolean plusp()
165    {
166        return numerator.signum() == denominator.signum();
167    }
168
169    @Override
170    public boolean minusp()
171    {
172        return numerator.signum() != denominator.signum();
173    }
174
175    @Override
176    public boolean zerop()
177    {
178        return false;
179    }
180
181    @Override
182    public float floatValue()
183    {
184        return (float) doubleValue();
185    }
186
187    @Override
188    public double doubleValue()
189    {
190        double result = numerator.doubleValue() / denominator.doubleValue();
191        if (result != 0 && !Double.isNaN(result) && !Double.isInfinite(result))
192            return result;
193        final boolean negative = numerator.signum() < 0;
194        final BigInteger num = negative ? numerator.negate() : numerator;
195        final BigInteger den = denominator;
196        final int numLen = num.bitLength();
197        final int denLen = den.bitLength();
198        int length = Math.min(numLen, denLen);
199        if (length <= 1)
200            return result;
201        BigInteger n = num;
202        BigInteger d = den;
203        final int digits = 54;
204        if (length > digits) {
205            n = n.shiftRight(length - digits);
206            d = d.shiftRight(length - digits);
207            length -= digits;
208        } else {
209            n = n.shiftRight(1);
210            d = d.shiftRight(1);
211            --length;
212        }
213        for (int i = 0; i < length; i++) {
214            result = n.doubleValue() / d.doubleValue();
215            if (result != 0 && !Double.isNaN(result) && !Double.isInfinite(result))
216                break;
217            n = n.shiftRight(1);
218            d = d.shiftRight(1);
219        }
220        return negative ? -result : result;
221    }
222
223    @Override
224    public final LispObject incr()
225    {
226        return new Ratio(numerator.add(denominator), denominator);
227    }
228
229    @Override
230    public final LispObject decr()
231    {
232        return new Ratio(numerator.subtract(denominator), denominator);
233    }
234
235    @Override
236    public LispObject add(LispObject obj)
237    {
238        if (obj instanceof Fixnum) {
239            BigInteger n =
240                numerator.add(BigInteger.valueOf(((Fixnum)obj).value).multiply(denominator));
241            return number(n, denominator);
242        }
243        if (obj instanceof Bignum) {
244            BigInteger n = ((Bignum)obj).value;
245            return number(numerator.add(n.multiply(denominator)),
246                denominator);
247        }
248        if (obj instanceof Ratio) {
249            BigInteger n = ((Ratio)obj).numerator;
250            BigInteger d = ((Ratio)obj).denominator;
251            if (denominator.equals(d))
252                return number(numerator.add(n), denominator);
253            BigInteger common = denominator.multiply(d);
254            return number(numerator.multiply(d).add(n.multiply(denominator)),
255                common);
256        }
257        if (obj instanceof SingleFloat) {
258            return new SingleFloat(floatValue() + ((SingleFloat)obj).value);
259        }
260        if (obj instanceof DoubleFloat) {
261            return new DoubleFloat(doubleValue() + ((DoubleFloat)obj).value);
262        }
263        if (obj instanceof Complex) {
264            Complex c = (Complex) obj;
265            return Complex.getInstance(add(c.getRealPart()), c.getImaginaryPart());
266        }
267        return error(new TypeError(obj, Symbol.NUMBER));
268    }
269
270    @Override
271    public LispObject subtract(LispObject obj)
272    {
273        if (obj instanceof Fixnum) {
274            BigInteger n =
275                numerator.subtract(BigInteger.valueOf(((Fixnum)obj).value).multiply(denominator));
276            return number(n, denominator);
277        }
278        if (obj instanceof Bignum) {
279            BigInteger n = ((Bignum)obj).value;
280            return number(numerator.subtract(n.multiply(denominator)),
281                denominator);
282        }
283        if (obj instanceof Ratio) {
284            BigInteger n = ((Ratio)obj).numerator;
285            BigInteger d = ((Ratio)obj).denominator;
286            if (denominator.equals(d))
287                return number(numerator.subtract(n), denominator);
288            BigInteger common = denominator.multiply(d);
289            return number(numerator.multiply(d).subtract(n.multiply(denominator)),
290                common);
291        }
292        if (obj instanceof SingleFloat) {
293            return new SingleFloat(floatValue() - ((SingleFloat)obj).value);
294        }
295        if (obj instanceof DoubleFloat) {
296            return new DoubleFloat(doubleValue() - ((DoubleFloat)obj).value);
297        }
298        if (obj instanceof Complex) {
299            Complex c = (Complex) obj;
300            return Complex.getInstance(subtract(c.getRealPart()),
301                                       Fixnum.ZERO.subtract(c.getImaginaryPart()));
302        }
303        return error(new TypeError(obj, Symbol.NUMBER));
304    }
305
306    @Override
307    public LispObject multiplyBy(LispObject obj)
308    {
309        if (obj instanceof Fixnum) {
310            BigInteger n = ((Fixnum)obj).getBigInteger();
311            return number(numerator.multiply(n), denominator);
312        }
313        if (obj instanceof Bignum) {
314            BigInteger n = ((Bignum)obj).value;
315            return number(numerator.multiply(n), denominator);
316        }
317        if (obj instanceof Ratio) {
318            BigInteger n = ((Ratio)obj).numerator;
319            BigInteger d = ((Ratio)obj).denominator;
320            return number(numerator.multiply(n), denominator.multiply(d));
321        }
322        if (obj instanceof SingleFloat) {
323            return new SingleFloat(floatValue() * ((SingleFloat)obj).value);
324        }
325        if (obj instanceof DoubleFloat) {
326            return new DoubleFloat(doubleValue() * ((DoubleFloat)obj).value);
327        }
328        if (obj instanceof Complex) {
329            Complex c = (Complex) obj;
330            return Complex.getInstance(multiplyBy(c.getRealPart()),
331                                       multiplyBy(c.getImaginaryPart()));
332        }
333        return error(new TypeError(obj, Symbol.NUMBER));
334    }
335
336    @Override
337    public LispObject divideBy(LispObject obj)
338    {
339        if (obj instanceof Fixnum) {
340            BigInteger n = ((Fixnum)obj).getBigInteger();
341            return number(numerator, denominator.multiply(n));
342        }
343        if (obj instanceof Bignum) {
344            BigInteger n = ((Bignum)obj).value;
345            return number(numerator, denominator.multiply(n));
346        }
347        if (obj instanceof Ratio) {
348            BigInteger n = ((Ratio)obj).numerator;
349            BigInteger d = ((Ratio)obj).denominator;
350            return number(numerator.multiply(d), denominator.multiply(n));
351        }
352        if (obj instanceof SingleFloat) {
353            if (obj.zerop())
354                return error(new DivisionByZero());
355            return new SingleFloat(floatValue() / ((SingleFloat)obj).value);
356        }
357        if (obj instanceof DoubleFloat) {
358            if (obj.zerop())
359                return error(new DivisionByZero());
360            return new DoubleFloat(doubleValue() / ((DoubleFloat)obj).value);
361        }
362        if (obj instanceof Complex) {
363            Complex c = (Complex) obj;
364            // numerator
365            LispObject realPart = this.multiplyBy(c.getRealPart());
366            LispObject imagPart =
367                Fixnum.ZERO.subtract(this).multiplyBy(c.getImaginaryPart());
368            // denominator
369            LispObject d =
370                c.getRealPart().multiplyBy(c.getRealPart());
371            d = d.add(c.getImaginaryPart().multiplyBy(c.getImaginaryPart()));
372            return Complex.getInstance(realPart.divideBy(d),
373                                       imagPart.divideBy(d));
374        }
375        return error(new TypeError(obj, Symbol.NUMBER));
376    }
377
378    @Override
379    public boolean isEqualTo(LispObject obj)
380    {
381        if (obj instanceof Ratio)
382            return (numerator.equals(((Ratio)obj).numerator) &&
383                    denominator.equals(((Ratio)obj).denominator));
384        if (obj instanceof SingleFloat)
385            return isEqualTo(((SingleFloat)obj).rational());
386        if (obj instanceof DoubleFloat)
387            return isEqualTo(((DoubleFloat)obj).rational());
388        if (obj.numberp())
389            return false;
390        error(new TypeError(obj, Symbol.NUMBER));
391        // Not reached.
392        return false;
393    }
394
395    @Override
396    public boolean isNotEqualTo(LispObject obj)
397    {
398        return !isEqualTo(obj);
399    }
400
401    @Override
402    public boolean isLessThan(LispObject obj)
403    {
404        if (obj instanceof Fixnum) {
405            BigInteger n2 = ((Fixnum)obj).getBigInteger().multiply(denominator);
406            return numerator.compareTo(n2) < 0;
407        }
408        if (obj instanceof Bignum) {
409            BigInteger n = ((Bignum)obj).value.multiply(denominator);
410            return numerator.compareTo(n) < 0;
411        }
412        if (obj instanceof Ratio) {
413            BigInteger n1 = numerator.multiply(((Ratio)obj).denominator);
414            BigInteger n2 = ((Ratio)obj).numerator.multiply(denominator);
415            return n1.compareTo(n2) < 0;
416        }
417        if (obj instanceof SingleFloat)
418            return isLessThan(((SingleFloat)obj).rational());
419        if (obj instanceof DoubleFloat)
420            return isLessThan(((DoubleFloat)obj).rational());
421        error(new TypeError(obj, Symbol.REAL));
422        // Not reached.
423        return false;
424    }
425
426    @Override
427    public boolean isGreaterThan(LispObject obj)
428    {
429        if (obj instanceof Fixnum) {
430            BigInteger n2 = ((Fixnum)obj).getBigInteger().multiply(denominator);
431            return numerator.compareTo(n2) > 0;
432        }
433        if (obj instanceof Bignum) {
434            BigInteger n = ((Bignum)obj).value.multiply(denominator);
435            return numerator.compareTo(n) > 0;
436        }
437        if (obj instanceof Ratio) {
438            BigInteger n1 = numerator.multiply(((Ratio)obj).denominator);
439            BigInteger n2 = ((Ratio)obj).numerator.multiply(denominator);
440            return n1.compareTo(n2) > 0;
441        }
442        if (obj instanceof SingleFloat)
443            return isGreaterThan(((SingleFloat)obj).rational());
444        if (obj instanceof DoubleFloat)
445            return isGreaterThan(((DoubleFloat)obj).rational());
446        error(new TypeError(obj, Symbol.REAL));
447        // Not reached.
448        return false;
449    }
450
451    @Override
452    public boolean isLessThanOrEqualTo(LispObject obj)
453    {
454        if (obj instanceof Fixnum) {
455            BigInteger n2 = ((Fixnum)obj).getBigInteger().multiply(denominator);
456            return numerator.compareTo(n2) <= 0;
457        }
458        if (obj instanceof Bignum) {
459            BigInteger n = ((Bignum)obj).value.multiply(denominator);
460            return numerator.compareTo(n) <= 0;
461        }
462        if (obj instanceof Ratio) {
463            BigInteger n1 = numerator.multiply(((Ratio)obj).denominator);
464            BigInteger n2 = ((Ratio)obj).numerator.multiply(denominator);
465            return n1.compareTo(n2) <= 0;
466        }
467        if (obj instanceof SingleFloat)
468            return isLessThanOrEqualTo(((SingleFloat)obj).rational());
469        if (obj instanceof DoubleFloat)
470            return isLessThanOrEqualTo(((DoubleFloat)obj).rational());
471        error(new TypeError(obj, Symbol.REAL));
472        // Not reached.
473        return false;
474    }
475
476    @Override
477    public boolean isGreaterThanOrEqualTo(LispObject obj)
478    {
479        if (obj instanceof Fixnum) {
480            BigInteger n2 = ((Fixnum)obj).getBigInteger().multiply(denominator);
481            return numerator.compareTo(n2) >= 0;
482        }
483        if (obj instanceof Bignum) {
484            BigInteger n = ((Bignum)obj).value.multiply(denominator);
485            return numerator.compareTo(n) >= 0;
486        }
487        if (obj instanceof Ratio) {
488            BigInteger n1 = numerator.multiply(((Ratio)obj).denominator);
489            BigInteger n2 = ((Ratio)obj).numerator.multiply(denominator);
490            return n1.compareTo(n2) >= 0;
491        }
492        if (obj instanceof SingleFloat)
493            return isGreaterThanOrEqualTo(((SingleFloat)obj).rational());
494        if (obj instanceof DoubleFloat)
495            return isGreaterThanOrEqualTo(((DoubleFloat)obj).rational());
496        error(new TypeError(obj, Symbol.REAL));
497        // Not reached.
498        return false;
499    }
500
501    @Override
502    public LispObject truncate(LispObject obj)
503    {
504        // "When rationals and floats are combined by a numerical function,
505        // the rational is first converted to a float of the same format."
506        // 12.1.4.1
507        if (obj instanceof SingleFloat)
508            return new SingleFloat(floatValue()).truncate(obj);
509        if (obj instanceof DoubleFloat)
510            return new DoubleFloat(doubleValue()).truncate(obj);
511        BigInteger n, d;
512  try {
513    if (obj instanceof Fixnum) {
514            n = ((Fixnum)obj).getBigInteger();
515            d = BigInteger.ONE;
516    } else if (obj instanceof Bignum) {
517            n = ((Bignum)obj).value;
518            d = BigInteger.ONE;
519    } else if (obj instanceof Ratio) {
520            n = ((Ratio)obj).numerator();
521            d = ((Ratio)obj).denominator();
522    } else {
523            return error(new TypeError(obj, Symbol.NUMBER));
524    }
525    // Invert and multiply.
526    BigInteger num = numerator.multiply(d);
527    BigInteger den = denominator.multiply(n);
528    BigInteger quotient = num.divide(den);
529    // Multiply quotient by divisor.
530    LispObject product = number(quotient.multiply(n), d);
531    // Subtract to get remainder.
532    LispObject remainder = subtract(product);
533          return LispThread.currentThread().setValues(number(quotient), remainder);
534        }
535        catch (ArithmeticException e) {
536            if (obj.zerop())
537                return error(new DivisionByZero());
538            return error(new ArithmeticError(e.getMessage()));
539        }
540    }
541
542    @Override
543    public int hashCode()
544    {
545        return numerator.hashCode() ^ denominator.hashCode();
546    }
547
548    @Override
549    public String writeToString()
550    {
551        final LispThread thread = LispThread.currentThread();
552        int base = Fixnum.getValue(Symbol.PRINT_BASE.symbolValue(thread));
553        StringBuffer sb = new StringBuffer(numerator.toString(base));
554        sb.append('/');
555        sb.append(denominator.toString(base));
556        String s = sb.toString().toUpperCase();
557        if (Symbol.PRINT_RADIX.symbolValue(thread) != NIL) {
558            sb.setLength(0);
559            switch (base) {
560                case 2:
561                    sb.append("#b");
562                    sb.append(s);
563                    break;
564                case 8:
565                    sb.append("#o");
566                    sb.append(s);
567                    break;
568                case 10:
569                    sb.append("#10r");
570                    sb.append(s);
571                    break;
572                case 16:
573                    sb.append("#x");
574                    sb.append(s);
575                    break;
576                default:
577                    sb.append('#');
578                    sb.append(String.valueOf(base));
579                    sb.append('r');
580                    sb.append(s);
581                    break;
582            }
583            s = sb.toString();
584        }
585        return s;
586    }
587}
Note: See TracBrowser for help on using the repository browser.