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

Last change on this file was 12254, checked in by ehuelsmann, 16 years ago

Remove 'throws ConditionThrowable?' method annotations:

it's an unchecked exception now, so no need to declare it thrown.

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