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 */
17 #include <gtest/gtest.h>
19 #include <fenv.h>
21 template <typename RT, typename T1>
22 struct data_1_1_t {
23 RT expected;
24 T1 input;
25 };
27 template <typename RT, typename T1, typename T2>
28 struct data_1_2_t {
29 RT expected;
30 T1 input1;
31 T2 input2;
32 };
34 template <typename RT1, typename RT2, typename T>
35 struct data_2_1_t {
36 RT1 expected1;
37 RT2 expected2;
38 T input;
39 };
41 template <typename T> union fp_u;
43 template <> union fp_u<float> {
44 float value;
45 struct {
46 unsigned frac:23;
47 unsigned exp:8;
48 unsigned sign:1;
49 } bits;
50 uint32_t sign_magnitude;
51 };
53 template <> union fp_u<double> {
54 double value;
55 struct {
56 unsigned fracl;
57 unsigned frach:20;
58 unsigned exp:11;
59 unsigned sign:1;
60 } bits;
61 uint64_t sign_magnitude;
62 };
64 // TODO: long double.
66 template <typename T>
67 static inline auto SignAndMagnitudeToBiased(const T& value) -> decltype(fp_u<T>::sign_magnitude) {
68 fp_u<T> u;
69 u.value = value;
70 if (u.bits.sign) {
71 return ~u.sign_magnitude + 1;
72 } else {
73 u.bits.sign = 1;
74 return u.sign_magnitude;
75 }
76 }
78 // Based on the existing googletest implementation, which uses a fixed 4 ulp bound.
79 template <typename T>
80 size_t UlpDistance(T lhs, T rhs) {
81 const auto biased1 = SignAndMagnitudeToBiased(lhs);
82 const auto biased2 = SignAndMagnitudeToBiased(rhs);
83 return (biased1 >= biased2) ? (biased1 - biased2) : (biased2 - biased1);
84 }
86 template <size_t ULP, typename T>
87 struct FpUlpEq {
88 ::testing::AssertionResult operator()(const char* /* expected_expression */,
89 const char* /* actual_expression */,
90 T expected,
91 T actual) {
92 if (!isnan(expected) && !isnan(actual) && UlpDistance(expected, actual) <= ULP) {
93 return ::testing::AssertionSuccess();
94 }
96 // Output the actual and expected values as hex floating point.
97 char expected_str[64];
98 char actual_str[64];
99 snprintf(expected_str, sizeof(expected_str), "%a", expected);
100 snprintf(actual_str, sizeof(actual_str), "%a", actual);
102 return ::testing::AssertionFailure()
103 << "expected (" << expected_str << ") != actual (" << actual_str << ")";
104 }
105 };
107 // Runs through the array 'data' applying 'f' to each of the input values
108 // and asserting that the result is within ULP ulps of the expected value.
109 // For testing a (double) -> double function like sin(3).
110 template <size_t ULP, typename RT, typename T, size_t N>
111 void DoMathDataTest(data_1_1_t<RT, T> (&data)[N], RT f(T)) {
112 fesetenv(FE_DFL_ENV);
113 FpUlpEq<ULP, RT> predicate;
114 for (size_t i = 0; i < N; ++i) {
115 EXPECT_PRED_FORMAT2(predicate,
116 data[i].expected, f(data[i].input)) << "Failed on element " << i;
117 }
118 }
120 // Runs through the array 'data' applying 'f' to each of the pairs of input values
121 // and asserting that the result is within ULP ulps of the expected value.
122 // For testing a (double, double) -> double function like pow(3).
123 template <size_t ULP, typename RT, typename T1, typename T2, size_t N>
124 void DoMathDataTest(data_1_2_t<RT, T1, T2> (&data)[N], RT f(T1, T2)) {
125 fesetenv(FE_DFL_ENV);
126 FpUlpEq<ULP, RT> predicate;
127 for (size_t i = 0; i < N; ++i) {
128 EXPECT_PRED_FORMAT2(predicate,
129 data[i].expected, f(data[i].input1, data[i].input2)) << "Failed on element " << i;
130 }
131 }
133 // Runs through the array 'data' applying 'f' to each of the input values
134 // and asserting that the results are within ULP ulps of the expected values.
135 // For testing a (double, double*, double*) -> void function like sincos(3).
136 template <size_t ULP, typename RT1, typename RT2, typename T1, size_t N>
137 void DoMathDataTest(data_2_1_t<RT1, RT2, T1> (&data)[N], void f(T1, RT1*, RT2*)) {
138 fesetenv(FE_DFL_ENV);
139 FpUlpEq<ULP, RT1> predicate1;
140 FpUlpEq<ULP, RT2> predicate2;
141 for (size_t i = 0; i < N; ++i) {
142 RT1 out1;
143 RT2 out2;
144 f(data[i].input, &out1, &out2);
145 EXPECT_PRED_FORMAT2(predicate1, data[i].expected1, out1) << "Failed on element " << i;
146 EXPECT_PRED_FORMAT2(predicate2, data[i].expected2, out2) << "Failed on element " << i;
147 }
148 }