summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean-Luc Brouillet <jeanluc@google.com>2014-07-24 00:53:15 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2014-07-23 18:04:01 +0000
commit762716417cc8115b36ee6896f384faa313943262 (patch)
tree1a469df34f4f293f14b404dfe7754e588f622c77
parent1df878568c84a1510ff1a96506b3f4bb96b7269b (diff)
parent00c565bac18bb38784b077a7be6588efa7b93fbc (diff)
downloadcts-762716417cc8115b36ee6896f384faa313943262.tar.gz
Merge "Fix CTS tests precision issues."
-rw-r--r--tests/tests/renderscript/src/android/renderscript/cts/CoreMathVerifier.java42
-rw-r--r--tests/tests/renderscript/src/android/renderscript/cts/Floaty.java88
2 files changed, 113 insertions, 17 deletions
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/CoreMathVerifier.java b/tests/tests/renderscript/src/android/renderscript/cts/CoreMathVerifier.java
index 90f47dae643..f378ea4c69f 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/CoreMathVerifier.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/CoreMathVerifier.java
@@ -229,7 +229,9 @@ public class CoreMathVerifier {
new Floaty(point2[i], ulpFactor, ulpRelaxedFactor));
sum.add(Floaty.multiply(diff, diff));
}
- return Floaty.sqrt(sum);
+ Floaty d = Floaty.sqrt(sum);
+ d.setMinimumError(ulpFactor, ulpRelaxedFactor);
+ return d;
}
// Returns the length of the n-dimensional vector.
@@ -239,7 +241,9 @@ public class CoreMathVerifier {
Floaty f = new Floaty(array[i], ulpFactor, ulpRelaxedFactor);
sum.add(Floaty.multiply(f, f));
}
- return Floaty.sqrt(sum);
+ Floaty l = Floaty.sqrt(sum);
+ l.setMinimumError(ulpFactor, ulpRelaxedFactor);
+ return l;
}
// Normalizes the n-dimensional vector, i.e. makes it length 1.
@@ -255,7 +259,8 @@ public class CoreMathVerifier {
}
// Computes the cross product of two 3D vectors.
- static private void cross(float[] v1, float[] v2, Floaty[] out) {
+ static private void cross(float[] v1, float[] v2, Floaty[] out, int ulpFactor,
+ int ulpRelaxedFactor) {
Floaty a12 = Floaty.multiply(new Floaty(v1[1]), new Floaty(v2[2]));
Floaty a21 = Floaty.multiply(new Floaty(v1[2]), new Floaty(v2[1]));
out[0] = Floaty.subtract(a12, a21);
@@ -268,6 +273,14 @@ public class CoreMathVerifier {
if (out.length == 4) {
out[3] = new Floaty(0f);
}
+ setMinimumError(out, ulpFactor, ulpRelaxedFactor);
+ }
+
+ // Set a minimum error for every entry of out.
+ static void setMinimumError(Floaty[] out, int ulpFactor, int ulpRelaxedFactor) {
+ for (int i = 0; i < out.length; i++) {
+ out[i].setMinimumError(ulpFactor, ulpRelaxedFactor);
+ }
}
static public void computeAbs(TestAbs.ArgumentsCharUchar args) {
@@ -756,11 +769,14 @@ public class CoreMathVerifier {
}
static public void computeCospi(TestCospi.ArgumentsFloatFloat args) {
- args.out = new Floaty(cos(args.in * (float) Math.PI), 4, 128);
+ Floaty ip = new Floaty((float) ((double)args.in * Math.PI), 1, 1);
+ args.out = Floaty.FloatyFromRange(
+ (float) Math.cos(ip.getDoubleMin()),
+ (float) Math.cos(ip.getDoubleMax()), 4, 128);
}
static public void computeCross(TestCross.ArgumentsFloatNFloatNFloatN args) {
- cross(args.inLhs, args.inRhs, args.out);
+ cross(args.inLhs, args.inRhs, args.out, 1, 4);
}
static public void computeDegrees(TestDegrees.ArgumentsFloatFloat args) {
@@ -777,6 +793,7 @@ public class CoreMathVerifier {
static public void computeDot(TestDot.ArgumentsFloatFloatFloat args) {
args.out = new Floaty(args.inLhs * args.inRhs);
+ args.out.setMinimumError(1, 4);
}
static public void computeDot(TestDot.ArgumentsFloatNFloatNFloat args) {
@@ -787,6 +804,7 @@ public class CoreMathVerifier {
sum.add(Floaty.multiply(a, b));
}
args.out = sum;
+ args.out.setMinimumError(1, 4);
}
static public void computeErf(TestErf.ArgumentsFloatFloat args) {
@@ -847,7 +865,7 @@ public class CoreMathVerifier {
}
static public void computeFdim(TestFdim.ArgumentsFloatFloatFloat args) {
- args.out = new Floaty(Math.max(0f, args.inA - args.inB), 0, 0);
+ args.out = new Floaty(Math.max(0f, args.inA - args.inB), 0, 1);
}
static public void computeFloor(TestFloor.ArgumentsFloatFloat args) {
@@ -960,6 +978,7 @@ public class CoreMathVerifier {
static public void computeMad(TestMad.ArgumentsFloatFloatFloatFloat args) {
args.out = Floaty.add(new Floaty(args.inA * args.inB), new Floaty(args.inC));
+ args.out.setMinimumError(1, 4);
}
static public void computeMax(TestMax.ArgumentsCharCharChar args) {
@@ -1043,6 +1062,7 @@ public class CoreMathVerifier {
Floaty stop = new Floaty(args.inStop);
Floaty diff = Floaty.subtract(stop, start);
args.out = Floaty.add(start, Floaty.multiply(diff, new Floaty(args.inAmount)));
+ args.out.setMinimumError(1, 4);
}
static public void computeModf(TestModf.ArgumentsFloatFloatFloat args) {
@@ -1183,7 +1203,10 @@ public class CoreMathVerifier {
}
static public void computeSinpi(TestSinpi.ArgumentsFloatFloat args) {
- args.out = new Floaty(sin(args.in * (float) Math.PI), 4, 128);
+ Floaty ip = new Floaty((float) ((double)args.in * Math.PI), 1, 1);
+ args.out = Floaty.FloatyFromRange(
+ (float) Math.sin(ip.getDoubleMin()),
+ (float) Math.sin(ip.getDoubleMax()), 4, 128);
}
static public void computeSqrt(TestSqrt.ArgumentsFloatFloat args) {
@@ -1203,7 +1226,10 @@ public class CoreMathVerifier {
}
static public void computeTanpi(TestTanpi.ArgumentsFloatFloat args) {
- args.out = new Floaty(tan(args.in * (float) Math.PI), 6, 128);
+ Floaty ip = new Floaty((float) ((double)args.in * Math.PI), 1, 1);
+ args.out = Floaty.FloatyFromRange(
+ (float) Math.tan(ip.getDoubleMin()),
+ (float) Math.tan(ip.getDoubleMax()), 4, 128);
}
static public void computeTgamma(TestTgamma.ArgumentsFloatFloat args) {
diff --git a/tests/tests/renderscript/src/android/renderscript/cts/Floaty.java b/tests/tests/renderscript/src/android/renderscript/cts/Floaty.java
index 608e172ff94..85b00cee529 100644
--- a/tests/tests/renderscript/src/android/renderscript/cts/Floaty.java
+++ b/tests/tests/renderscript/src/android/renderscript/cts/Floaty.java
@@ -24,8 +24,12 @@ import android.util.Log;
* compute the correct error of the result.
*/
public class Floaty {
- private double mValue; // The value this instance represent.
- private double mError; // The real value should be between mValue - mError and mValue + mError.
+ // The value this instance represents.
+ private double mValue;
+ /* The real value should be between mValue - mError and mValue + mError.
+ * mError should be positive.
+ */
+ private double mError;
/* The number of bits the value should have, either 32 or 64. It would have been nice to
* use generics, e.g. Floaty<float> and Floaty<double> but Java does not support generics
* of float and double. Also, Java does not have a f16 type. This can simulate it, although
@@ -57,6 +61,30 @@ public class Floaty {
setErrorFromValue(1, 1);
}
+ /** Creates a Floaty for which any value between a and b are legal, expanded by the specified factor. */
+ public static Floaty FloatyFromRange(float a, float b, float ulpFactor, float ulpRelaxedFactor) {
+ // Order the edges of the range.
+ float min, max;
+ if (a < b) {
+ min = a;
+ max = b;
+ } else {
+ min = b;
+ max = a;
+ }
+ // Expand the edges by the specified factor.
+ float factor = relaxed ? ulpRelaxedFactor : ulpFactor;
+ min = min + (Math.nextAfter(min, -Float.MAX_VALUE) - min) * factor;
+ max = max + (Math.nextAfter(max, Float.MAX_VALUE) - max) * factor;
+
+ // Convert a [range] to a (mid +- error)
+ float delta = Math.abs(a - b);
+ float mid = (min + max) / 2.f;
+ Floaty fl = new Floaty(mid);
+ fl.mError = Math.max(mid - min, max - mid);
+ return fl;
+ }
+
/** Sets the value and the error based on whether we're doing relaxed computations or not. */
public Floaty(float v, int ulpFactor, int ulpRelaxedFactor) {
mValue = v;
@@ -76,12 +104,17 @@ public class Floaty {
public float getFloatError() { return (float) mError; }
public double getDoubleError() { return mError; }
+ public double getDoubleMin() { return mValue - mError; }
+ public double getDoubleMax() { return mValue + mError; }
+
/** Returns the number we would need to multiply the ulp to get the current error. */
public int getUlf() {
- return (int) Math.abs(mError / getUlp());
+ return (int) (mError / getUlp() + 0.5);
}
- /** Returns the unit of least precision for the number we handle. */
+ /** Returns the unit of least precision for the number we handle. This is
+ * always a positive number.
+ */
private double getUlp() {
if (mNumberOfBits == 64) {
return Math.ulp(mValue);
@@ -112,7 +145,7 @@ public class Floaty {
mError *= relaxed ? ulpRelaxedFactor : ulpFactor;
mNumberOfBits = numberOfBits;
}
-
+
/** If needed, increases the error so that the provided value is covered by the error range. */
private void expandError(double valueWithError) {
// We disregard NaN values that can be produced when testing close to a cliff.
@@ -125,6 +158,14 @@ public class Floaty {
}
}
+ /** Makes sure the allowed error is at least ulp{Relaxed}Factor. */
+ public void setMinimumError(int ulpFactor, int ulpRelaxedFactor) {
+ double minError = getUlp() * (relaxed ? ulpRelaxedFactor : ulpFactor);
+ if (mError < minError) {
+ mError = minError;
+ }
+ }
+
/** Returns true if the number passed is within mError of our value. */
public boolean couldBe(double a) {
return couldBe(a, 0.0);
@@ -133,7 +174,7 @@ public class Floaty {
/**
* Returns true if the number passed is within mError of our value, or if it's whithin
* minimumError of the value.
- */
+ */
public boolean couldBe(double a, double minimumError) {
if (a != a && mValue != mValue) {
return true; // Both are NaN
@@ -146,11 +187,40 @@ public class Floaty {
double error = Math.max(mError, minimumError);
boolean inRange = mValue - error <= a && a <= mValue + error;
+ /* For relaxed precision, some implementations don't return denormalized values for very
+ * subnormal values. Two examples:
+ * a) nextafter(0.0, 1.0): When denormalized are allowed, 1.40129846e-45 (0x00000001) is
+ * expected. If only normalized values are returned, 1.1754944e-38 (0x00800000) is
+ * expected.
+ * b) powr(1600.4, -11.9): With denormalized, 7.4076481e-39 is returned. For normalized,
+ * 0.0 can be returned.
+ */
+ if (!inRange && relaxed) {
+ boolean isSubnormal = false;
+ double normalized = 0.0;
+ // Check if we have a subnormal value.
+ if (mNumberOfBits == 32 && Math.abs(mValue) < Float.MIN_NORMAL) {
+ isSubnormal = true;
+ normalized = Math.copySign(Float.MIN_NORMAL, (float) mValue);
+ } else if (Math.abs(mValue) < Double.MIN_NORMAL) {
+ isSubnormal = true;
+ normalized = Math.copySign(Double.MIN_NORMAL, mValue);
+ }
+ if (isSubnormal) {
+ // First try replacing the expected value with the larger MIN_NORMAL
+ inRange = (normalized - error) <= a && a <= (normalized + error);
+ // Second try replacing the expected value with 0.
+ if (!inRange) {
+ inRange = -error <= a && a <= error;
+ }
+ }
+ }
+
/* This is useful for debugging:
if (!inRange) {
- int ulfNeeded = (int) Math.abs(Math.round((a - mValue) / Math.ulp(mValue)));
- Log.e("Floaty.couldBe", "Comparing " + Float.toString(a) +
- " against " + Float.toString(mValue) + " +- " + Float.toString(error) +
+ int ulfNeeded = (int) Math.abs(Math.round((a - mValue) / getUlp()));
+ Log.e("Floaty.couldBe", "Comparing " + Double.toString(a) +
+ " against " + Double.toString(mValue) + " +- " + Double.toString(error) +
" relaxed " + Boolean.toString(relaxed) +
" ulfNeeded " + Integer.toString(ulfNeeded) +
", off by " + Integer.toString(ulfNeeded - getUlf()));