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}