1 /*
2  * Copyright (C) 2012 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  */
16 
17 package android.renderscript.cts;
18 
19 import android.content.res.Resources;
20 import android.renderscript.Allocation;
21 import android.renderscript.RSRuntimeException;
22 
23 import java.util.Random;
24 
25 /**
26  * This class supplies some utils for renderscript tests
27  */
28 public class RSUtils {
29     public static final short FLOAT16_POSITIVE_INFINITY = (short) 0x7c00;
30     public static final short FLOAT16_NEGATIVE_INFINITY = (short) 0xfc00;
31     public static final short FLOAT16_MIN_NORMAL        = (short) 0x0400;  // 0.00006103516
32     public static final short FLOAT16_MAX_VALUE         = (short) 0x7bff;  // 65504
33 
34     private static final double[] sInterestingDoubles = {
35         0.0,
36         1.0,
37         Math.E,
38         Math.PI,
39         Math.PI / 2.0,
40         Math.PI * 2.0,
41         -0.0,
42         -1.0,
43         -Math.E,
44         -Math.PI,
45         -Math.PI / 2.0,
46         -Math.PI * 2.0,
47     };
48 
49     // Constants E, PI etc. are set to their nearest representations in Float16.
50     private static final short[] sInterestingFloat16s = {
51         (short) 0x0, // zero
52         (short) 0x3c00, // one
53         (short) 0x4170, // E, 2.71875000000
54         (short) 0x4248, // PI, 3.14062500000
55         (short) 0x3e48, // PI / 2, 1.57031250000
56         (short) 0x4648, // PI * 2, 6.28125000000
57 
58         (short) 0x8000, // negative zero
59         (short) 0xbc00, // negative one
60         (short) 0xc170, // -E, -2.71875000000
61         (short) 0xc248, // -PI, -3.14062500000
62         (short) 0xbe48, // -PI / 2, -1.57031250000
63         (short) 0xc648, // -PI * 2, -6.28125000000
64     };
65 
66     /**
67      * Fills the array with random doubles.  Values will be between min (inclusive) and
68      * max (inclusive).
69      */
genRandomDoubles(long seed, double min, double max, double array[], boolean includeExtremes)70     public static void genRandomDoubles(long seed, double min, double max, double array[],
71             boolean includeExtremes) {
72         Random r = new Random(seed);
73         int minExponent = Math.min(Math.getExponent(min), 0);
74         int maxExponent = Math.max(Math.getExponent(max), 0);
75         if (minExponent < -6 || maxExponent > 6) {
76             // Use an exponential distribution
77             int exponentDiff = maxExponent - minExponent;
78             for (int i = 0; i < array.length; i++) {
79                 double mantissa = r.nextDouble();
80                 int exponent = minExponent + r.nextInt(maxExponent - minExponent);
81                 int sign = (min >= 0) ? 1 : 1 - r.nextInt(2) * 2;  // -1 or 1
82                 double rand = sign * mantissa * Math.pow(2.0, exponent);
83                 if (rand < min || rand > max) {
84                     continue;
85                 }
86                 array[i] = rand;
87             }
88         } else {
89             // Use a linear distribution
90             for (int i = 0; i < array.length; i++) {
91                 double rand = r.nextDouble();
92                 array[i] = min + rand * (max - min);
93             }
94         }
95         // Seed a few special numbers we want to be sure to test.
96         for (int i = 0; i < sInterestingDoubles.length; i++) {
97             double d = sInterestingDoubles[i];
98             if (min <= d && d <= max) {
99                 array[r.nextInt(array.length)] = d;
100             }
101         }
102         array[r.nextInt(array.length)] = min;
103         array[r.nextInt(array.length)] = max;
104         if (includeExtremes) {
105             array[r.nextInt(array.length)] = Double.NaN;
106             array[r.nextInt(array.length)] = Double.POSITIVE_INFINITY;
107             array[r.nextInt(array.length)] = Double.NEGATIVE_INFINITY;
108             array[r.nextInt(array.length)] = Double.MIN_VALUE;
109             array[r.nextInt(array.length)] = Double.MIN_NORMAL;
110             array[r.nextInt(array.length)] = Double.MAX_VALUE;
111             array[r.nextInt(array.length)] = -Double.MIN_VALUE;
112             array[r.nextInt(array.length)] = -Double.MIN_NORMAL;
113             array[r.nextInt(array.length)] = -Double.MAX_VALUE;
114         }
115     }
116 
117     /**
118      * Fills the array with random floats.  Values will be between min (inclusive) and
119      * max (inclusive).
120      */
genRandomFloats(long seed, float min, float max, float array[], boolean includeExtremes)121     public static void genRandomFloats(long seed, float min, float max, float array[],
122             boolean includeExtremes) {
123         Random r = new Random(seed);
124         int minExponent = Math.min(Math.getExponent(min), 0);
125         int maxExponent = Math.max(Math.getExponent(max), 0);
126         if (minExponent < -6 || maxExponent > 6) {
127             // Use an exponential distribution
128             int exponentDiff = maxExponent - minExponent;
129             for (int i = 0; i < array.length; i++) {
130                 float mantissa = r.nextFloat();
131                 int exponent = minExponent + r.nextInt(maxExponent - minExponent);
132                 int sign = (min >= 0) ? 1 : 1 - r.nextInt(2) * 2;  // -1 or 1
133                 float rand = sign * mantissa * (float) Math.pow(2.0, exponent);
134                 if (rand < min || rand > max) {
135                     continue;
136                 }
137                 array[i] = rand;
138             }
139         } else {
140             // Use a linear distribution
141             for (int i = 0; i < array.length; i++) {
142                 float rand = r.nextFloat();
143                 array[i] = min + rand * (max - min);
144             }
145         }
146         // Seed a few special numbers we want to be sure to test.
147         for (int i = 0; i < sInterestingDoubles.length; i++) {
148             float f = (float) sInterestingDoubles[i];
149             if (min <= f && f <= max) {
150                 array[r.nextInt(array.length)] = f;
151             }
152         }
153         array[r.nextInt(array.length)] = min;
154         array[r.nextInt(array.length)] = max;
155         if (includeExtremes) {
156             array[r.nextInt(array.length)] = Float.NaN;
157             array[r.nextInt(array.length)] = Float.POSITIVE_INFINITY;
158             array[r.nextInt(array.length)] = Float.NEGATIVE_INFINITY;
159             array[r.nextInt(array.length)] = Float.MIN_VALUE;
160             array[r.nextInt(array.length)] = Float.MIN_NORMAL;
161             array[r.nextInt(array.length)] = Float.MAX_VALUE;
162             array[r.nextInt(array.length)] = -Float.MIN_VALUE;
163             array[r.nextInt(array.length)] = -Float.MIN_NORMAL;
164             array[r.nextInt(array.length)] = -Float.MAX_VALUE;
165         }
166     }
167 
genRandomFloat16s(long seed, double minDoubleValue, double maxDoubleValue, short array[], boolean includeExtremes)168     public static void genRandomFloat16s(long seed, double minDoubleValue, double maxDoubleValue,
169             short array[], boolean includeExtremes) {
170 
171         // Ensure that requests for random Float16s span a reasnoable range.
172         if (maxDoubleValue - minDoubleValue <= 1.) {
173             throw new RSRuntimeException("Unexpected: Range is too small");
174         }
175 
176         boolean includeNegatives = false;
177 
178         // Identify a range of 'short' values from the input range of 'double' If either
179         // minValueInHalf or maxValueInHalf is +/- infinity, use MAX_VALUE with appropriate sign
180         // instead.  The extreme values will get included if includeExtremes flag is set.
181         double minValueInHalf = Float16Utils.roundToFloat16(minDoubleValue)[1];
182         double maxValueInHalf = Float16Utils.roundToFloat16(maxDoubleValue)[0];
183 
184         if (Double.isInfinite(minValueInHalf)) {
185             minValueInHalf = Math.copySign(Float16Utils.MAX_VALUE, minValueInHalf);
186         }
187         if (Double.isInfinite(maxValueInHalf)) {
188             maxValueInHalf = Math.copySign(Float16Utils.MAX_VALUE, maxValueInHalf);
189         }
190 
191         short min = Float16Utils.convertDoubleToFloat16(minValueInHalf);
192         short max = Float16Utils.convertDoubleToFloat16(maxValueInHalf);
193 
194         // If range spans across zero, set the range to be entirely positive and set
195         // includeNegatives to true.  In this scenario, the upper bound is set to the larger of
196         // maxValue and abs(minValue).  The lower bound is FLOAT16_MIN_NORMAL.
197         if (minDoubleValue < 0. && maxDoubleValue > 0.) {
198             includeNegatives = true;
199             min = FLOAT16_MIN_NORMAL;
200 
201             // If abs(minDoubleValue) is greater than maxDoubleValue, pick abs(minValue) as the
202             // upper bound.
203             // TODO Update this function to generate random float16s exactly between minDoubleValue
204             // and maxDoubleValue.
205             if (Math.abs(minDoubleValue) > maxDoubleValue) {
206                 max = (short) (0x7fff & min);
207             }
208         } else if (maxDoubleValue < 0.) {
209             throw new RSRuntimeException("Unexpected: Range is entirely negative: " +
210                 Double.toString(minDoubleValue) + " to " + Double.toString(maxDoubleValue));
211         }
212 
213         // If min is 0 or subnormal, set it to FLOAT16_MIN_NORMAL
214         if (Float16Utils.isFloat16Zero(min) || Float16Utils.isFloat16SubNormal(min)) {
215             min = FLOAT16_MIN_NORMAL;
216         }
217 
218         Random r = new Random(seed);
219         short range = (short) (max - min + 1);
220         for (int i = 0; i < array.length; i ++) {
221             array[i] = (short) (min + r.nextInt(range));
222         }
223         array[r.nextInt(array.length)] = min;
224         array[r.nextInt(array.length)] = max;
225 
226         // Negate approximately half of the elements.
227         if (includeNegatives) {
228             for (int i = 0; i < array.length; i ++) {
229                 if (r.nextBoolean()) {
230                     array[i] = (short) (0x8000 | array[i]);
231                 }
232             }
233         }
234 
235         for (short s : sInterestingFloat16s) {
236             if (!includeNegatives && s < 0)
237                 continue;
238             array[r.nextInt(array.length)] = s;
239         }
240         if (includeExtremes) {
241             array[r.nextInt(array.length)] = (short) 0x7c01; // NaN
242             array[r.nextInt(array.length)] = FLOAT16_POSITIVE_INFINITY;
243             array[r.nextInt(array.length)] = FLOAT16_NEGATIVE_INFINITY;
244             array[r.nextInt(array.length)] = FLOAT16_MIN_NORMAL;
245             array[r.nextInt(array.length)] = FLOAT16_MAX_VALUE;
246             array[r.nextInt(array.length)] = (short) 0x8400; // -MIN_NORMAL, -0.00006103516
247             array[r.nextInt(array.length)] = (short) 0xfbff; // -MAX_VALUE, -65504
248         }
249     }
250 
251     /**
252      * Fills the array with random ints.  Values will be between min (inclusive) and
253      * max (inclusive).
254      */
genRandomInts(long seed, int min, int max, int array[])255     public static void genRandomInts(long seed, int min, int max, int array[]) {
256         Random r = new Random(seed);
257         for (int i = 0; i < array.length; i++) {
258             long range = max - min + 1;
259             array[i] = (int) (min + r.nextLong() % range);
260         }
261         array[r.nextInt(array.length)] = min;
262         array[r.nextInt(array.length)] = max;
263     }
264 
265     /**
266      * Fills the array with random longs.  If signed is true, negative values can be generated.
267      * The values will fit within 'numberOfBits'.  This is useful for conversion tests.
268      */
genRandomLongs(long seed, long array[], boolean signed, int numberOfBits)269     public static void genRandomLongs(long seed, long array[], boolean signed, int numberOfBits) {
270       long positiveMask = numberOfBits == 64 ? -1 : ((1l << numberOfBits) - 1);
271       long negativeMask = ~positiveMask;
272       Random r = new Random(seed);
273       for (int i = 0; i < array.length; i++) {
274           long l = r.nextLong();
275           if (signed && l < 0) {
276               l = l | negativeMask;
277           } else {
278               l = l & positiveMask;
279           }
280           array[i] = l;
281       }
282       // Seed a few special numbers we want to be sure to test.
283       array[r.nextInt(array.length)] = 0l;
284       array[r.nextInt(array.length)] = 1l;
285       array[r.nextInt(array.length)] = positiveMask;
286       if (signed) {
287           array[r.nextInt(array.length)] = negativeMask;
288           array[r.nextInt(array.length)] = -1;
289       }
290     }
291 
genRandomInts(long seed, int array[], boolean signed, int numberOfBits)292     public static void genRandomInts(long seed, int array[], boolean signed, int numberOfBits) {
293         long[] longs = new long[array.length];
294         genRandomLongs(seed, longs, signed, numberOfBits);
295         for (int i = 0; i < array.length; i++) {
296             array[i] = (int) longs[i];
297         }
298     }
299 
genRandomShorts(long seed, short array[], boolean signed, int numberOfBits)300     public static void genRandomShorts(long seed, short array[], boolean signed, int numberOfBits) {
301         long[] longs = new long[array.length];
302         genRandomLongs(seed, longs, signed, numberOfBits);
303         for (int i = 0; i < array.length; i++) {
304             array[i] = (short) longs[i];
305         }
306     }
307 
genRandomBytes(long seed, byte array[], boolean signed, int numberOfBits)308     public static void genRandomBytes(long seed, byte array[], boolean signed, int numberOfBits) {
309         long[] longs = new long[array.length];
310         genRandomLongs(seed, longs, signed, numberOfBits);
311         for (int i = 0; i < array.length; i++) {
312             array[i] = (byte) longs[i];
313         }
314     }
315 
316     // Compares two unsigned long.  Returns < 0 if a < b, 0 if a == b, > 0 if a > b.
compareUnsignedLong(long a, long b)317     public static long compareUnsignedLong(long a, long b) {
318         long aFirstFourBits = a >>> 60;
319         long bFirstFourBits = b >>> 60;
320         long firstFourBitsDiff = aFirstFourBits - bFirstFourBits;
321         if (firstFourBitsDiff != 0) {
322             return firstFourBitsDiff;
323         }
324         long aRest = a & 0x0fffffffffffffffl;
325         long bRest = b & 0x0fffffffffffffffl;
326         return aRest - bRest;
327     }
328 }
329