source: trunk/abcl/src/org/armedbear/lisp/Ratio.java @ 12559

Last change on this file since 12559 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.