1/* 2 * Copyright (C) 2013 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16package android.hardware.camera2; 17 18/** 19 * The rational data type used by CameraMetadata keys. Contains a pair of ints representing the 20 * numerator and denominator of a Rational number. This type is immutable. 21 */ 22public final class Rational { 23 private final int mNumerator; 24 private final int mDenominator; 25 26 /** 27 * <p>Create a Rational with a given numerator and denominator.</p> 28 * 29 * <p>The signs of the numerator and the denominator may be flipped such that the denominator 30 * is always positive.</p> 31 * 32 * <p>A rational value with a 0-denominator may be constructed, but will have similar semantics 33 * as float NaN and INF values. The int getter functions return 0 in this case.</p> 34 * 35 * @param numerator the numerator of the rational 36 * @param denominator the denominator of the rational 37 */ 38 public Rational(int numerator, int denominator) { 39 40 if (denominator < 0) { 41 numerator = -numerator; 42 denominator = -denominator; 43 } 44 45 mNumerator = numerator; 46 mDenominator = denominator; 47 } 48 49 /** 50 * Gets the numerator of the rational. 51 */ 52 public int getNumerator() { 53 if (mDenominator == 0) { 54 return 0; 55 } 56 return mNumerator; 57 } 58 59 /** 60 * Gets the denominator of the rational 61 */ 62 public int getDenominator() { 63 return mDenominator; 64 } 65 66 private boolean isNaN() { 67 return mDenominator == 0 && mNumerator == 0; 68 } 69 70 private boolean isInf() { 71 return mDenominator == 0 && mNumerator > 0; 72 } 73 74 private boolean isNegInf() { 75 return mDenominator == 0 && mNumerator < 0; 76 } 77 78 /** 79 * <p>Compare this Rational to another object and see if they are equal.</p> 80 * 81 * <p>A Rational object can only be equal to another Rational object (comparing against any other 82 * type will return false).</p> 83 * 84 * <p>A Rational object is considered equal to another Rational object if and only if one of 85 * the following holds</p>: 86 * <ul><li>Both are NaN</li> 87 * <li>Both are infinities of the same sign</li> 88 * <li>Both have the same numerator and denominator in their reduced form</li> 89 * </ul> 90 * 91 * <p>A reduced form of a Rational is calculated by dividing both the numerator and the 92 * denominator by their greatest common divisor.</p> 93 * 94 * <pre> 95 * (new Rational(1, 2)).equals(new Rational(1, 2)) == true // trivially true 96 * (new Rational(2, 3)).equals(new Rational(1, 2)) == false // trivially false 97 * (new Rational(1, 2)).equals(new Rational(2, 4)) == true // true after reduction 98 * (new Rational(0, 0)).equals(new Rational(0, 0)) == true // NaN.equals(NaN) 99 * (new Rational(1, 0)).equals(new Rational(5, 0)) == true // both are +infinity 100 * (new Rational(1, 0)).equals(new Rational(-1, 0)) == false // +infinity != -infinity 101 * </pre> 102 * 103 * @param obj a reference to another object 104 * 105 * @return A boolean that determines whether or not the two Rational objects are equal. 106 */ 107 @Override 108 public boolean equals(Object obj) { 109 if (obj == null) { 110 return false; 111 } else if (obj instanceof Rational) { 112 Rational other = (Rational) obj; 113 if (mDenominator == 0 || other.mDenominator == 0) { 114 if (isNaN() && other.isNaN()) { 115 return true; 116 } else if (isInf() && other.isInf() || isNegInf() && other.isNegInf()) { 117 return true; 118 } else { 119 return false; 120 } 121 } else if (mNumerator == other.mNumerator && mDenominator == other.mDenominator) { 122 return true; 123 } else { 124 int thisGcd = gcd(); 125 int otherGcd = other.gcd(); 126 127 int thisNumerator = mNumerator / thisGcd; 128 int thisDenominator = mDenominator / thisGcd; 129 130 int otherNumerator = other.mNumerator / otherGcd; 131 int otherDenominator = other.mDenominator / otherGcd; 132 133 return (thisNumerator == otherNumerator && thisDenominator == otherDenominator); 134 } 135 } 136 return false; 137 } 138 139 @Override 140 public String toString() { 141 if (isNaN()) { 142 return "NaN"; 143 } else if (isInf()) { 144 return "Infinity"; 145 } else if (isNegInf()) { 146 return "-Infinity"; 147 } else { 148 return mNumerator + "/" + mDenominator; 149 } 150 } 151 152 /** 153 * <p>Convert to a floating point representation.</p> 154 * 155 * @return The floating point representation of this rational number. 156 * @hide 157 */ 158 public float toFloat() { 159 return (float) mNumerator / (float) mDenominator; 160 } 161 162 @Override 163 public int hashCode() { 164 final long INT_MASK = 0xffffffffL; 165 166 long asLong = INT_MASK & mNumerator; 167 asLong <<= 32; 168 169 asLong |= (INT_MASK & mDenominator); 170 171 return ((Long)asLong).hashCode(); 172 } 173 174 /** 175 * Calculates the greatest common divisor using Euclid's algorithm. 176 * 177 * @return An int value representing the gcd. Always positive. 178 * @hide 179 */ 180 public int gcd() { 181 /** 182 * Non-recursive implementation of Euclid's algorithm: 183 * 184 * gcd(a, 0) := a 185 * gcd(a, b) := gcd(b, a mod b) 186 * 187 */ 188 189 int a = mNumerator; 190 int b = mDenominator; 191 192 while (b != 0) { 193 int oldB = b; 194 195 b = a % b; 196 a = oldB; 197 } 198 199 return Math.abs(a); 200 } 201} 202