//----------------------------------------------------------------------------//
// //
// R a t i o n a l //
// //
//----------------------------------------------------------------------------//
// <editor-fold defaultstate="collapsed" desc="hdr"> //
// Copyright © Hervé Bitteur and others 2000-2013. All rights reserved. //
// This software is released under the GNU General Public License. //
// Goto http://kenai.com/projects/audiveris to report bugs or suggestions. //
//----------------------------------------------------------------------------//
// </editor-fold>
package omr.math;
import java.math.BigInteger;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
/**
* Class {@code Rational} implements non-mutable rational numbers
* (composed of a numerator and a denominator).
*
* <p>Invariants:<ol>
* <li>The rational data is always kept in reduced form : gcd(num,den)==1</li>
* <li>The denominator value is always kept positive : den >= 1</li>
* </ol></p>
*
* <p>It is (un)marshallable through JAXB.</p>
*
* @author Hervé Bitteur
*/
@XmlAccessorType(XmlAccessType.NONE)
@XmlRootElement(name = "rational")
public class Rational
implements Comparable<Rational>
{
//~ Static fields/initializers ---------------------------------------------
/** The zero rational instance */
public static final Rational ZERO = new Rational(0, 1);
/** The one rational instance */
public static final Rational ONE = new Rational(1, 1);
/** Max rational value */
public static final Rational MAX_VALUE = new Rational(Integer.MAX_VALUE, 1);
//~ Instance fields --------------------------------------------------------
/** Final denominator value */
@XmlAttribute
public final int den;
/** Final numerator value */
@XmlAttribute
public final int num;
//~ Constructors -----------------------------------------------------------
//----------//
// Rational //
//----------//
/**
* Create a final Rational instance
*
* @param num numerator value
* @param den denominator value
* @throws IllegalArgumentException if the provided denominator is zero
*/
public Rational (int num,
int den)
{
if (den == 0) {
throw new IllegalArgumentException("Denominator is zero");
}
// Reduction
int gcd = GCD.gcd(num, den);
num /= gcd;
den /= gcd;
// Positive denominator
if (den < 0) {
den = -den;
num = -num;
}
// Record final values
this.num = num;
this.den = den;
}
//----------//
// Rational //
//----------//
/** Needed for JAXB */
private Rational ()
{
num = den = 1;
}
//~ Methods ----------------------------------------------------------------
//-----//
// abs //
//-----//
/**
* Report the absolute value
*
* @return |num| / den
*/
public Rational abs ()
{
return new Rational(Math.abs(num), den);
}
//-----------//
// compareTo //
//-----------//
/**
* Comparison
*
* @param that the other rational instance
* @return -1,0,1 if this <,==,> that respectively
*/
@Override
public int compareTo (Rational that)
{
int a = this.num * that.den;
int b = this.den * that.num;
// Detect overflow, using the fact that den's are always >= 1
if ((Integer.signum(b) != Integer.signum(that.num))
|| (Integer.signum(a) != Integer.signum(this.num))) {
BigInteger bigThisNum = BigInteger.valueOf(this.num);
BigInteger bigThisDen = BigInteger.valueOf(this.den);
BigInteger bigThatNum = BigInteger.valueOf(that.num);
BigInteger bigThatDen = BigInteger.valueOf(that.den);
BigInteger A = bigThisNum.multiply(bigThatDen);
BigInteger B = bigThisDen.multiply(bigThatNum);
return A.compareTo(B);
} else {
return Integer.signum(a - b);
}
///return Integer.signum((this.num * that.den) - (this.den * that.num));
}
//---------//
// divides //
//---------//
/**
* Division
*
* @param that the other rational instance
* @return this / that
*/
public Rational divides (Rational that)
{
return times(that.inverse());
}
//---------//
// divides //
//---------//
/**
* Division
*
* @param that the integer to divide by
* @return this / that
*/
public Rational divides (int that)
{
return new Rational(num, den * that);
}
//--------//
// equals //
//--------//
/**
* Identity
*
* @param obj the instance to compare to
* @return true if this value equals that value
*/
@Override
public boolean equals (Object obj)
{
if (!(obj instanceof Rational)) {
return false;
} else {
return compareTo((Rational) obj) == 0;
}
}
//-----//
// gcd //
//-----//
public static Rational gcd (Rational a,
Rational b)
{
if (a.num == 0) {
return b;
} else {
return new Rational(1, GCD.lcm(a.den, b.den));
}
}
//-----//
// gcd //
//-----//
public static Rational gcd (Rational... vals)
{
Rational s = Rational.ZERO;
for (Rational val : vals) {
s = gcd(s, val);
}
return s;
}
//----------//
// hashCode //
//----------//
/** {@inheritDoc } */
@Override
public int hashCode ()
{
int hash = 5;
hash = (89 * hash) + den;
hash = (89 * hash) + num;
return hash;
}
//---------//
// inverse //
//---------//
/**
* Unary inversion
*
* @return 1 / this
*/
public Rational inverse ()
{
return new Rational(den, num);
}
//-------//
// minus //
//-------//
/**
* Substraction
*
* @param that the other rational instance
* @return this - that
*/
public Rational minus (Rational that)
{
return plus(that.opposite());
}
//-------//
// minus //
//-------//
/**
* Substraction
*
* @param that the integer to substract
* @return this - that
*/
public Rational minus (int that)
{
return plus(-that);
}
//----------//
// opposite //
//----------//
/**
* Unary negation
*
* @return -this
*/
public Rational opposite ()
{
return new Rational(-num, den);
}
//------//
// plus //
//------//
/**
* Addition
*
* @param that the other rational instance
* @return this + that
*/
public Rational plus (Rational that)
{
if (this.equals(ZERO)) {
return that;
}
if (that.equals(ZERO)) {
return this;
}
return new Rational(
(this.num * that.den) + (this.den * that.num),
this.den * that.den);
}
//------//
// plus //
//------//
/**
* Addition
*
* @param that the integer to add
* @return this + that
*/
public Rational plus (int that)
{
return plus(new Rational(that, 1));
}
//-------//
// times //
//-------//
/**
* Multiplication
*
* @param that the other rational instance
* @return this * that
*/
public Rational times (Rational that)
{
return new Rational(this.num * that.num, this.den * that.den);
}
//-------//
// times //
//-------//
/**
* Multiplication
*
* @param that the integer to multiply by
* @return this * that
*/
public Rational times (int that)
{
return new Rational(num * that, den);
}
//----------//
// toDouble //
//----------//
public double toDouble ()
{
return (double) num / den;
}
//----------//
// toString //
//----------//
/** {@inheritDoc } */
@Override
public String toString ()
{
if (den == 1) {
return num + "";
} else {
return num + "/" + den;
}
}
}