All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.twelvemonkeys.imageio.metadata.tiff.Rational Maven / Gradle / Ivy

There is a newer version: 1.2.2.1-jre17
Show newest version
/*
 * Copyright (c) 2009, Harald Kuhr
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * * Redistributions of source code must retain the above copyright notice, this
 *   list of conditions and the following disclaimer.
 *
 * * Redistributions in binary form must reproduce the above copyright notice,
 *   this list of conditions and the following disclaimer in the documentation
 *   and/or other materials provided with the distribution.
 *
 * * Neither the name of the copyright holder nor the names of its
 *   contributors may be used to endorse or promote products derived from
 *   this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * Adapted from sample code featured in
 * "Intro to Programming in Java: An Interdisciplinary Approach" (Addison Wesley)
 * by Robert Sedgewick and Kevin Wayne. Permission granted to redistribute under BSD license.
 */

package com.twelvemonkeys.imageio.metadata.tiff;

/**
 * Represents a rational number with a {@code long} numerator and {@code long} denominator.
 * Rational numbers are stored in reduced form with the sign stored with the numerator.
 * Rationals are immutable.
 * 

* Adapted from sample code featured in * "Intro to Programming in Java: An Interdisciplinary Approach" (Addison Wesley) * by Robert Sedgewick and Kevin Wayne. Permission granted to redistribute under BSD license. *

* * @author Harald Kuhr * @author Robert Sedgewick and Kevin Wayne (original version) * @author last modified by $Author: haraldk$ * @version $Id: Rational.java,v 1.0 Nov 18, 2009 1:12:00 AM haraldk Exp$ */ public final class Rational extends Number implements Comparable { // TODO: Document public API // TODO: Move to com.tm.lang? // Inspired by http://www.cs.princeton.edu/introcs/92symbolic/Rational.java.html and java.lang.Integer static final Rational ZERO = new Rational(0, 1); static final Rational NaN = new Rational(); // TODO: This field needs thoughts/tests/spec/consistency check, see Float.NaN private final long numerator; private final long denominator; private Rational() { numerator = 0; denominator = 0; } public Rational(final long pNumber) { this(pNumber, 1); } public Rational(final long pNumerator, final long pDenominator) { if (pDenominator == 0) { throw new IllegalArgumentException("denominator == 0"); } if (pNumerator == Long.MIN_VALUE || pDenominator == Long.MIN_VALUE) { throw new IllegalArgumentException("value == Long.MIN_VALUE"); } // Reduce fractions long gcd = gcd(pNumerator, pDenominator); long num = pNumerator / gcd; long den = pDenominator / gcd; numerator = pDenominator >= 0 ? num : -num; denominator = pDenominator >= 0 ? den : -den; } private static long gcd(final long m, final long n) { if (m < 0) { return gcd(n, -m); } return n == 0 ? m : gcd(n, m % n); } private static long lcm(final long m, final long n) { if (m < 0) { return lcm(n, -m); } return m * (n / gcd(m, n)); // parentheses important to avoid overflow } public long numerator() { return numerator; } public long denominator() { return denominator; } /// Number implementation @Override public int intValue() { return (int) doubleValue(); } @Override public long longValue() { return (long) doubleValue(); } @Override public float floatValue() { return (float) doubleValue(); } @Override public double doubleValue() { if (this == NaN) { return Double.NaN; } return numerator / (double) denominator; } /// Comparable implementation public int compareTo(final Rational pOther) { double thisVal = doubleValue(); double otherVal = pOther.doubleValue(); return Double.compare(thisVal, otherVal); } /// Object overrides @Override public int hashCode() { return Float.floatToIntBits(floatValue()); } @Override public boolean equals(final Object pOther) { return pOther == this || pOther instanceof Rational && compareTo((Rational) pOther) == 0; } @Override public String toString() { if (this == NaN) { return "NaN"; } return denominator == 1 ? Long.toString(numerator) : String.format("%s/%s", numerator, denominator); } /// Operations (adapted from http://www.cs.princeton.edu/introcs/92symbolic/Rational.java.html) // TODO: Naming! multiply/divide/add/subtract or times/divides/plus/minus // return a * b, staving off overflow as much as possible by cross-cancellation public Rational times(final Rational pOther) { // special cases if (equals(ZERO) || pOther.equals(ZERO)) { return ZERO; } // reduce p1/q2 and p2/q1, then multiply, where a = p1/q1 and b = p2/q2 Rational c = new Rational(numerator, pOther.denominator); Rational d = new Rational(pOther.numerator, denominator); return new Rational(c.numerator * d.numerator, c.denominator * d.denominator); } // return a + b, staving off overflow public Rational plus(final Rational pOther) { // special cases if (equals(ZERO)) { return pOther; } if (pOther.equals(ZERO)) { return this; } // Find gcd of numerators and denominators long f = gcd(numerator, pOther.numerator); long g = gcd(denominator, pOther.denominator); // add cross-product terms for numerator // multiply back in return new Rational( ((numerator / f) * (pOther.denominator / g) + (pOther.numerator / f) * (denominator / g)) * f, lcm(denominator, pOther.denominator) ); } // return -a public Rational negate() { return new Rational(-numerator, denominator); } // return a - b public Rational minus(final Rational pOther) { return plus(pOther.negate()); } public Rational reciprocal() { return new Rational(denominator, numerator); } // return a / b public Rational divides(final Rational pOther) { if (pOther.equals(ZERO)) { throw new ArithmeticException("/ by zero"); } return times(pOther.reciprocal()); } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy