/* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.hardware.camera2; /** * The rational data type used by CameraMetadata keys. Contains a pair of ints representing the * numerator and denominator of a Rational number. This type is immutable. */ public final class Rational { private final int mNumerator; private final int mDenominator; /** *

Create a Rational with a given numerator and denominator.

* *

The signs of the numerator and the denominator may be flipped such that the denominator * is always positive.

* *

A rational value with a 0-denominator may be constructed, but will have similar semantics * as float NaN and INF values. The int getter functions return 0 in this case.

* * @param numerator the numerator of the rational * @param denominator the denominator of the rational */ public Rational(int numerator, int denominator) { if (denominator < 0) { numerator = -numerator; denominator = -denominator; } mNumerator = numerator; mDenominator = denominator; } /** * Gets the numerator of the rational. */ public int getNumerator() { if (mDenominator == 0) { return 0; } return mNumerator; } /** * Gets the denominator of the rational */ public int getDenominator() { return mDenominator; } private boolean isNaN() { return mDenominator == 0 && mNumerator == 0; } private boolean isInf() { return mDenominator == 0 && mNumerator > 0; } private boolean isNegInf() { return mDenominator == 0 && mNumerator < 0; } /** *

Compare this Rational to another object and see if they are equal.

* *

A Rational object can only be equal to another Rational object (comparing against any other * type will return false).

* *

A Rational object is considered equal to another Rational object if and only if one of * the following holds

: * * *

A reduced form of a Rational is calculated by dividing both the numerator and the * denominator by their greatest common divisor.

* *
     *      (new Rational(1, 2)).equals(new Rational(1, 2)) == true   // trivially true
     *      (new Rational(2, 3)).equals(new Rational(1, 2)) == false  // trivially false
     *      (new Rational(1, 2)).equals(new Rational(2, 4)) == true   // true after reduction
     *      (new Rational(0, 0)).equals(new Rational(0, 0)) == true   // NaN.equals(NaN)
     *      (new Rational(1, 0)).equals(new Rational(5, 0)) == true   // both are +infinity
     *      (new Rational(1, 0)).equals(new Rational(-1, 0)) == false // +infinity != -infinity
     * 
* * @param obj a reference to another object * * @return A boolean that determines whether or not the two Rational objects are equal. */ @Override public boolean equals(Object obj) { if (obj == null) { return false; } else if (obj instanceof Rational) { Rational other = (Rational) obj; if (mDenominator == 0 || other.mDenominator == 0) { if (isNaN() && other.isNaN()) { return true; } else if (isInf() && other.isInf() || isNegInf() && other.isNegInf()) { return true; } else { return false; } } else if (mNumerator == other.mNumerator && mDenominator == other.mDenominator) { return true; } else { int thisGcd = gcd(); int otherGcd = other.gcd(); int thisNumerator = mNumerator / thisGcd; int thisDenominator = mDenominator / thisGcd; int otherNumerator = other.mNumerator / otherGcd; int otherDenominator = other.mDenominator / otherGcd; return (thisNumerator == otherNumerator && thisDenominator == otherDenominator); } } return false; } @Override public String toString() { if (isNaN()) { return "NaN"; } else if (isInf()) { return "Infinity"; } else if (isNegInf()) { return "-Infinity"; } else { return mNumerator + "/" + mDenominator; } } /** *

Convert to a floating point representation.

* * @return The floating point representation of this rational number. * @hide */ public float toFloat() { return (float) mNumerator / (float) mDenominator; } @Override public int hashCode() { final long INT_MASK = 0xffffffffL; long asLong = INT_MASK & mNumerator; asLong <<= 32; asLong |= (INT_MASK & mDenominator); return ((Long)asLong).hashCode(); } /** * Calculates the greatest common divisor using Euclid's algorithm. * * @return An int value representing the gcd. Always positive. * @hide */ public int gcd() { /** * Non-recursive implementation of Euclid's algorithm: * * gcd(a, 0) := a * gcd(a, b) := gcd(b, a mod b) * */ int a = mNumerator; int b = mDenominator; while (b != 0) { int oldB = b; b = a % b; a = oldB; } return Math.abs(a); } }