/*
 * JScience - Java(TM) Tools and Libraries for the Advancement of Sciences.
 * Copyright (C) 2006 - JScience (http://jscience.org/)
 * All rights reserved.
 * 
 * Permission to use, copy, modify, and distribute this software is
 * freely granted, provided that this notice is preserved.
 */
package org.jscience.mathematics.number;

import org.jscience.mathematics.structure.Field;

import javolution.context.ObjectFactory;
import javolution.text.Text;
import javolution.xml.XMLFormat;
import javolution.xml.stream.XMLStreamException;

/**
 * 

This class represents the ratio of two {@link LargeInteger} numbers.

* *

Instances of this class are immutable and can be used to find exact * solutions to linear equations with the {@link * org.jscience.mathematics.vector.Matrix Matrix} class.

* * @author Jean-Marie Dautelle * @version 3.0, February 13, 2006 * @see * Wikipedia: Rational Numbers */ public final class Rational extends Number implements Field{ /** * Holds the default XML representation for rational numbers. * This representation consists of a simple value attribute * holding the {@link #toText() textual} representation. */ static final XMLFormat XML = new XMLFormat(Rational.class) { @Override public Rational newInstance(Class cls, InputElement xml) throws XMLStreamException { return Rational.valueOf(xml.getAttribute("value")); } public void write(Rational rational, OutputElement xml) throws XMLStreamException { xml.setAttribute("value", rational.toText()); } public void read(InputElement xml, Rational rational) { // Nothing to do, immutable. } }; /** * Holds the factory constructing rational instances. */ private static final ObjectFactory FACTORY = new ObjectFactory() { protected Rational create() { return new Rational(); } }; /** * The {@link Rational} representing the additive identity. */ public static final Rational ZERO = new Rational(LargeInteger.ZERO, LargeInteger.ONE); /** * The {@link Rational} representing the multiplicative identity. */ public static final Rational ONE = new Rational(LargeInteger.ONE, LargeInteger.ONE); /** * Holds the dividend. */ private LargeInteger _dividend; /** * Holds the divisor. */ private LargeInteger _divisor; /** * Default constructor. */ private Rational() { } /** * Creates a rational number for the specified integer dividend and * divisor. * * @param dividend the dividend value. * @param divisor the divisor value. * @throws ArithmeticException if divisor == 0 */ private Rational(LargeInteger dividend, LargeInteger divisor) { _dividend = dividend; _divisor = divisor; } /** * Returns the rational number for the specified integer dividend and * divisor. * * @param dividend the dividend value. * @param divisor the divisor value. * @return dividend / divisor * @throws ArithmeticException if divisor == 0 */ public static Rational valueOf(long dividend, long divisor) { Rational r = FACTORY.object(); r._dividend = LargeInteger.valueOf(dividend); r._divisor = LargeInteger.valueOf(divisor); return r.normalize(); } /** * Returns the rational number for the specified large integer * dividend and divisor. * * @param dividend the dividend value. * @param divisor the divisor value. * @return dividend / divisor * @throws ArithmeticException if divisor.isZero() */ public static Rational valueOf(LargeInteger dividend, LargeInteger divisor) { Rational r = FACTORY.object(); r._dividend = dividend; r._divisor = divisor; return r.normalize(); } /** * Returns the rational number for the specified character sequence. * * @param chars the character sequence. * @return the corresponding rational number. */ public static Rational valueOf(CharSequence chars) { Text txt = Text.valueOf(chars); // TODO Use TextFormat... int sep = txt.indexOf("/"); if (sep >= 0) { LargeInteger dividend = LargeInteger.valueOf(txt.subtext(0, sep)); LargeInteger divisor = LargeInteger.valueOf(txt.subtext( sep + 1, chars.length())); return valueOf(dividend, divisor); } else { // No divisor. return valueOf(LargeInteger.valueOf(txt), LargeInteger.ONE); } } /** * Returns the smallest dividend of the fraction representing this * rational number. * * @return this rational dividend. */ public LargeInteger getDividend() { return _dividend; } /** * Returns the smallest divisor of the fraction representing this * rational (always positive). * * @return this rational divisor. */ public LargeInteger getDivisor() { return _divisor; } /** * Returns the closest integer value to this rational number. * * @return this rational rounded to the nearest integer. */ public LargeInteger round() { LargeInteger halfDivisor = _divisor.times2pow(-1); return isNegative() ? _dividend.minus(halfDivisor).divide(_divisor) : _dividend.plus(halfDivisor).divide(_divisor); } /** * Returns the opposite of this rational number. * * @return -this. */ public Rational opposite() { return Rational.valueOf(_dividend.opposite(), _divisor); } /** * Returns the sum of this rational number with the one specified. * * @param that the rational number to be added. * @return this + that. */ public Rational plus(Rational that) { return Rational.valueOf( this._dividend.times(that._divisor).plus( this._divisor.times(that._dividend)), this._divisor.times(that._divisor)).normalize(); } /** * Returns the difference between this rational number and the one * specified. * * @param that the rational number to be subtracted. * @return this - that. */ public Rational minus(Rational that) { return Rational.valueOf( this._dividend.times(that._divisor).minus( this._divisor.times(that._dividend)), this._divisor.times(that._divisor)).normalize(); } /** * Returns the product of this rational number with the specified * long multiplier. * * @param multiplier the long multiplier. * @return this · multiplier. */ public Rational times(long multiplier) { return this.times(Rational.valueOf(multiplier, 1)); } /** * Returns the product of this rational number with the one specified. * * @param that the rational number multiplier. * @return this · that. */ public Rational times(Rational that) { Rational r = Rational.valueOf(this._dividend.times(that._dividend), this._divisor.times(that._divisor)).normalize(); return r; } /** * Returns the inverse of this rational number. * * @return 1 / this. * @throws ArithmeticException if dividend.isZero() */ public Rational inverse() { if (_dividend.isZero()) throw new ArithmeticException("Dividend is zero"); return _dividend.isNegative() ? Rational.valueOf(_divisor.opposite(), _dividend.opposite()) : Rational.valueOf(_divisor, _dividend); } /** * Returns this rational number divided by the one specified. * * @param that the rational number divisor. * @return this / that. * @throws ArithmeticException if that.equals(ZERO) */ public Rational divide(Rational that) { return Rational.valueOf(this._dividend.times(that._divisor), this._divisor.times(that._dividend)).normalize(); } /** * Returns the absolute value of this rational number. * * @return |this|. */ public Rational abs() { return Rational.valueOf(_dividend.abs(), _divisor); } /** * Indicates if this rational number is equal to zero. * * @return this == 0 */ public boolean isZero() { return _dividend.isZero(); } /** * Indicates if this rational number is greater than zero. * * @return this > 0 */ public boolean isPositive() { return _dividend.isPositive(); } /** * Indicates if this rational number is less than zero. * * @return this < 0 */ public boolean isNegative() { return _dividend.isNegative(); } /** * Compares the absolute value of two rational numbers. * * @param that the rational number to be compared with. * @return |this| > |that| */ public boolean isLargerThan(Rational that) { return this._dividend.times(that._divisor).isLargerThan( that._dividend.times(this._divisor)); } /** * Returns the decimal text representation of this number. * * @return the text representation of this number. */ public Text toText() { return _dividend.toText().concat(Text.valueOf('/')).concat( _divisor.toText()); } /** * Compares this rational number against the specified object. * * @param that the object to compare with. * @return true if the objects are the same; * false otherwise. */ public boolean equals(Object that) { if (that instanceof Rational) { return this._dividend.equals(((Rational) that)._dividend) && this._divisor.equals(((Rational) that)._divisor); } else { return false; } } /** * Returns the hash code for this rational number. * * @return the hash code value. */ public int hashCode() { return 3191 * _dividend.hashCode() + 9811 * _divisor.hashCode(); } /** * Returns the value of this rational number as a long. * * @return the numeric value represented by this rational after conversion * to type long. */ public long longValue() { return _dividend.divide(_divisor).longValue(); } /** * Returns the value of this rational number as a double. * * @return the numeric value represented by this rational after conversion * to type double. */ public double doubleValue() { if (_dividend.isNegative()) // Avoid negative numbers (ref. bitLength) return - this.abs().doubleValue(); // Normalize to 63 bits (minimum). int dividendBitLength = _dividend.bitLength(); int divisorBitLength = _divisor.bitLength(); if (dividendBitLength > divisorBitLength) { // Normalizes the divisor to 63 bits. int shift = divisorBitLength - 63;; long divisor = _divisor.shiftRight(shift).longValue(); LargeInteger dividend = _dividend.shiftRight(shift); return dividend.doubleValue() / divisor; } else { // Normalizes the dividend to 63 bits. int shift = dividendBitLength - 63;; long dividend = _dividend.shiftRight(shift).longValue(); LargeInteger divisor = _divisor.shiftRight(shift); return dividend / divisor.doubleValue(); } } /** * Compares two rational number numerically. * * @param that the rational number to compare with. * @return -1, 0 or 1 as this rational number is numerically less than, * equal to, or greater than that. */ public int compareTo(Rational that) { return this._dividend.times(that._divisor).compareTo( that._dividend.times(this._divisor)); } /** * Returns the normalized form of this rational. * * @return this rational after normalization. * @throws ArithmeticException if divisor.isZero() */ private Rational normalize() { if (!_divisor.isZero()) { if (_divisor.isPositive()) { LargeInteger gcd = _dividend.gcd(_divisor); if (!gcd.equals(LargeInteger.ONE)) { _dividend = _dividend.divide(gcd); _divisor = _divisor.divide(gcd); } return this; } else { _dividend = _dividend.opposite(); _divisor = _divisor.opposite(); return normalize(); } } else { throw new ArithmeticException("Zero divisor"); } } @Override public Rational copy() { Rational r = FACTORY.object(); r._dividend = _dividend.copy(); r._divisor = _divisor.copy(); return r; } private static final long serialVersionUID = 1L; }

Ads help maintain this website.