From 23c8809568b68430f875df759108c58016c44c16 Mon Sep 17 00:00:00 2001 From: Timothy Knight Date: Wed, 21 Aug 2013 14:33:40 -0700 Subject: [PATCH] Camera2: Updated Rational for denom=0. Handle NaN and INF using the same semantics as Java floats. No longer throw an exception if a rational is constructed with a zero-denominator. This commit is required for the ITS pdk app, since without it, the app fails when it tries to deserialize rational values that are (incorrectly) set to 0/0. Bug: 10337323 Change-Id: I890ec2092f2945abc0f531fc46f9a7f5c71d2dbf --- .../android/hardware/camera2/Rational.java | 83 ++++++++++++++----- .../mediaframeworktest/unit/RationalTest.java | 51 ++++++++++-- 2 files changed, 105 insertions(+), 29 deletions(-) diff --git a/core/java/android/hardware/camera2/Rational.java b/core/java/android/hardware/camera2/Rational.java index 0260e021dc98b..77b8c2685441d 100644 --- a/core/java/android/hardware/camera2/Rational.java +++ b/core/java/android/hardware/camera2/Rational.java @@ -26,22 +26,17 @@ public final class Rational { /** *

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 0. - *

+ *

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 - * - * @throws IllegalArgumentException if the denominator is 0 */ public Rational(int numerator, int denominator) { - if (denominator == 0) { - throw new IllegalArgumentException("Argument 'denominator' is 0"); - } - if (denominator < 0) { numerator = -numerator; denominator = -denominator; @@ -55,6 +50,9 @@ public final class Rational { * Gets the numerator of the rational. */ public int getNumerator() { + if (mDenominator == 0) { + return 0; + } return mNumerator; } @@ -65,22 +63,41 @@ public final class Rational { 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 their - * reduced forms have the same numerator and denominator.

+ *

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(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 @@ -91,13 +108,17 @@ public final class Rational { public boolean equals(Object obj) { if (obj == null) { return false; - } - if (this == obj) { - return true; - } - if (obj instanceof Rational) { + } else if (obj instanceof Rational) { Rational other = (Rational) obj; - if(mNumerator == other.mNumerator && mDenominator == other.mDenominator) { + 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(); @@ -117,7 +138,25 @@ public final class Rational { @Override public String toString() { - return mNumerator + "/" + mDenominator; + 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 diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java index 926719c691a11..9621f92b78f53 100644 --- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java +++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/RationalTest.java @@ -50,12 +50,20 @@ public class RationalTest extends junit.framework.TestCase { assertEquals(1, r.getNumerator()); assertEquals(2, r.getDenominator()); - // Dividing by zero is not allowed - try { - r = new Rational(1, 0); - fail("Expected Rational constructor to throw an IllegalArgumentException"); - } catch(IllegalArgumentException e) { - } + // Infinity. + r = new Rational(1, 0); + assertEquals(0, r.getNumerator()); + assertEquals(0, r.getDenominator()); + + // Negative infinity. + r = new Rational(-1, 0); + assertEquals(0, r.getNumerator()); + assertEquals(0, r.getDenominator()); + + // NaN. + r = new Rational(0, 0); + assertEquals(0, r.getNumerator()); + assertEquals(0, r.getDenominator()); } @SmallTest @@ -110,5 +118,34 @@ public class RationalTest extends junit.framework.TestCase { assertEquals(moreComplicated, moreComplicated2); assertEquals(moreComplicated2, moreComplicated); + Rational nan = new Rational(0, 0); + Rational nan2 = new Rational(0, 0); + assertTrue(nan.equals(nan)); + assertTrue(nan.equals(nan2)); + assertTrue(nan2.equals(nan)); + assertFalse(nan.equals(r)); + assertFalse(r.equals(nan)); + + // Infinities of the same sign are equal. + Rational posInf = new Rational(1, 0); + Rational posInf2 = new Rational(2, 0); + Rational negInf = new Rational(-1, 0); + Rational negInf2 = new Rational(-2, 0); + assertEquals(posInf, posInf); + assertEquals(negInf, negInf); + assertEquals(posInf, posInf2); + assertEquals(negInf, negInf2); + + // Infinities aren't equal to anything else. + assertFalse(posInf.equals(negInf)); + assertFalse(negInf.equals(posInf)); + assertFalse(negInf.equals(r)); + assertFalse(posInf.equals(r)); + assertFalse(r.equals(negInf)); + assertFalse(r.equals(posInf)); + assertFalse(posInf.equals(nan)); + assertFalse(negInf.equals(nan)); + assertFalse(nan.equals(posInf)); + assertFalse(nan.equals(negInf)); } -} \ No newline at end of file +}