1
2 //
3 // This source file is part of appleseed.
4 // Visit https://appleseedhq.net/ for additional information and resources.
5 //
6 // This software is released under the MIT license.
7 //
8 // Copyright (c) 2010-2013 Francois Beaune, Jupiter Jazz Limited
9 // Copyright (c) 2014-2018 Francois Beaune, The appleseedhq Organization
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining a copy
12 // of this software and associated documentation files (the "Software"), to deal
13 // in the Software without restriction, including without limitation the rights
14 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 // copies of the Software, and to permit persons to whom the Software is
16 // furnished to do so, subject to the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be included in
19 // all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 // THE SOFTWARE.
28 //
29
30 // appleseed.foundation headers.
31 #include "foundation/math/combination.h"
32 #include "foundation/math/fp.h"
33 #include "foundation/math/minmax.h"
34 #ifdef APPLESEED_USE_SSE
35 #include "foundation/platform/sse.h"
36 #endif
37 #include "foundation/utility/casts.h"
38 #include "foundation/utility/test.h"
39 #include "foundation/utility/typetraits.h"
40
41 // Standard headers.
42 #include <algorithm>
43 #include <cstddef>
44 #include <utility>
45
46 using namespace foundation;
47 using namespace std;
48
TEST_SUITE(Foundation_Math_MinMax)49 TEST_SUITE(Foundation_Math_MinMax)
50 {
51 TEST_CASE(Min_ThreeArguments)
52 {
53 EXPECT_EQ(0, min(0, 1, 2));
54 EXPECT_EQ(0, min(0, 2, 1));
55 EXPECT_EQ(0, min(1, 0, 2));
56 EXPECT_EQ(0, min(1, 2, 0));
57 EXPECT_EQ(0, min(2, 0, 1));
58 EXPECT_EQ(0, min(2, 1, 0));
59 }
60
61 TEST_CASE(Max_ThreeArguments)
62 {
63 EXPECT_EQ(2, max(0, 1, 2));
64 EXPECT_EQ(2, max(0, 2, 1));
65 EXPECT_EQ(2, max(1, 0, 2));
66 EXPECT_EQ(2, max(1, 2, 0));
67 EXPECT_EQ(2, max(2, 0, 1));
68 EXPECT_EQ(2, max(2, 1, 0));
69 }
70
71 pair<int, int> minmax_pair(const int a, const int b)
72 {
73 int min, max;
74 minmax(a, b, min, max);
75 return make_pair(min, max);
76 }
77
78 pair<int, int> minmax_pair(const int a, const int b, const int c)
79 {
80 int min, max;
81 minmax(a, b, c, min, max);
82 return make_pair(min, max);
83 }
84
85 TEST_CASE(MinMax_TwoArguments)
86 {
87 EXPECT_EQ(0, minmax_pair(0, 2).first);
88 EXPECT_EQ(2, minmax_pair(0, 2).second);
89 EXPECT_EQ(0, minmax_pair(2, 0).first);
90 EXPECT_EQ(2, minmax_pair(2, 0).second);
91 }
92
93 TEST_CASE(MinMax_ThreeArguments)
94 {
95 EXPECT_EQ(0, minmax_pair(0, 1, 2).first);
96 EXPECT_EQ(2, minmax_pair(0, 1, 2).second);
97 EXPECT_EQ(0, minmax_pair(0, 2, 1).first);
98 EXPECT_EQ(2, minmax_pair(0, 2, 1).second);
99 EXPECT_EQ(0, minmax_pair(1, 0, 2).first);
100 EXPECT_EQ(2, minmax_pair(1, 0, 2).second);
101 EXPECT_EQ(0, minmax_pair(1, 2, 0).first);
102 EXPECT_EQ(2, minmax_pair(1, 2, 0).second);
103 EXPECT_EQ(0, minmax_pair(2, 0, 1).first);
104 EXPECT_EQ(2, minmax_pair(2, 0, 1).second);
105 EXPECT_EQ(0, minmax_pair(2, 1, 0).first);
106 EXPECT_EQ(2, minmax_pair(2, 1, 0).second);
107 }
108
109 #ifdef APPLESEED_USE_SSE
110
111 float ssemin_reference(const float a, const float b)
112 {
113 return _mm_cvtss_f32(_mm_min_ss(_mm_set_ss(a), _mm_set_ss(b)));
114 }
115
116 float ssemax_reference(const float a, const float b)
117 {
118 return _mm_cvtss_f32(_mm_max_ss(_mm_set_ss(a), _mm_set_ss(b)));
119 }
120
121 TEST_CASE(SSEMinAndSSEMax_GivenPermutationsOfSpecialFloatingPointNumbers_MatchMINSSAndMAXSS)
122 {
123 typedef TypeConv<float>::UInt UInt;
124
125 static UInt Values[] =
126 {
127 binary_cast<UInt>(1.0f),
128 binary_cast<UInt>(2.0f),
129 binary_cast<UInt>(FP<float>::pos_zero()),
130 binary_cast<UInt>(FP<float>::neg_zero()),
131 binary_cast<UInt>(FP<float>::pos_min()),
132 binary_cast<UInt>(FP<float>::neg_min()),
133 binary_cast<UInt>(FP<float>::pos_inf()),
134 binary_cast<UInt>(FP<float>::neg_inf()),
135 binary_cast<UInt>(FP<float>::snan()),
136 binary_cast<UInt>(FP<float>::qnan())
137 };
138
139 const size_t N = countof(Values);
140
141 sort(&Values[0], &Values[N]);
142
143 UInt* first = &Values[0];
144 UInt* middle = &Values[2];
145 UInt* last = &Values[N];
146
147 size_t permutation_count = 0;
148
149 do
150 {
151 const float a = binary_cast<float>(*first);
152 const float b = binary_cast<float>(*middle);
153
154 const UInt expected_min = binary_cast<UInt>(ssemin_reference(a, b));
155 const UInt obtained_min = binary_cast<UInt>(ssemin(a, b));
156
157 EXPECT_EQ(expected_min, obtained_min);
158
159 const UInt expected_max = binary_cast<UInt>(ssemax_reference(a, b));
160 const UInt obtained_max = binary_cast<UInt>(ssemax(a, b));
161
162 EXPECT_EQ(expected_max, obtained_max);
163
164 ++permutation_count;
165 }
166 while (next_partial_permutation(first, middle, last));
167
168 const size_t ExpectedPermutationCount = factorial(N) / factorial(N - 2);
169
170 EXPECT_EQ(ExpectedPermutationCount, permutation_count);
171 }
172
173 #endif // APPLESEED_USE_SSE
174
175 TEST_CASE(MinIndex_TwoArguments)
176 {
177 EXPECT_EQ(0, min_index(0, 2));
178 EXPECT_EQ(1, min_index(2, 0));
179 }
180
181 TEST_CASE(MinIndex_ThreeArguments)
182 {
183 EXPECT_EQ(0, min_index(0, 1, 2));
184 EXPECT_EQ(0, min_index(0, 2, 1));
185 EXPECT_EQ(1, min_index(1, 0, 2));
186 EXPECT_EQ(2, min_index(1, 2, 0));
187 EXPECT_EQ(1, min_index(2, 0, 1));
188 EXPECT_EQ(2, min_index(2, 1, 0));
189 }
190
191 TEST_CASE(MaxIndex_TwoArguments)
192 {
193 EXPECT_EQ(1, max_index(0, 2));
194 EXPECT_EQ(0, max_index(2, 0));
195 }
196
197 TEST_CASE(MaxIndex_ThreeArguments)
198 {
199 EXPECT_EQ(2, max_index(0, 1, 2));
200 EXPECT_EQ(1, max_index(0, 2, 1));
201 EXPECT_EQ(2, max_index(1, 0, 2));
202 EXPECT_EQ(1, max_index(1, 2, 0));
203 EXPECT_EQ(0, max_index(2, 0, 1));
204 EXPECT_EQ(0, max_index(2, 1, 0));
205 }
206 }
207