KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > jscience > mathematics > numbers > Rational


1 /*
2  * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
3  * Copyright (C) 2006 - JScience (http://jscience.org/)
4  * All rights reserved.
5  *
6  * Permission to use, copy, modify, and distribute this software is
7  * freely granted, provided that this notice is preserved.
8  */

9 package org.jscience.mathematics.numbers;
10
11 import org.jscience.mathematics.structures.Field;
12
13 import javolution.text.Text;
14 import javolution.xml.XMLFormat;
15 import javolution.xml.stream.XMLStreamException;
16
17 /**
18  * <p> This class represents the ratio of two {@link LargeInteger} numbers.</p>
19  *
20  * <p> Instances of this class are immutable and can be used to find exact
21  * solutions to linear equations with the {@link
22  * org.jscience.mathematics.vectors.Matrix Matrix} class.</p>
23  *
24  * @author <a HREF="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
25  * @version 3.0, February 13, 2006
26  * @see <a HREF="http://en.wikipedia.org/wiki/Rational_numbers">
27  * Wikipedia: Rational Numbers</a>
28  */

29 public final class Rational extends Number JavaDoc<Rational> implements Field<Rational>{
30
31     /**
32      * Holds the default XML representation for rational numbers.
33      * This representation consists of a simple <code>value</code> attribute
34      * holding the {@link #toText() textual} representation.
35      */

36     protected static final XMLFormat<Rational> XML = new XMLFormat<Rational>(Rational.class) {
37         
38         @Override JavaDoc
39         public Rational newInstance(Class JavaDoc<Rational> cls, InputElement xml) throws XMLStreamException {
40             return Rational.valueOf(xml.getAttribute("value"));
41         }
42         
43         public void write(Rational rational, OutputElement xml) throws XMLStreamException {
44             xml.setAttribute("value", rational.toText());
45         }
46
47          public void read(InputElement xml, Rational rational) {
48              // Nothing to do, immutable.
49
}
50      };
51
52     /**
53      * Holds the factory constructing rational instances.
54      */

55     private static final Factory<Rational> FACTORY = new Factory<Rational>() {
56
57         protected Rational create() {
58             return new Rational();
59         }
60     };
61
62     /**
63      * The {@link Rational} representing the additive identity.
64      */

65     public static final Rational ZERO = new Rational(LargeInteger.ZERO,
66             LargeInteger.ONE);
67
68     /**
69      * The {@link Rational} representing the multiplicative identity.
70      */

71     public static final Rational ONE = new Rational(LargeInteger.ONE,
72             LargeInteger.ONE);
73
74     /**
75      * Holds the dividend.
76      */

77     private LargeInteger _dividend;
78
79     /**
80      * Holds the divisor.
81      */

82     private LargeInteger _divisor;
83
84     /**
85      * Default constructor.
86      */

87     private Rational() {
88     }
89
90     /**
91      * Creates a rational number for the specified integer dividend and
92      * divisor.
93      *
94      * @param dividend the dividend value.
95      * @param divisor the divisor value.
96      * @throws ArithmeticException if <code>divisor == 0</code>
97      */

98     private Rational(LargeInteger dividend, LargeInteger divisor) {
99         _dividend = dividend;
100         _divisor = divisor;
101     }
102
103     /**
104      * Returns the rational number for the specified integer dividend and
105      * divisor.
106      *
107      * @param dividend the dividend value.
108      * @param divisor the divisor value.
109      * @return <code>dividend / divisor</code>
110      * @throws ArithmeticException if <code>divisor == 0</code>
111      */

112     public static Rational valueOf(long dividend, long divisor) {
113         Rational r = FACTORY.object();
114         r._dividend = LargeInteger.valueOf(dividend);
115         r._divisor = LargeInteger.valueOf(divisor);
116         return r.normalize();
117     }
118
119     /**
120      * Returns the rational number for the specified large integer
121      * dividend and divisor.
122      *
123      * @param dividend the dividend value.
124      * @param divisor the divisor value.
125      * @return <code>dividend / divisor</code>
126      * @throws ArithmeticException if <code>divisor.isZero()</code>
127      */

128     public static Rational valueOf(LargeInteger dividend, LargeInteger divisor) {
129         Rational r = FACTORY.object();
130         r._dividend = dividend;
131         r._divisor = divisor;
132         return r.normalize();
133     }
134
135     /**
136      * Returns the rational number for the specified character sequence.
137      *
138      * @param chars the character sequence.
139      * @return the corresponding rational number.
140      */

141     public static Rational valueOf(CharSequence JavaDoc chars) {
142         Text txt = Text.valueOf(chars); // TODO Use TextFormat...
143
int sep = txt.indexOf("/");
144         if (sep >= 0) {
145             LargeInteger dividend = LargeInteger.valueOf(txt.subtext(0, sep));
146             LargeInteger divisor = LargeInteger.valueOf(txt.subtext(
147                     sep + 1, chars.length()));
148             return valueOf(dividend, divisor);
149         } else { // No divisor.
150
return valueOf(LargeInteger.valueOf(txt.subtext(0, sep)),
151                     LargeInteger.ONE);
152         }
153     }
154
155     /**
156      * Returns the smallest dividend of the fraction representing this
157      * rational number.
158      *
159      * @return this rational dividend.
160      */

161     public LargeInteger getDividend() {
162         return _dividend;
163     }
164
165     /**
166      * Returns the smallest divisor of the fraction representing this
167      * rational (always positive).
168      *
169      * @return this rational divisor.
170      */

171     public LargeInteger getDivisor() {
172         return _divisor;
173     }
174
175     /**
176      * Returns the closest integer to this rational number.
177      *
178      * @return this rational rounded to the nearest integer.
179      */

180     public LargeInteger round() {
181         return _dividend.divide(_divisor);
182     }
183
184     /**
185      * Returns the opposite of this rational number.
186      *
187      * @return <code>-this</code>.
188      */

189     public Rational opposite() {
190         return Rational.valueOf(_dividend.opposite(), _divisor);
191     }
192
193     /**
194      * Returns the sum of this rational number with the one specified.
195      *
196      * @param that the rational number to be added.
197      * @return <code>this + that</code>.
198      */

199     public Rational plus(Rational that) {
200         return Rational.valueOf(
201                 this._dividend.times(that._divisor).plus(
202                         this._divisor.times(that._dividend)),
203                 this._divisor.times(that._divisor)).normalize();
204     }
205
206     /**
207      * Returns the difference between this rational number and the one
208      * specified.
209      *
210      * @param that the rational number to be subtracted.
211      * @return <code>this - that</code>.
212      */

213     public Rational minus(Rational that) {
214         return Rational.valueOf(
215                 this._dividend.times(that._divisor).minus(
216                         this._divisor.times(that._dividend)),
217                 this._divisor.times(that._divisor)).normalize();
218     }
219
220     /**
221      * Returns the product of this rational number with the one specified.
222      *
223      * @param that the rational number multiplier.
224      * @return <code>this ยท that</code>.
225      */

226     public Rational times(Rational that) {
227         Rational r = Rational.valueOf(this._dividend.times(that._dividend),
228                 this._divisor.times(that._divisor)).normalize();
229         return r;
230     }
231
232     /**
233      * Returns the inverse of this rational number.
234      *
235      * @return <code>1 / this</code>.
236      * @throws ArithmeticException if <code>dividend.isZero()</code>
237      */

238     public Rational inverse() {
239         if (_dividend.isZero())
240             throw new ArithmeticException JavaDoc("Dividend is zero");
241         return _dividend.isNegative() ? Rational.valueOf(_divisor.opposite(),
242                 _dividend.opposite()) : Rational.valueOf(_divisor, _dividend);
243     }
244
245     /**
246      * Returns this rational number divided by the one specified.
247      *
248      * @param that the rational number divisor.
249      * @return <code>this / that</code>.
250      * @throws ArithmeticException if <code>that.equals(ZERO)</code>
251      */

252     public Rational divide(Rational that) {
253         return Rational.valueOf(this._dividend.times(that._divisor),
254                 this._divisor.times(that._dividend)).normalize();
255     }
256
257     /**
258      * Returns the absolute value of this rational number.
259      *
260      * @return <code>|this|</code>.
261      */

262     public Rational abs() {
263         return Rational.valueOf(_dividend.abs(), _divisor);
264     }
265
266     /**
267      * Compares the absolute value of two rational numbers.
268      *
269      * @param that the rational number to be compared with.
270      * @return <code>|this| > |that|</code>
271      */

272     public boolean isLargerThan(Rational that) {
273         return this._dividend.times(that._divisor).isLargerThan(
274                 that._dividend.times(this._divisor));
275     }
276
277     /**
278      * Returns the decimal text representation of this number.
279      *
280      * @return the text representation of this number.
281      */

282     public Text toText() {
283         return _dividend.toText().concat(Text.valueOf('/')).concat(
284                 _divisor.toText());
285     }
286
287     /**
288      * Returns the text representation of this number in the specified radix.
289      *
290      * @param radix the radix of the representation.
291      * @return the text representation of this number.
292      */

293     public Text toText(int radix) {
294         return _dividend.toText(radix).concat(Text.valueOf('/')).concat(
295                 _divisor.toText(radix));
296     }
297
298     /**
299      * Compares this rational number against the specified object.
300      *
301      * @param that the object to compare with.
302      * @return <code>true</code> if the objects are the same;
303      * <code>false</code> otherwise.
304      */

305     public boolean equals(Object JavaDoc that) {
306         if (that instanceof Rational) {
307             return this._dividend.equals(((Rational) that)._dividend)
308                     && this._divisor.equals(((Rational) that)._divisor);
309         } else {
310             return false;
311         }
312     }
313
314     /**
315      * Returns the hash code for this rational number.
316      *
317      * @return the hash code value.
318      */

319     public int hashCode() {
320         return _dividend.hashCode() - _divisor.hashCode();
321     }
322
323     /**
324      * Returns the value of this rational number as a <code>long</code>.
325      *
326      * @return the numeric value represented by this rational after conversion
327      * to type <code>long</code>.
328      */

329     public long longValue() {
330         return (long) doubleValue();
331     }
332
333     /**
334      * Returns the value of this rational number as a <code>double</code>.
335      *
336      * @return the numeric value represented by this rational after conversion
337      * to type <code>double</code>.
338      */

339     public double doubleValue() {
340         // Normalize to 63 bits (minimum).
341
int dividendBitLength = _dividend.bitLength();
342         int divisorBitLength = _divisor.bitLength();
343         if (dividendBitLength > divisorBitLength) {
344             // Normalizes the divisor to 63 bits.
345
int shift = divisorBitLength - 63;;
346             long divisor = _divisor.shiftRight(shift).longValue();
347             LargeInteger dividend = _dividend.shiftRight(shift);
348             return dividend.doubleValue() / divisor;
349         } else {
350             // Normalizes the dividend to 63 bits.
351
int shift = dividendBitLength - 63;;
352             long dividend = _dividend.shiftRight(shift).longValue();
353             LargeInteger divisor = _divisor.shiftRight(shift);
354             return dividend / divisor.doubleValue();
355         }
356     }
357
358     /**
359      * Compares two rational number numerically.
360      *
361      * @param that the rational number to compare with.
362      * @return -1, 0 or 1 as this rational number is numerically less than,
363      * equal to, or greater than <code>that</code>.
364      */

365     public int compareTo(Rational that) {
366         return this._dividend.times(that._divisor).compareTo(
367                 that._dividend.times(this._divisor));
368     }
369
370     /**
371      * Returns the normalized form of this rational.
372      *
373      * @return this rational after normalization.
374      * @throws ArithmeticException if <code>divisor.isZero()</code>
375      */

376     private Rational normalize() {
377         if (!_divisor.isZero()) {
378             if (_divisor.isPositive()) {
379                 LargeInteger gcd = _dividend.gcd(_divisor);
380                 if (!gcd.equals(LargeInteger.ONE)) {
381                     _dividend = _dividend.divide(gcd);
382                     _divisor = _divisor.divide(gcd);
383                 }
384                 return this;
385             } else {
386                 _dividend = _dividend.opposite();
387                 _divisor = _divisor.opposite();
388                 return normalize();
389             }
390         } else {
391             throw new ArithmeticException JavaDoc("Zero divisor");
392         }
393     }
394
395     // Moves additional real-time members.
396
public boolean move(ObjectSpace os) {
397         if (super.move(os)) {
398             _dividend.move(os);
399             _divisor.move(os);
400             return true;
401         }
402         return false;
403     }
404
405     private static final long serialVersionUID = 1L;
406
407 }
Popular Tags