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

Last change on this file was 13440, checked in by ehuelsmann, 13 years ago

Rename writeToString() to printObject() since that's what it's being used for.
Additionally, create princToString() for use in error messages, making the

required replacement where appropriate.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 19.2 KB
Line 
1/*
2 * Ratio.java
3 *
4 * Copyright (C) 2003-2005 Peter Graves
5 * $Id: Ratio.java 13440 2011-08-05 21:25:10Z 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 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        float result = (float) doubleValue();
185        if (Float.isInfinite(result) && TRAP_OVERFLOW)
186            type_error(this, Symbol.SINGLE_FLOAT);
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        if (Double.isInfinite(result) && TRAP_OVERFLOW)
225            type_error(this, Symbol.DOUBLE_FLOAT);
226
227        return negative ? -result : result;
228    }
229
230    @Override
231    public final LispObject incr()
232    {
233        return new Ratio(numerator.add(denominator), denominator);
234    }
235
236    @Override
237    public final LispObject decr()
238    {
239        return new Ratio(numerator.subtract(denominator), denominator);
240    }
241
242    @Override
243    public LispObject add(LispObject obj)
244    {
245        if (obj instanceof Fixnum) {
246            BigInteger n =
247                numerator.add(BigInteger.valueOf(((Fixnum)obj).value).multiply(denominator));
248            return number(n, denominator);
249        }
250        if (obj instanceof Bignum) {
251            BigInteger n = ((Bignum)obj).value;
252            return number(numerator.add(n.multiply(denominator)),
253                denominator);
254        }
255        if (obj instanceof Ratio) {
256            BigInteger n = ((Ratio)obj).numerator;
257            BigInteger d = ((Ratio)obj).denominator;
258            if (denominator.equals(d))
259                return number(numerator.add(n), denominator);
260            BigInteger common = denominator.multiply(d);
261            return number(numerator.multiply(d).add(n.multiply(denominator)),
262                common);
263        }
264        if (obj instanceof SingleFloat) {
265            return new SingleFloat(floatValue() + ((SingleFloat)obj).value);
266        }
267        if (obj instanceof DoubleFloat) {
268            return new DoubleFloat(doubleValue() + ((DoubleFloat)obj).value);
269        }
270        if (obj instanceof Complex) {
271            Complex c = (Complex) obj;
272            return Complex.getInstance(add(c.getRealPart()), c.getImaginaryPart());
273        }
274        return error(new TypeError(obj, Symbol.NUMBER));
275    }
276
277    @Override
278    public LispObject subtract(LispObject obj)
279    {
280        if (obj instanceof Fixnum) {
281            BigInteger n =
282                numerator.subtract(BigInteger.valueOf(((Fixnum)obj).value).multiply(denominator));
283            return number(n, denominator);
284        }
285        if (obj instanceof Bignum) {
286            BigInteger n = ((Bignum)obj).value;
287            return number(numerator.subtract(n.multiply(denominator)),
288                denominator);
289        }
290        if (obj instanceof Ratio) {
291            BigInteger n = ((Ratio)obj).numerator;
292            BigInteger d = ((Ratio)obj).denominator;
293            if (denominator.equals(d))
294                return number(numerator.subtract(n), denominator);
295            BigInteger common = denominator.multiply(d);
296            return number(numerator.multiply(d).subtract(n.multiply(denominator)),
297                common);
298        }
299        if (obj instanceof SingleFloat) {
300            return new SingleFloat(floatValue() - ((SingleFloat)obj).value);
301        }
302        if (obj instanceof DoubleFloat) {
303            return new DoubleFloat(doubleValue() - ((DoubleFloat)obj).value);
304        }
305        if (obj instanceof Complex) {
306            Complex c = (Complex) obj;
307            return Complex.getInstance(subtract(c.getRealPart()),
308                                       Fixnum.ZERO.subtract(c.getImaginaryPart()));
309        }
310        return error(new TypeError(obj, Symbol.NUMBER));
311    }
312
313    @Override
314    public LispObject multiplyBy(LispObject obj)
315    {
316        if (obj instanceof Fixnum) {
317            BigInteger n = ((Fixnum)obj).getBigInteger();
318            return number(numerator.multiply(n), denominator);
319        }
320        if (obj instanceof Bignum) {
321            BigInteger n = ((Bignum)obj).value;
322            return number(numerator.multiply(n), denominator);
323        }
324        if (obj instanceof Ratio) {
325            BigInteger n = ((Ratio)obj).numerator;
326            BigInteger d = ((Ratio)obj).denominator;
327            return number(numerator.multiply(n), denominator.multiply(d));
328        }
329        if (obj instanceof SingleFloat) {
330            return new SingleFloat(floatValue() * ((SingleFloat)obj).value);
331        }
332        if (obj instanceof DoubleFloat) {
333            return new DoubleFloat(doubleValue() * ((DoubleFloat)obj).value);
334        }
335        if (obj instanceof Complex) {
336            Complex c = (Complex) obj;
337            return Complex.getInstance(multiplyBy(c.getRealPart()),
338                                       multiplyBy(c.getImaginaryPart()));
339        }
340        return error(new TypeError(obj, Symbol.NUMBER));
341    }
342
343    @Override
344    public LispObject divideBy(LispObject obj)
345    {
346        if (obj instanceof Fixnum) {
347            BigInteger n = ((Fixnum)obj).getBigInteger();
348            return number(numerator, denominator.multiply(n));
349        }
350        if (obj instanceof Bignum) {
351            BigInteger n = ((Bignum)obj).value;
352            return number(numerator, denominator.multiply(n));
353        }
354        if (obj instanceof Ratio) {
355            BigInteger n = ((Ratio)obj).numerator;
356            BigInteger d = ((Ratio)obj).denominator;
357            return number(numerator.multiply(d), denominator.multiply(n));
358        }
359        if (obj instanceof SingleFloat) {
360            if (obj.zerop())
361                return error(new DivisionByZero());
362            return new SingleFloat(floatValue() / ((SingleFloat)obj).value);
363        }
364        if (obj instanceof DoubleFloat) {
365            if (obj.zerop())
366                return error(new DivisionByZero());
367            return new DoubleFloat(doubleValue() / ((DoubleFloat)obj).value);
368        }
369        if (obj instanceof Complex) {
370            Complex c = (Complex) obj;
371            // numerator
372            LispObject realPart = this.multiplyBy(c.getRealPart());
373            LispObject imagPart =
374                Fixnum.ZERO.subtract(this).multiplyBy(c.getImaginaryPart());
375            // denominator
376            LispObject d =
377                c.getRealPart().multiplyBy(c.getRealPart());
378            d = d.add(c.getImaginaryPart().multiplyBy(c.getImaginaryPart()));
379            return Complex.getInstance(realPart.divideBy(d),
380                                       imagPart.divideBy(d));
381        }
382        return error(new TypeError(obj, Symbol.NUMBER));
383    }
384
385    @Override
386    public boolean isEqualTo(LispObject obj)
387    {
388        if (obj instanceof Ratio)
389            return (numerator.equals(((Ratio)obj).numerator) &&
390                    denominator.equals(((Ratio)obj).denominator));
391        if (obj instanceof SingleFloat)
392            return isEqualTo(((SingleFloat)obj).rational());
393        if (obj instanceof DoubleFloat)
394            return isEqualTo(((DoubleFloat)obj).rational());
395        if (obj.numberp())
396            return false;
397        error(new TypeError(obj, Symbol.NUMBER));
398        // Not reached.
399        return false;
400    }
401
402    @Override
403    public boolean isNotEqualTo(LispObject obj)
404    {
405        return !isEqualTo(obj);
406    }
407
408    @Override
409    public boolean isLessThan(LispObject obj)
410    {
411        if (obj instanceof Fixnum) {
412            BigInteger n2 = ((Fixnum)obj).getBigInteger().multiply(denominator);
413            return numerator.compareTo(n2) < 0;
414        }
415        if (obj instanceof Bignum) {
416            BigInteger n = ((Bignum)obj).value.multiply(denominator);
417            return numerator.compareTo(n) < 0;
418        }
419        if (obj instanceof Ratio) {
420            BigInteger n1 = numerator.multiply(((Ratio)obj).denominator);
421            BigInteger n2 = ((Ratio)obj).numerator.multiply(denominator);
422            return n1.compareTo(n2) < 0;
423        }
424        if (obj instanceof SingleFloat)
425            return isLessThan(((SingleFloat)obj).rational());
426        if (obj instanceof DoubleFloat)
427            return isLessThan(((DoubleFloat)obj).rational());
428        error(new TypeError(obj, Symbol.REAL));
429        // Not reached.
430        return false;
431    }
432
433    @Override
434    public boolean isGreaterThan(LispObject obj)
435    {
436        if (obj instanceof Fixnum) {
437            BigInteger n2 = ((Fixnum)obj).getBigInteger().multiply(denominator);
438            return numerator.compareTo(n2) > 0;
439        }
440        if (obj instanceof Bignum) {
441            BigInteger n = ((Bignum)obj).value.multiply(denominator);
442            return numerator.compareTo(n) > 0;
443        }
444        if (obj instanceof Ratio) {
445            BigInteger n1 = numerator.multiply(((Ratio)obj).denominator);
446            BigInteger n2 = ((Ratio)obj).numerator.multiply(denominator);
447            return n1.compareTo(n2) > 0;
448        }
449        if (obj instanceof SingleFloat)
450            return isGreaterThan(((SingleFloat)obj).rational());
451        if (obj instanceof DoubleFloat)
452            return isGreaterThan(((DoubleFloat)obj).rational());
453        error(new TypeError(obj, Symbol.REAL));
454        // Not reached.
455        return false;
456    }
457
458    @Override
459    public boolean isLessThanOrEqualTo(LispObject obj)
460    {
461        if (obj instanceof Fixnum) {
462            BigInteger n2 = ((Fixnum)obj).getBigInteger().multiply(denominator);
463            return numerator.compareTo(n2) <= 0;
464        }
465        if (obj instanceof Bignum) {
466            BigInteger n = ((Bignum)obj).value.multiply(denominator);
467            return numerator.compareTo(n) <= 0;
468        }
469        if (obj instanceof Ratio) {
470            BigInteger n1 = numerator.multiply(((Ratio)obj).denominator);
471            BigInteger n2 = ((Ratio)obj).numerator.multiply(denominator);
472            return n1.compareTo(n2) <= 0;
473        }
474        if (obj instanceof SingleFloat)
475            return isLessThanOrEqualTo(((SingleFloat)obj).rational());
476        if (obj instanceof DoubleFloat)
477            return isLessThanOrEqualTo(((DoubleFloat)obj).rational());
478        error(new TypeError(obj, Symbol.REAL));
479        // Not reached.
480        return false;
481    }
482
483    @Override
484    public boolean isGreaterThanOrEqualTo(LispObject obj)
485    {
486        if (obj instanceof Fixnum) {
487            BigInteger n2 = ((Fixnum)obj).getBigInteger().multiply(denominator);
488            return numerator.compareTo(n2) >= 0;
489        }
490        if (obj instanceof Bignum) {
491            BigInteger n = ((Bignum)obj).value.multiply(denominator);
492            return numerator.compareTo(n) >= 0;
493        }
494        if (obj instanceof Ratio) {
495            BigInteger n1 = numerator.multiply(((Ratio)obj).denominator);
496            BigInteger n2 = ((Ratio)obj).numerator.multiply(denominator);
497            return n1.compareTo(n2) >= 0;
498        }
499        if (obj instanceof SingleFloat)
500            return isGreaterThanOrEqualTo(((SingleFloat)obj).rational());
501        if (obj instanceof DoubleFloat)
502            return isGreaterThanOrEqualTo(((DoubleFloat)obj).rational());
503        error(new TypeError(obj, Symbol.REAL));
504        // Not reached.
505        return false;
506    }
507
508    @Override
509    public LispObject truncate(LispObject obj)
510    {
511        // "When rationals and floats are combined by a numerical function,
512        // the rational is first converted to a float of the same format."
513        // 12.1.4.1
514        if (obj instanceof SingleFloat)
515            return new SingleFloat(floatValue()).truncate(obj);
516        if (obj instanceof DoubleFloat)
517            return new DoubleFloat(doubleValue()).truncate(obj);
518        BigInteger n, d;
519  try {
520    if (obj instanceof Fixnum) {
521            n = ((Fixnum)obj).getBigInteger();
522            d = BigInteger.ONE;
523    } else if (obj instanceof Bignum) {
524            n = ((Bignum)obj).value;
525            d = BigInteger.ONE;
526    } else if (obj instanceof Ratio) {
527            n = ((Ratio)obj).numerator();
528            d = ((Ratio)obj).denominator();
529    } else {
530            return error(new TypeError(obj, Symbol.NUMBER));
531    }
532    // Invert and multiply.
533    BigInteger num = numerator.multiply(d);
534    BigInteger den = denominator.multiply(n);
535    BigInteger quotient = num.divide(den);
536    // Multiply quotient by divisor.
537    LispObject product = number(quotient.multiply(n), d);
538    // Subtract to get remainder.
539    LispObject remainder = subtract(product);
540          return LispThread.currentThread().setValues(number(quotient), remainder);
541        }
542        catch (ArithmeticException e) {
543            if (obj.zerop())
544                return error(new DivisionByZero());
545            return error(new ArithmeticError(e.getMessage()));
546        }
547    }
548
549    @Override
550    public int hashCode()
551    {
552        return numerator.hashCode() ^ denominator.hashCode();
553    }
554
555    @Override
556    public String printObject()
557    {
558        final LispThread thread = LispThread.currentThread();
559        int base = Fixnum.getValue(Symbol.PRINT_BASE.symbolValue(thread));
560        StringBuffer sb = new StringBuffer(numerator.toString(base));
561        sb.append('/');
562        sb.append(denominator.toString(base));
563        String s = sb.toString().toUpperCase();
564        if (Symbol.PRINT_RADIX.symbolValue(thread) != NIL) {
565            sb.setLength(0);
566            switch (base) {
567                case 2:
568                    sb.append("#b");
569                    sb.append(s);
570                    break;
571                case 8:
572                    sb.append("#o");
573                    sb.append(s);
574                    break;
575                case 10:
576                    sb.append("#10r");
577                    sb.append(s);
578                    break;
579                case 16:
580                    sb.append("#x");
581                    sb.append(s);
582                    break;
583                default:
584                    sb.append('#');
585                    sb.append(String.valueOf(base));
586                    sb.append('r');
587                    sb.append(s);
588                    break;
589            }
590            s = sb.toString();
591        }
592        return s;
593    }
594}
Note: See TracBrowser for help on using the repository browser.