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