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