• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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 #include <gtest/gtest.h>
18 
19 #include <fenv.h>
20 
21 template <typename RT, typename T1>
22 struct data_1_1_t {
23   RT expected;
24   T1 input;
25 };
26 
27 template <typename T1>
28 struct data_int_1_t {
29   int expected;
30   T1 input;
31 };
32 
33 template <typename T1>
34 struct data_long_1_t {
35   long expected;
36   T1 input;
37 };
38 
39 template <typename T1>
40 struct data_llong_1_t {
41   long long expected;
42   T1 input;
43 };
44 
45 template <typename RT, typename T1, typename T2>
46 struct data_1_2_t {
47   RT expected;
48   T1 input1;
49   T2 input2;
50 };
51 
52 template <typename RT1, typename RT2, typename T>
53 struct data_2_1_t {
54   RT1 expected1;
55   RT2 expected2;
56   T input;
57 };
58 
59 template <typename RT1, typename T>
60 struct data_1_int_1_t {
61   RT1 expected1;
62   int expected2;
63   T input;
64 };
65 
66 template <typename RT1, typename T1, typename T2>
67 struct data_1_int_2_t {
68   RT1 expected1;
69   int expected2;
70   T1 input1;
71   T2 input2;
72 };
73 
74 template <typename RT, typename T1, typename T2, typename T3>
75 struct data_1_3_t {
76   RT expected;
77   T1 input1;
78   T2 input2;
79   T3 input3;
80 };
81 
82 template <typename T> union fp_u;
83 
84 template <> union fp_u<float> {
85   float value;
86   struct {
87     unsigned frac:23;
88     unsigned exp:8;
89     unsigned sign:1;
90   } bits;
91   uint32_t sign_magnitude;
92 };
93 
94 template <> union fp_u<double> {
95   double value;
96   struct {
97     unsigned fracl;
98     unsigned frach:20;
99     unsigned exp:11;
100     unsigned sign:1;
101   } bits;
102   uint64_t sign_magnitude;
103 };
104 
105 // TODO: long double.
106 
107 template <typename T>
108 static inline auto SignAndMagnitudeToBiased(const T& value) -> decltype(fp_u<T>::sign_magnitude) {
109   fp_u<T> u;
110   u.value = value;
111   if (u.bits.sign) {
112     return ~u.sign_magnitude + 1;
113   } else {
114     u.bits.sign = 1;
115     return u.sign_magnitude;
116   }
117 }
118 
119 // Based on the existing googletest implementation, which uses a fixed 4 ulp bound.
120 template <typename T>
121 size_t UlpDistance(T lhs, T rhs) {
122   const auto biased1 = SignAndMagnitudeToBiased(lhs);
123   const auto biased2 = SignAndMagnitudeToBiased(rhs);
124   return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1);
125 }
126 
127 template <size_t ULP, typename T>
128 struct FpUlpEq {
129   ::testing::AssertionResult operator()(const char* /* expected_expression */,
130                                         const char* /* actual_expression */,
131                                         T expected,
132                                         T actual) {
133     if (!isnan(expected) && !isnan(actual) && UlpDistance(expected, actual) <= ULP) {
134       return ::testing::AssertionSuccess();
135     }
136 
137     // Output the actual and expected values as hex floating point.
138     char expected_str[64];
139     char actual_str[64];
140     snprintf(expected_str, sizeof(expected_str), "%a", expected);
141     snprintf(actual_str, sizeof(actual_str), "%a", actual);
142 
143     return ::testing::AssertionFailure()
144         << "expected (" << expected_str << ") != actual (" << actual_str << ")";
145   }
146 };
147 
148 // Runs through the array 'data' applying 'f' to each of the input values
149 // and asserting that the result is within ULP ulps of the expected value.
150 // For testing a (double) -> double function like sin(3).
151 template <size_t ULP, typename RT, typename T, size_t N>
152 void DoMathDataTest(data_1_1_t<RT, T> (&data)[N], RT f(T)) {
153   fesetenv(FE_DFL_ENV);
154   FpUlpEq<ULP, RT> predicate;
155   for (size_t i = 0; i < N; ++i) {
156     EXPECT_PRED_FORMAT2(predicate,
157                         data[i].expected, f(data[i].input)) << "Failed on element " << i;
158   }
159 }
160 
161 // Runs through the array 'data' applying 'f' to each of the input values
162 // and asserting that the result is within ULP ulps of the expected value.
163 // For testing a (double) -> int function like ilogb(3).
164 template <size_t ULP, typename T, size_t N>
165 void DoMathDataTest(data_int_1_t<T> (&data)[N], int f(T)) {
166   fesetenv(FE_DFL_ENV);
167   for (size_t i = 0; i < N; ++i) {
168     EXPECT_EQ(data[i].expected, f(data[i].input)) << "Failed on element " << i;
169   }
170 }
171 
172 // Runs through the array 'data' applying 'f' to each of the input values
173 // and asserting that the result is within ULP ulps of the expected value.
174 // For testing a (double) -> long int function like lrint(3).
175 template <size_t ULP, typename T, size_t N>
176 void DoMathDataTest(data_long_1_t<T> (&data)[N], long f(T)) {
177   fesetenv(FE_DFL_ENV);
178   for (size_t i = 0; i < N; ++i) {
179     EXPECT_EQ(data[i].expected, f(data[i].input)) << "Failed on element " << i;
180   }
181 }
182 
183 // Runs through the array 'data' applying 'f' to each of the input values
184 // and asserting that the result is within ULP ulps of the expected value.
185 // For testing a (double) -> long long int function like llrint(3).
186 template <size_t ULP, typename T, size_t N>
187 void DoMathDataTest(data_llong_1_t<T> (&data)[N], long long f(T)) {
188   fesetenv(FE_DFL_ENV);
189   for (size_t i = 0; i < N; ++i) {
190     EXPECT_EQ(data[i].expected, f(data[i].input)) << "Failed on element " << i;
191   }
192 }
193 
194 // Runs through the array 'data' applying 'f' to each of the pairs of input values
195 // and asserting that the result is within ULP ulps of the expected value.
196 // For testing a (double, double) -> double function like pow(3).
197 template <size_t ULP, typename RT, typename T1, typename T2, size_t N>
198 void DoMathDataTest(data_1_2_t<RT, T1, T2> (&data)[N], RT f(T1, T2)) {
199   fesetenv(FE_DFL_ENV);
200   FpUlpEq<ULP, RT> predicate;
201   for (size_t i = 0; i < N; ++i) {
202     EXPECT_PRED_FORMAT2(predicate,
203                         data[i].expected, f(data[i].input1, data[i].input2)) << "Failed on element " << i;
204   }
205 }
206 
207 // Runs through the array 'data' applying 'f' to each of the input values
208 // and asserting that the results are within ULP ulps of the expected values.
209 // For testing a (double, double*, double*) -> void function like sincos(3).
210 template <size_t ULP, typename RT1, typename RT2, typename T1, size_t N>
211 void DoMathDataTest(data_2_1_t<RT1, RT2, T1> (&data)[N], void f(T1, RT1*, RT2*)) {
212   fesetenv(FE_DFL_ENV);
213   FpUlpEq<ULP, RT1> predicate1;
214   FpUlpEq<ULP, RT2> predicate2;
215   for (size_t i = 0; i < N; ++i) {
216     RT1 out1;
217     RT2 out2;
218     f(data[i].input, &out1, &out2);
219     EXPECT_PRED_FORMAT2(predicate1, data[i].expected1, out1) << "Failed on element " << i;
220     EXPECT_PRED_FORMAT2(predicate2, data[i].expected2, out2) << "Failed on element " << i;
221   }
222 }
223 
224 // Runs through the array 'data' applying 'f' to each of the input values
225 // and asserting that the results are within ULP ulps of the expected values.
226 // For testing a (double, double*) -> double function like modf(3).
227 template <size_t ULP, typename RT1, typename RT2, typename T1, size_t N>
228 void DoMathDataTest(data_2_1_t<RT1, RT2, T1> (&data)[N], RT1 f(T1, RT2*)) {
229   fesetenv(FE_DFL_ENV);
230   FpUlpEq<ULP, RT1> predicate1;
231   FpUlpEq<ULP, RT2> predicate2;
232   for (size_t i = 0; i < N; ++i) {
233     RT1 out1;
234     RT2 out2;
235     out1 = f(data[i].input, &out2);
236     EXPECT_PRED_FORMAT2(predicate1, data[i].expected1, out1) << "Failed on element " << i;
237     EXPECT_PRED_FORMAT2(predicate2, data[i].expected2, out2) << "Failed on element " << i;
238   }
239 }
240 
241 // Runs through the array 'data' applying 'f' to each of the input values
242 // and asserting that the results are within ULP ulps of the expected values.
243 // For testing a (double, int*) -> double function like frexp(3).
244 template <size_t ULP, typename RT1, typename T1, size_t N>
245 void DoMathDataTest(data_1_int_1_t<RT1, T1> (&data)[N], RT1 f(T1, int*)) {
246   fesetenv(FE_DFL_ENV);
247   FpUlpEq<ULP, RT1> predicate1;
248   for (size_t i = 0; i < N; ++i) {
249     RT1 out1;
250     int out2;
251     out1 = f(data[i].input, &out2);
252     EXPECT_PRED_FORMAT2(predicate1, data[i].expected1, out1) << "Failed on element " << i;
253     EXPECT_EQ(data[i].expected2, out2) << "Failed on element " << i;
254   }
255 }
256 
257 // Runs through the array 'data' applying 'f' to each of the input values
258 // and asserting that the results are within ULP ulps of the expected values.
259 // For testing a (double, double, int*) -> double function like remquo(3).
260 template <size_t ULP, typename RT1, typename T1, typename T2, size_t N>
261 void DoMathDataTest(data_1_int_2_t<RT1, T1, T2> (&data)[N], RT1 f(T1, T2, int*)) {
262   fesetenv(FE_DFL_ENV);
263   FpUlpEq<ULP, RT1> predicate1;
264   for (size_t i = 0; i < N; ++i) {
265     RT1 out1;
266     int out2;
267     out1 = f(data[i].input1, data[i].input2, &out2);
268     EXPECT_PRED_FORMAT2(predicate1, data[i].expected1, out1) << "Failed on element " << i;
269     EXPECT_EQ(data[i].expected2, out2) << "Failed on element " << i;
270   }
271 }
272 
273 // Runs through the array 'data' applying 'f' to each of the pairs of input values
274 // and asserting that the result is within ULP ulps of the expected value.
275 // For testing a (double, double, double) -> double function like fma(3).
276 template <size_t ULP, typename RT, typename T1, typename T2, typename T3, size_t N>
277 void DoMathDataTest(data_1_3_t<RT, T1, T2, T3> (&data)[N], RT f(T1, T2, T3)) {
278   fesetenv(FE_DFL_ENV);
279   FpUlpEq<ULP, RT> predicate;
280   for (size_t i = 0; i < N; ++i) {
281     EXPECT_PRED_FORMAT2(predicate,
282                         data[i].expected, f(data[i].input1, data[i].input2, data[i].input3)) << "Failed on element " << i;
283   }
284 }
285 
286