Rational.java revision 2f1a2e423e0fbb64467d6fcfa4e82c6384f31210
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>
30     * The signs of the numerator and the denominator may be flipped such that the denominator
31     * is always 0.
32     * </p>
33     *
34     * @param numerator the numerator of the rational
35     * @param denominator the denominator of the rational
36     *
37     * @throws IllegalArgumentException if the denominator is 0
38     */
39    public Rational(int numerator, int denominator) {
40
41        if (denominator == 0) {
42            throw new IllegalArgumentException("Argument 'denominator' is 0");
43        }
44
45        if (denominator < 0) {
46            numerator = -numerator;
47            denominator = -denominator;
48        }
49
50        mNumerator = numerator;
51        mDenominator = denominator;
52    }
53
54    /**
55     * Gets the numerator of the rational.
56     */
57    public int getNumerator() {
58        return mNumerator;
59    }
60
61    /**
62     * Gets the denominator of the rational
63     */
64    public int getDenominator() {
65        return mDenominator;
66    }
67
68    /**
69     * <p>Compare this Rational to another object and see if they are equal.</p>
70     *
71     * <p>A Rational object can only be equal to another Rational object (comparing against any other
72     * type will return false).</p>
73     *
74     * <p>A Rational object is considered equal to another Rational object if and only if their
75     * reduced forms have the same numerator and denominator.</p>
76     *
77     * <p>A reduced form of a Rational is calculated by dividing both the numerator and the
78     * denominator by their greatest common divisor.</p>
79     *
80     * <pre>
81     *      (new Rational(1, 2)).equals(new Rational(1, 2)) == true  // trivially true
82     *      (new Rational(2, 3)).equals(new Rational(1, 2)) == false // trivially false
83     *      (new Rational(1, 2)).equals(new Rational(2, 4)) == true  // true after reduction
84     * </pre>
85     *
86     * @param obj a reference to another object
87     *
88     * @return boolean that determines whether or not the two Rational objects are equal.
89     */
90    @Override
91    public boolean equals(Object obj) {
92        if (obj == null) {
93            return false;
94        }
95        if (this == obj) {
96            return true;
97        }
98        if (obj instanceof Rational) {
99            Rational other = (Rational) obj;
100            if(mNumerator == other.mNumerator && mDenominator == other.mDenominator) {
101                return true;
102            } else {
103                int thisGcd = gcd();
104                int otherGcd = other.gcd();
105
106                int thisNumerator = mNumerator / thisGcd;
107                int thisDenominator = mDenominator / thisGcd;
108
109                int otherNumerator = other.mNumerator / otherGcd;
110                int otherDenominator = other.mDenominator / otherGcd;
111
112                return (thisNumerator == otherNumerator && thisDenominator == otherDenominator);
113            }
114        }
115        return false;
116    }
117
118    @Override
119    public String toString() {
120        return mNumerator + "/" + mDenominator;
121    }
122
123    @Override
124    public int hashCode() {
125        final long INT_MASK = 0xffffffffL;
126
127        long asLong = INT_MASK & mNumerator;
128        asLong <<= 32;
129
130        asLong |= (INT_MASK & mDenominator);
131
132        return ((Long)asLong).hashCode();
133    }
134
135    /**
136     * Calculates the greatest common divisor using Euclid's algorithm.
137     *
138     * @return int value representing the gcd. Always positive.
139     * @hide
140     */
141    public int gcd() {
142        /**
143         * Non-recursive implementation of Euclid's algorithm:
144         *
145         *  gcd(a, 0) := a
146         *  gcd(a, b) := gcd(b, a mod b)
147         *
148         */
149
150        int a = mNumerator;
151        int b = mDenominator;
152
153        while (b != 0) {
154            int oldB = b;
155
156            b = a % b;
157            a = oldB;
158        }
159
160        return Math.abs(a);
161    }
162}
163