1 //
2 // Copyright (c) 2017 The Khronos Group Inc.
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 #ifndef TEST_CONFORMANCE_CLCPP_UTILS_TEST_COMPARE_HPP
17 #define TEST_CONFORMANCE_CLCPP_UTILS_TEST_COMPARE_HPP
18
19 #include <random>
20 #include <limits>
21 #include <type_traits>
22 #include <algorithm>
23
24 #include <cmath>
25
26 #include "../common.hpp"
27
28 // Checks if x is equal to y.
29 template<class type, class delta_type, class op_type>
are_equal(const type & x,const type & y,const delta_type & delta,op_type op,typename std::enable_if<is_vector_type<type>::value && std::is_integral<typename scalar_type<type>::type>::value>::type * =0)30 inline bool are_equal(const type& x,
31 const type& y,
32 const delta_type& delta,
33 op_type op,
34 typename std::enable_if<
35 is_vector_type<type>::value
36 && std::is_integral<typename scalar_type<type>::type>::value
37 >::type* = 0)
38 {
39 (void) delta;
40 for(size_t i = 0; i < vector_size<type>::value; i++)
41 {
42 if(op.is_out_bool())
43 {
44 if(!((x.s[i] != 0) == (y.s[i] != 0)))
45 {
46 return false;
47 }
48 }
49 else if(!(x.s[i] == y.s[i]))
50 {
51 return false;
52 }
53 }
54 return true;
55 }
56
57 template<class type, class delta_type, class op_type>
are_equal(const type & x,const type & y,const delta_type & delta,op_type op,typename std::enable_if<!is_vector_type<type>::value && std::is_integral<type>::value>::type * =0)58 inline bool are_equal(const type& x,
59 const type& y,
60 const delta_type& delta,
61 op_type op,
62 typename std::enable_if<
63 !is_vector_type<type>::value
64 && std::is_integral<type>::value
65 >::type* = 0)
66 {
67 (void) delta;
68 if(op.is_out_bool())
69 {
70 if(!((x != 0) == (y != 0)))
71 {
72 return false;
73 }
74 }
75 return x == y;
76 }
77
78 template<class type, class type1, class type2, class op_type>
are_equal(const type & x,const type1 & y,const type2 & delta,op_type op,typename std::enable_if<!is_vector_type<type>::value && std::is_floating_point<type>::value>::type * =0)79 inline bool are_equal(const type& x,
80 const type1& y,
81 const type2& delta,
82 op_type op,
83 typename std::enable_if<
84 !is_vector_type<type>::value
85 && std::is_floating_point<type>::value
86 >::type* = 0)
87 {
88 // x - expected
89 // y - result
90
91 // INFO:
92 // Whe don't care about subnormal values in OpenCL C++ tests
93 if(std::fpclassify(static_cast<type1>(x)) == FP_SUBNORMAL || std::fpclassify(y) == FP_SUBNORMAL)
94 {
95 return true;
96 }
97
98 // both are NaN
99 if((std::isnan)(static_cast<type1>(x)) && (std::isnan)(y))
100 {
101 return true;
102 }
103 // one is NaN
104 else if((std::isnan)(static_cast<type1>(x)) || (std::isnan)(y))
105 {
106 return false;
107 }
108
109 // Check for perfect match, it also covers inf, -inf
110 if(static_cast<type1>(x) != y)
111 {
112 // Check if values are close
113 if(std::abs(static_cast<type1>(x) - y) > (std::max)(std::numeric_limits<type2>::epsilon(), std::abs(delta)))
114 {
115 return false;
116 }
117 // Check ulp
118 if(op.use_ulp())
119 {
120 return !(std::abs(Ulp_Error(x, y)) > op.ulp());
121 }
122 }
123 return true;
124 }
125
126 template<class type, class type1, class type2, class op_type>
are_equal(const type & x,const type1 & y,const type2 & delta,op_type op,typename std::enable_if<is_vector_type<type>::value && std::is_floating_point<typename scalar_type<type>::type>::value>::type * =0)127 inline bool are_equal(const type& x,
128 const type1& y,
129 const type2& delta,
130 op_type op,
131 typename std::enable_if<
132 is_vector_type<type>::value
133 && std::is_floating_point<typename scalar_type<type>::type>::value
134 >::type* = 0)
135 {
136 // x - expected
137 // y - result
138 for(size_t i = 0; i < vector_size<type>::value; i++)
139 {
140 if(!are_equal(x.s[i], y.s[i], delta.s[i], op))
141 {
142 return false;
143 }
144 }
145 return true;
146 }
147
148 template<class type, class type1, class func>
print_error_msg(const type & expected,const type1 & result,size_t i,func op)149 inline void print_error_msg(const type& expected, const type1& result, size_t i, func op)
150 {
151 log_error(
152 "ERROR: test_%s %s failed. Error at %lu: Expected: %s, got: %s\n",
153 op.str().c_str(),
154 op.decl_str().c_str(),
155 i,
156 format_value(expected).c_str(),
157 format_value(result).c_str()
158 );
159 }
160
161 #endif // TEST_CONFORMANCE_CLCPP_UTILS_TEST_COMPARE_HPP
162