001/*
002 * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
003 * Copyright (C) 2006 - JScience (http://jscience.org/)
004 * All rights reserved.
005 * 
006 * Permission to use, copy, modify, and distribute this software is
007 * freely granted, provided that this notice is preserved.
008 */
009package org.jscience.mathematics.number;
010
011import org.jscience.mathematics.structure.Field;
012
013import javolution.context.ObjectFactory;
014import javolution.text.Text;
015import javolution.xml.XMLFormat;
016import javolution.xml.stream.XMLStreamException;
017
018/**
019 * <p> This class represents the ratio of two {@link LargeInteger} numbers.</p>
020 * 
021 * <p> Instances of this class are immutable and can be used to find exact 
022 *     solutions to linear equations with the {@link 
023 *     org.jscience.mathematics.vector.Matrix Matrix} class.</p>
024 * 
025 * @author <a href="mailto:jean-marie@dautelle.com">Jean-Marie Dautelle</a>
026 * @version 3.0, February 13, 2006
027 * @see <a href="http://en.wikipedia.org/wiki/Rational_numbers">
028 *      Wikipedia: Rational Numbers</a>
029 */
030public final class Rational extends Number<Rational> implements Field<Rational>{
031
032    /**
033     * Holds the default XML representation for rational numbers.
034     * This representation consists of a simple <code>value</code> attribute
035     * holding the {@link #toText() textual} representation.
036     */
037    static final XMLFormat<Rational> XML = new XMLFormat<Rational>(Rational.class) {
038        
039        @Override
040        public Rational newInstance(Class<Rational> cls, InputElement xml) throws XMLStreamException {
041            return Rational.valueOf(xml.getAttribute("value"));
042        }
043        
044        public void write(Rational rational, OutputElement xml) throws XMLStreamException {
045            xml.setAttribute("value", rational.toText());
046        }
047
048         public void read(InputElement xml, Rational rational) {
049             // Nothing to do, immutable.
050         }
051     };
052
053    /**
054     * Holds the factory constructing rational instances.
055     */
056    private static final ObjectFactory<Rational> FACTORY = new ObjectFactory<Rational>() {
057
058        protected Rational create() {
059            return new Rational();
060        }
061    };
062
063    /**
064     * The {@link Rational} representing the additive identity.
065     */
066    public static final Rational ZERO = new Rational(LargeInteger.ZERO,
067            LargeInteger.ONE);
068
069    /**
070     * The {@link Rational} representing the multiplicative identity.
071     */
072    public static final Rational ONE = new Rational(LargeInteger.ONE,
073            LargeInteger.ONE);
074
075    /**
076     * Holds the dividend.
077     */
078    private LargeInteger _dividend;
079
080    /**
081     * Holds the divisor.
082     */
083    private LargeInteger _divisor;
084
085    /**
086     * Default constructor. 
087     */
088    private Rational() {
089    }
090
091    /**
092     * Creates a rational number for the specified integer dividend and 
093     * divisor. 
094     * 
095     * @param dividend the dividend value.
096     * @param divisor the divisor value.
097     * @throws ArithmeticException if <code>divisor == 0</code>
098     */
099    private Rational(LargeInteger dividend, LargeInteger divisor) {
100        _dividend = dividend;
101        _divisor = divisor;
102    }
103
104    /**
105     * Returns the rational number for the specified integer dividend and 
106     * divisor. 
107     * 
108     * @param dividend the dividend value.
109     * @param divisor the divisor value.
110     * @return <code>dividend / divisor</code>
111     * @throws ArithmeticException if <code>divisor == 0</code>
112     */
113    public static Rational valueOf(long dividend, long divisor) {
114        Rational r = FACTORY.object();
115        r._dividend = LargeInteger.valueOf(dividend);
116        r._divisor = LargeInteger.valueOf(divisor);
117        return r.normalize();
118    }
119
120    /**
121     * Returns the rational number for the specified large integer 
122     * dividend and divisor. 
123     * 
124     * @param dividend the dividend value.
125     * @param divisor the divisor value.
126     * @return <code>dividend / divisor</code>
127     * @throws ArithmeticException if <code>divisor.isZero()</code>
128     */
129    public static Rational valueOf(LargeInteger dividend, LargeInteger divisor) {
130        Rational r = FACTORY.object();
131        r._dividend = dividend;
132        r._divisor = divisor;
133        return r.normalize();
134    }
135
136    /**
137     * Returns the rational number for the specified character sequence.
138     * 
139     * @param  chars the character sequence.
140     * @return the corresponding rational number.
141     */
142    public static Rational valueOf(CharSequence chars) {
143        Text txt = Text.valueOf(chars); // TODO Use TextFormat...
144        int sep = txt.indexOf("/");
145        if (sep >= 0) {
146            LargeInteger dividend = LargeInteger.valueOf(txt.subtext(0, sep));
147            LargeInteger divisor = LargeInteger.valueOf(txt.subtext(
148                    sep + 1, chars.length()));
149            return valueOf(dividend, divisor);
150        } else { // No divisor.
151            return valueOf(LargeInteger.valueOf(txt.subtext(0, sep)),
152                    LargeInteger.ONE);
153        }
154    }
155
156    /**
157     * Returns the smallest dividend of the fraction representing this
158     * rational number.
159     * 
160     * @return this rational dividend.
161     */
162    public LargeInteger getDividend() {
163        return _dividend;
164    }
165
166    /**
167     * Returns the smallest divisor of the fraction representing this 
168     * rational (always positive).
169     * 
170     * @return this rational divisor.
171     */
172    public LargeInteger getDivisor() {
173        return _divisor;
174    }
175
176    /**
177     * Returns the closest integer value to this rational number.
178     * 
179     * @return this rational rounded to the nearest integer.
180     */
181    public LargeInteger round() {
182        LargeInteger halfDivisor = _divisor.times2pow(-1);
183        return isNegative() ? _dividend.minus(halfDivisor).divide(_divisor) :
184            _dividend.plus(halfDivisor).divide(_divisor);
185    }
186
187    /**
188     * Returns the opposite of this rational number.
189     * 
190     * @return <code>-this</code>.
191     */
192    public Rational opposite() {
193        return Rational.valueOf(_dividend.opposite(), _divisor);
194    }
195
196    /**
197     * Returns the sum of this rational number with the one specified.
198     * 
199     * @param that the rational number to be added.
200     * @return <code>this + that</code>.
201     */
202    public Rational plus(Rational that) {
203        return Rational.valueOf(
204                this._dividend.times(that._divisor).plus(
205                        this._divisor.times(that._dividend)),
206                this._divisor.times(that._divisor)).normalize();
207    }
208
209    /**
210     * Returns the difference between this rational number and the one
211     * specified.
212     * 
213     * @param that the rational number to be subtracted.
214     * @return <code>this - that</code>.
215     */
216    public Rational minus(Rational that) {
217        return Rational.valueOf(
218                this._dividend.times(that._divisor).minus(
219                        this._divisor.times(that._dividend)),
220                this._divisor.times(that._divisor)).normalize();
221    }
222
223    /**
224     * Returns the product of this rational number with the specified 
225     * <code>long</code> multiplier.
226     * 
227     * @param multiplier the <code>long</code> multiplier.
228     * @return <code>this · multiplier</code>.
229     */
230    public Rational times(long multiplier) {
231        return this.times(Rational.valueOf(multiplier, 1));
232    }
233
234    /**
235     * Returns the product of this rational number with the one specified.
236     * 
237     * @param that the rational number multiplier.
238     * @return <code>this · that</code>.
239     */
240    public Rational times(Rational that) {
241        
242        Rational r = Rational.valueOf(this._dividend.times(that._dividend),
243                this._divisor.times(that._divisor)).normalize();
244        
245        return r;
246    }
247
248    /**
249     * Returns the inverse of this rational number.
250     * 
251     * @return <code>1 / this</code>.
252     * @throws ArithmeticException if <code>dividend.isZero()</code>
253     */
254    public Rational inverse() {
255        if (_dividend.isZero())
256            throw new ArithmeticException("Dividend is zero");
257        return _dividend.isNegative() ? Rational.valueOf(_divisor.opposite(),
258                _dividend.opposite()) : Rational.valueOf(_divisor, _dividend);
259    }
260
261    /**
262     * Returns this rational number divided by the one specified.
263     * 
264     * @param that the rational number divisor.
265     * @return <code>this / that</code>.
266     * @throws ArithmeticException if <code>that.equals(ZERO)</code>
267     */
268    public Rational divide(Rational that) {
269        return Rational.valueOf(this._dividend.times(that._divisor),
270                this._divisor.times(that._dividend)).normalize();
271    }
272
273    /**
274     * Returns the absolute value of this rational number.
275     * 
276     * @return <code>|this|</code>.
277     */
278    public Rational abs() {
279        return Rational.valueOf(_dividend.abs(), _divisor);
280    }
281
282    /**
283     * Indicates if this rational number is equal to zero.
284     * 
285     * @return <code>this == 0</code>
286     */
287    public boolean isZero() {
288        return _dividend.isZero();
289    }
290
291
292    /**
293     * Indicates if this rational number is greater than zero.
294     * 
295     * @return <code>this > 0</code>
296     */
297    public boolean isPositive() {
298        return _dividend.isPositive();
299    }
300
301    /**
302     * Indicates if this rational number is less than zero.
303     * 
304     * @return <code>this < 0</code>
305     */
306    public boolean isNegative() {
307        return _dividend.isNegative();
308    }
309
310    /**
311     * Compares the absolute value of two rational numbers.
312     *
313     * @param that the rational number to be compared with.
314     * @return <code>|this| > |that|</code>
315     */
316    public boolean isLargerThan(Rational that) {
317        return this._dividend.times(that._divisor).isLargerThan(
318                that._dividend.times(this._divisor));
319    }
320
321    /**
322     * Returns the decimal text representation of this number.
323     *
324     * @return the text representation of this number.
325     */
326    public Text toText() {
327        return _dividend.toText().concat(Text.valueOf('/')).concat(
328                _divisor.toText());
329    }
330
331    /**
332     * Compares this rational number against the specified object.
333     * 
334     * @param that the object to compare with.
335     * @return <code>true</code> if the objects are the same;
336     *         <code>false</code> otherwise.
337     */
338    public boolean equals(Object that) {
339        if (that instanceof Rational) {
340            return this._dividend.equals(((Rational) that)._dividend)
341                    && this._divisor.equals(((Rational) that)._divisor);
342        } else {
343            return false;
344        }
345    }
346
347    /**
348     * Returns the hash code for this rational number.
349     * 
350     * @return the hash code value.
351     */
352    public int hashCode() {
353        return _dividend.hashCode() - _divisor.hashCode();
354    }
355
356    /**
357     * Returns the value of this rational number as a <code>long</code>.
358     * 
359     * @return the numeric value represented by this rational after conversion
360     *         to type <code>long</code>.
361     */
362    public long longValue() {
363        return _dividend.divide(_divisor).longValue();
364    }
365
366    /**
367     * Returns the value of this rational number as a <code>double</code>.
368     * 
369     * @return the numeric value represented by this rational after conversion
370     *         to type <code>double</code>.
371     */
372    public double doubleValue() {
373        if (_dividend.isNegative()) // Avoid negative numbers (ref. bitLength) 
374            return - this.abs().doubleValue();
375        
376        // Normalize to 63 bits (minimum).
377        int dividendBitLength = _dividend.bitLength();
378        int divisorBitLength = _divisor.bitLength();
379        if (dividendBitLength > divisorBitLength) {
380            // Normalizes the divisor to 63 bits.
381            int shift = divisorBitLength - 63;;
382            long divisor = _divisor.shiftRight(shift).longValue();
383            LargeInteger dividend = _dividend.shiftRight(shift);
384            return dividend.doubleValue() / divisor;
385        } else {
386            // Normalizes the dividend to 63 bits.
387            int shift = dividendBitLength - 63;;
388            long dividend = _dividend.shiftRight(shift).longValue();
389            LargeInteger divisor = _divisor.shiftRight(shift);
390            return dividend / divisor.doubleValue();
391        }
392    }
393
394    /**
395     * Compares two rational number numerically.
396     * 
397     * @param that the rational number to compare with.
398     * @return -1, 0 or 1 as this rational number is numerically less than, 
399     *         equal to, or greater than <code>that</code>.
400     */
401    public int compareTo(Rational that) {
402        return this._dividend.times(that._divisor).compareTo(
403                that._dividend.times(this._divisor));
404    }
405
406    /**
407     * Returns the normalized form of this rational.
408     * 
409     * @return this rational after normalization.
410     * @throws ArithmeticException if <code>divisor.isZero()</code>
411     */
412    private Rational normalize() {
413        if (!_divisor.isZero()) {
414            if (_divisor.isPositive()) {
415                LargeInteger gcd = _dividend.gcd(_divisor);
416                if (!gcd.equals(LargeInteger.ONE)) {
417                    _dividend = _dividend.divide(gcd);
418                    _divisor = _divisor.divide(gcd);
419                }
420                return this;
421            } else {
422                _dividend = _dividend.opposite();
423                _divisor = _divisor.opposite();
424                return normalize();
425            }
426        } else {
427            throw new ArithmeticException("Zero divisor");
428        }
429    }
430
431    @Override
432    public Rational copy() {
433        Rational r = FACTORY.object();
434        r._dividend = _dividend.copy();
435        r._divisor = _divisor.copy();
436        return r;
437    }
438
439    private static final long serialVersionUID = 1L;
440}