1 /*
2  * Copyright (C) 2015 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 java.util.Random;
20 import java.lang.Math;
21 import java.lang.Float;
22 import java.lang.Integer;
23 import java.lang.Short;
24 
25 import android.content.Context;
26 import android.content.res.Resources;
27 import android.renderscript.Allocation;
28 import android.renderscript.cts.Float16Utils;
29 import android.renderscript.Element;
30 import android.renderscript.RenderScript;
31 import android.renderscript.RSRuntimeException;
32 import android.renderscript.Script;
33 import android.renderscript.Type;
34 import android.util.Log;
35 
36 public class Float16ArithmeticTest extends RSBaseCompute {
37     private int numInputs = Float16TestData.input.length;
38 
39     private ScriptC_float16_arithmetic script;
40 
41     // Allocations to hold float16 input and output
42     private Allocation mInput;
43     private Allocation mF16Matrix;
44     private Allocation mU16Matrix;
45 
46     // A numInputs * numInputs length 1-D array with data copied from
47     // mU16Matrix
48     private short[] output = new short[numInputs * numInputs];
49 
50     // Create input, intermediate, and output allocations.  Copy input data to
51     // the input allocation
52     @Override
setUp()53     protected void setUp() throws Exception {
54         super.setUp();
55 
56         Element f16 = Element.F16(mRS);
57         Element u16 = Element.U16(mRS);
58         Type f16Matrix = Type.createXY(mRS, f16, numInputs, numInputs);
59         Type u16Matrix = Type.createXY(mRS, u16, numInputs, numInputs);
60 
61         mInput = Allocation.createSized(mRS, f16, numInputs);
62         mF16Matrix = Allocation.createTyped(mRS, f16Matrix);
63         mU16Matrix = Allocation.createTyped(mRS, u16Matrix);
64 
65         mInput.copyFromUnchecked(Float16TestData.input);
66 
67         script = new ScriptC_float16_arithmetic(mRS);
68     }
69 
70     @Override
tearDown()71     protected void tearDown() throws Exception {
72         mInput.destroy();
73         mF16Matrix.destroy();
74         mU16Matrix.destroy();
75         script.destroy();
76         super.tearDown();
77     }
78 
79     // Check the output of performing 'operation' on inputs x and y against the
80     // reference output in refValues.  For special cases like Infinity, NaN and
81     // zero, use exact comparison.  Otherwise, check if the output is within
82     // the bounds in 'refValues' by converting all values to float.
checkFloat16Output(int x, int y, short[][][] refValues, String operation)83     private boolean checkFloat16Output(int x, int y, short[][][] refValues,
84                                        String operation)
85     {
86         // Find the input, output and reference values based on the indices
87         short in1 = Float16TestData.input[x];
88         short in2 = Float16TestData.input[y];
89         short out = output[x + y * numInputs];
90         short lb = refValues[x][y][0];
91         short ub = refValues[x][y][1];
92 
93         // Do exact match if the reference value is a special case (Nan, zero
94         // infinity or their negative equivalents).
95         if (Float16Utils.isFloat16Infinite(lb))
96             return lb == out;
97         // NaN can have any non-zero mantissa.  Do not use equality check
98         if (Float16Utils.isFloat16NaN(lb))
99             return Float16Utils.isFloat16NaN(out);
100         // If reference output is zero, test for exact equivalence if at least
101         // one of the input values is a special-case FP16 value.
102         if (Float16Utils.isFloat16Zero(lb)) {
103             if (!Float16Utils.isFloat16FiniteNonZero(in1) ||
104                 !Float16Utils.isFloat16FiniteNonZero(in2)) {
105                 return lb == out;
106             }
107         }
108 
109         float floatLB = Float16Utils.convertFloat16ToFloat(lb);
110         float floatUB = Float16Utils.convertFloat16ToFloat(ub);
111         float floatOut = Float16Utils.convertFloat16ToFloat(out);
112 
113         if (floatOut < floatLB || floatOut > floatUB) {
114             StringBuilder message = new StringBuilder();
115             message.append("Incorrect output for float16 " + operation + ":");
116             message.append("\nInput 1: " + Short.toString(in1));
117             message.append("\nInput 2: " + Short.toString(in2));
118             message.append("\nExpected output between: " + Short.toString(lb) +
119                            " and " + Short.toString(ub));
120             message.append("\nActual   output: " + Short.toString(out));
121             message.append("\nExpected output (in float) between: " +
122                            Float.toString(floatLB) + " and " + Float.toString(floatUB));
123             message.append("\nActual   output: " + Float.toString(floatOut));
124             assertTrue(message.toString(), false);
125         }
126         return true;
127     }
128 
checkFloat16Add(int x, int y)129     private boolean checkFloat16Add(int x, int y) {
130         return checkFloat16Output(x, y, Float16TestData.ReferenceOutputForAdd,
131                                   "addition");
132     }
133 
testFloat16Add()134     public void testFloat16Add() {
135         script.set_gInput(mInput);
136         script.forEach_add(mF16Matrix);
137         script.forEach_bitcast(mF16Matrix, mU16Matrix);
138         mU16Matrix.copyTo(output);
139 
140         for (int x = 0; x < numInputs; x ++) {
141             for (int y = 0; y < numInputs; y ++) {
142                 checkFloat16Add(x, y);
143             }
144         }
145     }
146 
checkFloat16Sub(int x, int y)147     private boolean checkFloat16Sub(int x, int y) {
148         return checkFloat16Output(x, y, Float16TestData.ReferenceOutputForSub,
149                                   "subtraction");
150     }
151 
testFloat16Sub()152     public void testFloat16Sub() {
153         script.set_gInput(mInput);
154         script.forEach_sub(mF16Matrix);
155         script.forEach_bitcast(mF16Matrix, mU16Matrix);
156         mU16Matrix.copyTo(output);
157 
158         for (int x = 0; x < numInputs; x ++) {
159             for (int y = 0; y < numInputs; y ++) {
160                 checkFloat16Sub(x, y);
161             }
162         }
163     }
164 
checkFloat16Mul(int x, int y)165     private boolean checkFloat16Mul(int x, int y) {
166         return checkFloat16Output(x, y, Float16TestData.ReferenceOutputForMul,
167                                   "multiplication");
168     }
169 
testFloat16Mul()170     public void testFloat16Mul() {
171         script.set_gInput(mInput);
172         script.forEach_mul(mF16Matrix);
173         script.forEach_bitcast(mF16Matrix, mU16Matrix);
174         mU16Matrix.copyTo(output);
175 
176         for (int x = 0; x < numInputs; x ++) {
177             for (int y = 0; y < numInputs; y ++) {
178                 checkFloat16Mul(x, y);
179             }
180         }
181     }
182 
checkFloat16Div(int x, int y)183     private boolean checkFloat16Div(int x, int y) {
184         return checkFloat16Output(x, y, Float16TestData.ReferenceOutputForDiv,
185                                   "division");
186     }
187 
testFloat16Div()188     public void testFloat16Div() {
189         script.set_gInput(mInput);
190         script.forEach_div(mF16Matrix);
191         script.forEach_bitcast(mF16Matrix, mU16Matrix);
192         mU16Matrix.copyTo(output);
193 
194         for (int x = 0; x < numInputs; x ++) {
195             for (int y = 0; y < numInputs; y ++) {
196                 checkFloat16Div(x, y);
197             }
198         }
199     }
200 }
201