1 // Copyright 2015, Tobias Hermann and the FunctionalPlus contributors.
2 // https://github.com/Dobiasd/FunctionalPlus
3 // Distributed under the Boost Software License, Version 1.0.
4 // (See accompanying file LICENSE_1_0.txt or copy at
5 //  http://www.boost.org/LICENSE_1_0.txt)
6 
7 #include <doctest/doctest.h>
8 #include <fplus/fplus.hpp>
9 #include <vector>
10 
11 namespace {
12 
mod2(int x)13     int mod2(int x)
14     {
15         return x % 2;
16     }
17 
mod7(int x)18     int mod7(int x)
19     {
20         return x % 7;
21     }
22 
string_length(const std::string & s)23     std::size_t string_length(const std::string& s)
24     {
25         return s.size();
26     }
27 
28     typedef std::vector<int> Ints;
29     typedef std::vector<float> Floats;
30     typedef std::vector<double> Doubles;
31 }
32 
33 TEST_CASE("numeric_test - is_in_interval")
34 {
35     REQUIRE(fplus::is_in_interval(1, 3, 1));
36     REQUIRE(fplus::is_in_interval(1, 3, 2));
37     REQUIRE_FALSE(fplus::is_in_interval(1, 3, 0));
38     REQUIRE_FALSE(fplus::is_in_interval(1, 3, 3));
39     REQUIRE(fplus::is_in_closed_interval(1, 3, 1));
40     REQUIRE(fplus::is_in_closed_interval(1, 3, 2));
41     REQUIRE(fplus::is_in_closed_interval(1, 3, 3));
42     REQUIRE_FALSE(fplus::is_in_open_interval(1, 3, 1));
43     REQUIRE(fplus::is_in_open_interval(1, 3, 2));
44     REQUIRE_FALSE(fplus::is_in_open_interval(1, 3, 3));
45     REQUIRE(fplus::is_in_interval(0.09, 0.11, fplus::abs(-0.1)));
46     REQUIRE(fplus::is_in_interval(0.09, 0.11, fplus::abs( 0.1)));
47 }
48 
49 TEST_CASE("numeric_test - is_in_interval_around")
50 {
51     REQUIRE_FALSE(fplus::is_in_interval_around(0.1, 2.0, 1.85));
52     REQUIRE(fplus::is_in_interval_around(0.1, 2.0, 1.95));
53     REQUIRE(fplus::is_in_interval_around(0.1, 2.0, 2.05));
54     REQUIRE_FALSE(fplus::is_in_interval_around(0.1, 2.0, 2.15));
55 
56     REQUIRE(fplus::is_in_interval_around(1, 2, 1));
57     REQUIRE_FALSE(fplus::is_in_interval_around(1, 2, 3));
58 }
59 
60 TEST_CASE("numeric_test - is_in_open_interval_around")
61 {
62     REQUIRE_FALSE(fplus::is_in_open_interval_around(0.1, 2.0, 1.85));
63     REQUIRE(fplus::is_in_open_interval_around(0.1, 2.0, 1.95));
64     REQUIRE(fplus::is_in_open_interval_around(0.1, 2.0, 2.05));
65     REQUIRE_FALSE(fplus::is_in_open_interval_around(0.1, 2.0, 2.15));
66 
67     REQUIRE_FALSE(fplus::is_in_open_interval_around(1, 2, 1));
68     REQUIRE_FALSE(fplus::is_in_open_interval_around(1, 2, 3));
69 }
70 
71 TEST_CASE("numeric_test - is_in_closed_interval_around")
72 {
73     REQUIRE_FALSE(fplus::is_in_closed_interval_around(0.1, 2.0, 1.85));
74     REQUIRE(fplus::is_in_closed_interval_around(0.1, 2.0, 1.95));
75     REQUIRE(fplus::is_in_closed_interval_around(0.1, 2.0, 2.05));
76     REQUIRE_FALSE(fplus::is_in_closed_interval_around(0.1, 2.0, 2.15));
77 
78     REQUIRE(fplus::is_in_closed_interval_around(1, 2, 1));
79     REQUIRE(fplus::is_in_closed_interval_around(1, 2, 3));
80 }
81 
82 TEST_CASE("numeric_test - is_negative")
83 {
84     REQUIRE(fplus::is_negative(-0.1));
85     REQUIRE_FALSE(fplus::is_negative(0.1));
86 }
87 
88 TEST_CASE("numeric_test - is_positive")
89 {
90     REQUIRE(fplus::is_positive(0.1));
91     REQUIRE_FALSE(fplus::is_positive(-0.1));
92 }
93 
94 TEST_CASE("numeric_test - is_even")
95 {
96     REQUIRE(fplus::is_even(2));
97     REQUIRE(fplus::is_even(-2));
98     REQUIRE_FALSE(fplus::is_even(3));
99     REQUIRE_FALSE(fplus::is_even(-3));
100 }
101 
102 TEST_CASE("numeric_test - is_odd")
103 {
104     REQUIRE(fplus::is_odd(1));
105     REQUIRE(fplus::is_odd(-1));
106     REQUIRE_FALSE(fplus::is_odd(2));
107     REQUIRE_FALSE(fplus::is_odd(-2));
108 }
109 
110 TEST_CASE("numeric_test - sign")
111 {
112     REQUIRE_EQ(fplus::sign(0.1), 1);
113     REQUIRE_EQ(fplus::sign(-0.1), -1);
114 }
115 
116 TEST_CASE("numeric_test - abs_diff")
117 {
118     REQUIRE_EQ(fplus::abs_diff<signed int>(3, 5), 2);
119     REQUIRE_EQ(fplus::abs_diff<signed int>(5, 3), 2);
120     REQUIRE_EQ(fplus::abs_diff<unsigned int>(3, 5), 2);
121     REQUIRE_EQ(fplus::abs_diff<unsigned int>(5, 3), 2);
122 }
123 
124 TEST_CASE("numeric_test - cyclic_value")
125 {
126     using namespace fplus;
127     REQUIRE_EQ(cyclic_value(8.0)(3), 3);
128     REQUIRE_EQ(cyclic_value(8.0)(11), 3);
129     REQUIRE_EQ(cyclic_value(8.0)(19), 3);
130     REQUIRE_EQ(cyclic_value(8.0)(-2), 6);
131     REQUIRE_EQ(cyclic_value(8.0)(-5), 3);
132     REQUIRE_EQ(cyclic_value(8.0)(-13), 3);
133 
134     REQUIRE_EQ(cyclic_value(8)(3), 3);
135     REQUIRE_EQ(cyclic_value(8)(11), 3);
136     REQUIRE_EQ(cyclic_value(8)(19), 3);
137     REQUIRE_EQ(cyclic_value(8)(-2), 6);
138     REQUIRE_EQ(cyclic_value(8)(-5), 3);
139     REQUIRE_EQ(cyclic_value(8)(-13), 3);
140 
141     REQUIRE_EQ(cyclic_value<unsigned int>(8)(3), 3);
142     REQUIRE_EQ(cyclic_value<unsigned int>(8)(11), 3);
143     REQUIRE_EQ(cyclic_value<unsigned int>(8)(19), 3);
144 
145     REQUIRE(is_in_interval(3.19, 3.21, cyclic_value(8.1)(3.2)));
146 }
147 
148 TEST_CASE("numeric_test - cyclic_difference")
149 {
150     using namespace fplus;
151     REQUIRE_EQ(cyclic_difference(100)(5, 2), 3);
152     REQUIRE_EQ(cyclic_difference(100)(2, 5), 97);
153     REQUIRE_EQ(cyclic_difference(100)(3, -2), 5);
154     REQUIRE_EQ(cyclic_difference(100)(-2, 3), 95);
155     REQUIRE_EQ(cyclic_difference(100)(90, 10), 80);
156     REQUIRE_EQ(cyclic_difference(100)(10, 90), 20);
157 
158     REQUIRE_EQ(cyclic_difference<unsigned int>(100)(5, 2), 3);
159     REQUIRE_EQ(cyclic_difference<unsigned int>(100)(2, 5), 97);
160     REQUIRE_EQ(cyclic_difference<unsigned int>(100)(90, 10), 80);
161     REQUIRE_EQ(cyclic_difference<unsigned int>(100)(10, 90), 20);
162 }
163 
164 TEST_CASE("numeric_test - cyclic_shortest_difference")
165 {
166     using namespace fplus;
167     REQUIRE_EQ(cyclic_shortest_difference(100)(5, 2), 3);
168     REQUIRE_EQ(cyclic_shortest_difference(100)(2, 5), -3);
169     REQUIRE_EQ(cyclic_shortest_difference(100)(3, -2), 5);
170     REQUIRE_EQ(cyclic_shortest_difference(100)(-2, 3), -5);
171     REQUIRE_EQ(cyclic_shortest_difference(100)(90, 10), -20);
172     REQUIRE_EQ(cyclic_shortest_difference(100)(10, 90), 20);
173 }
174 
175 TEST_CASE("numeric_test - cyclic_distance")
176 {
177     using namespace fplus;
178     REQUIRE_EQ(cyclic_distance(100)(2, 5), 3);
179     REQUIRE_EQ(cyclic_distance(100)(5, 2), 3);
180     REQUIRE_EQ(cyclic_distance(100)(-2, 3), 5);
181     REQUIRE_EQ(cyclic_distance(100)(3, -2), 5);
182     REQUIRE_EQ(cyclic_distance(100)(10, 90), 20);
183     REQUIRE_EQ(cyclic_distance(100)(90, 10), 20);
184 
185     REQUIRE_EQ(cyclic_distance<unsigned int>(100)(2, 5), 3);
186     REQUIRE_EQ(cyclic_distance<unsigned int>(100)(5, 2), 3);
187     REQUIRE_EQ(cyclic_distance<unsigned int>(100)(10, 90), 20);
188     REQUIRE_EQ(cyclic_distance<unsigned int>(100)(90, 10), 20);
189 }
190 
191 TEST_CASE("numeric_test - round")
192 {
193     // using namespace fplus;  // round is also defined in tgmath.h under msvc
194     REQUIRE_EQ(round(1.4), 1);
195     REQUIRE_EQ(round(1.5), 2);
196     REQUIRE_EQ(round(1.6), 2);
197 
198     REQUIRE_EQ((fplus::round<double, unsigned char>(254.9)), 255);
199     REQUIRE_EQ((fplus::round<double, unsigned char>(300.0)), 255);
200     REQUIRE_EQ((fplus::round<double, unsigned char>(-0.0000001)), 0);
201     REQUIRE_EQ((fplus::round<double, unsigned char>(-5.0)), 0);
202 
203     REQUIRE_EQ(fplus::round(-1.4), -1);
204     REQUIRE_EQ(fplus::round(-1.6), -2);
205 }
206 
207 TEST_CASE("numeric_test - integral_cast_clamp")
208 {
209     using namespace fplus;
210     REQUIRE_EQ(integral_cast_clamp<std::uint8_t>(std::int32_t(-1)), std::uint8_t(0));
211     REQUIRE_EQ(integral_cast_clamp<std::uint8_t>(std::int32_t(0)), std::uint8_t(0));
212     REQUIRE_EQ(integral_cast_clamp<std::uint8_t>(std::int32_t(3)), std::uint8_t(3));
213     REQUIRE_EQ(integral_cast_clamp<std::uint8_t>(std::int32_t(255)), std::uint8_t(255));
214     REQUIRE_EQ(integral_cast_clamp<std::uint8_t>(std::int32_t(256)), std::uint8_t(255));
215 
216     REQUIRE_EQ(integral_cast_clamp<std::int8_t>(std::int32_t(-129)), std::int8_t(-128));
217     REQUIRE_EQ(integral_cast_clamp<std::int8_t>(std::int32_t(-128)), std::int8_t(-128));
218     REQUIRE_EQ(integral_cast_clamp<std::int8_t>(std::int32_t(3)), std::int8_t(3));
219     REQUIRE_EQ(integral_cast_clamp<std::int8_t>(std::int32_t(127)), std::int8_t(127));
220     REQUIRE_EQ(integral_cast_clamp<std::int8_t>(std::int32_t(128)), std::int8_t(127));
221 
222     REQUIRE_EQ(integral_cast_clamp<std::int8_t>(std::uint8_t(0)), std::int8_t(0));
223     REQUIRE_EQ(integral_cast_clamp<std::int8_t>(std::uint8_t(127)), std::int8_t(127));
224     REQUIRE_EQ(integral_cast_clamp<std::int8_t>(std::uint8_t(128)), std::int8_t(127));
225 
226     REQUIRE_EQ(integral_cast_clamp<std::uint64_t>(std::numeric_limits<std::uint16_t>::lowest()), static_cast<std::int64_t>(std::numeric_limits<std::uint16_t>::lowest()));
227     REQUIRE_EQ(integral_cast_clamp<std::uint64_t>(std::uint16_t(0)), std::uint64_t(0));
228     REQUIRE_EQ(integral_cast_clamp<std::uint64_t>(std::numeric_limits<std::uint16_t>::max()), static_cast<std::int64_t>(std::numeric_limits<std::uint16_t>::max()));
229 
230     REQUIRE_EQ(integral_cast_clamp<std::int64_t>(std::numeric_limits<std::int16_t>::lowest()), static_cast<std::int64_t>(std::numeric_limits<std::int16_t>::lowest()));
231     REQUIRE_EQ(integral_cast_clamp<std::int64_t>(std::int16_t(0)), std::int64_t(0));
232     REQUIRE_EQ(integral_cast_clamp<std::int64_t>(std::numeric_limits<std::int16_t>::max()), static_cast<std::int64_t>(std::numeric_limits<std::int16_t>::max()));
233 }
234 
235 TEST_CASE("numeric_test - ceil")
236 {
237     using namespace fplus;
238     REQUIRE_EQ(ceil(1.4), 2);
239     REQUIRE_EQ(ceil(-1.4), -1);
240 }
241 
242 TEST_CASE("numeric_test - floor")
243 {
244     using namespace fplus;
245     REQUIRE_EQ(floor(1.4), 1);
246     REQUIRE_EQ(floor(-1.4), -2);
247 }
248 
249 TEST_CASE("numeric_test - floor_to_int_mult")
250 {
251     using namespace fplus;
252     REQUIRE_EQ(floor_to_int_mult(2, -3), -4);
253     REQUIRE_EQ(floor_to_int_mult(2, -2), -2);
254     REQUIRE_EQ(floor_to_int_mult(2, -1), -2);
255     REQUIRE_EQ(floor_to_int_mult(2, 0), 0);
256     REQUIRE_EQ(floor_to_int_mult(2, 1), 0);
257     REQUIRE_EQ(floor_to_int_mult(2, 2), 2);
258     REQUIRE_EQ(floor_to_int_mult(2, 3), 2);
259     REQUIRE_EQ(floor_to_int_mult<unsigned char>(2, 0), 0);
260     REQUIRE_EQ(floor_to_int_mult<unsigned char>(2, 1), 0);
261     REQUIRE_EQ(floor_to_int_mult<unsigned char>(2, 2), 2);
262     REQUIRE_EQ(floor_to_int_mult<unsigned char>(2, 3), 2);
263 
264     REQUIRE_EQ(floor_to_int_mult(1, -1), -1);
265     REQUIRE_EQ(floor_to_int_mult(1, 0), 0);
266     REQUIRE_EQ(floor_to_int_mult(1, 1), 1);
267 }
268 
269 TEST_CASE("numeric_test - ceil_to_int_mult")
270 {
271     using namespace fplus;
272     REQUIRE_EQ(ceil_to_int_mult(2, -3), -2);
273     REQUIRE_EQ(ceil_to_int_mult(2, -2), -2);
274     REQUIRE_EQ(ceil_to_int_mult(2, -1), -0);
275     REQUIRE_EQ(ceil_to_int_mult(2, 0), 0);
276     REQUIRE_EQ(ceil_to_int_mult(2, 1), 2);
277     REQUIRE_EQ(ceil_to_int_mult(2, 2), 2);
278     REQUIRE_EQ(ceil_to_int_mult(2, 3), 4);
279     REQUIRE_EQ(ceil_to_int_mult<unsigned char>(2, 0), 0);
280     REQUIRE_EQ(ceil_to_int_mult<unsigned char>(2, 1), 2);
281     REQUIRE_EQ(ceil_to_int_mult<unsigned char>(2, 2), 2);
282     REQUIRE_EQ(ceil_to_int_mult<unsigned char>(2, 3), 4);
283 
284     REQUIRE_EQ(ceil_to_int_mult(1, -1), -1);
285     REQUIRE_EQ(ceil_to_int_mult(1, 0), 0);
286     REQUIRE_EQ(ceil_to_int_mult(1, 1), 1);
287 }
288 
289 TEST_CASE("numeric_test - reference_interval")
290 {
291     using namespace fplus;
292     REQUIRE_EQ(reference_interval(2, 6, 0, 4, 3), 5);
293     REQUIRE_EQ(reference_interval(2, 10, 0, 4, 3), 8);
294     REQUIRE_EQ(reference_interval(2, 6, 0, 4, -1), 1);
295     REQUIRE_EQ(reference_interval(2, 10, 0, 4, -1), 0);
296 }
297 
298 TEST_CASE("numeric_test - clamp")
299 {
300     using namespace fplus;
301     REQUIRE_EQ(clamp(2, 6, 5), 5);
302     REQUIRE_EQ(clamp(2, 6, 1), 2);
303     REQUIRE_EQ(clamp(2, 6, 8), 6);
304 }
305 
306 TEST_CASE("numeric_test - int_power")
307 {
308     using namespace fplus;
309     REQUIRE_EQ(int_power(3, 0), 1);
310     REQUIRE_EQ(int_power(3, 1), 3);
311     REQUIRE_EQ(int_power(3, 2), 9);
312     REQUIRE_EQ(int_power(3, 3), 27);
313     REQUIRE_EQ(int_power(3, 4), 81);
314 }
315 
316 TEST_CASE("numeric_test - min_on")
317 {
318     REQUIRE_EQ(fplus::min_on(mod2)(4, 4), 4);
319     REQUIRE_EQ(fplus::min_on(mod2)(4, 3), 4);
320     REQUIRE_EQ(fplus::min_on(mod2)(4, 3, 7), 4);
321     REQUIRE_EQ(fplus::min_on(mod2)(5, 3, 7), 5);
322     REQUIRE_EQ(fplus::min_on(mod2)(5, 3, 7, 9, 2), 2);
323     REQUIRE_EQ(fplus::min_on(mod2)(5, 3, 7, 13, 19, 4), 4);
324 
325     REQUIRE_EQ(fplus::min_on(mod7)(4, 4), 4);
326     REQUIRE_EQ(fplus::min_on(mod7)(4, 3), 3);
327     REQUIRE_EQ(fplus::min_on(mod7)(4, 3, 7), 7);
328     REQUIRE_EQ(fplus::min_on(mod7)(5, 3, 7, 9, 9), 7);
329     REQUIRE_EQ(fplus::min_on(mod7)(5, 3, 7, 9, 9, 6, 6, 6, 6, 6, 6), 7);
330     REQUIRE_EQ(fplus::min_on(mod7)(70, 3, 7, 9, 9, 6, 6, 6, 6, 6, 6), 70);
331 
332     const std::string s1("AAA");
333     const std::string s2("AAABB");
334     const std::string s3("AAABBCCC");
335     REQUIRE_EQ(fplus::min_on(string_length)(s1, s2), s1);
336     REQUIRE_EQ(fplus::min_on(string_length)(s2, s3), s2);
337     REQUIRE_EQ(fplus::min_on(string_length)(s1, s2, s3), s1);
338     REQUIRE_EQ(fplus::min_on(string_length)(s1, s3), s1);
339 
340     auto l1_min_on = fplus::min_on(mod7);
341     REQUIRE_EQ(l1_min_on(1), 1);
342     REQUIRE_EQ(l1_min_on(1, 2), 1);
343     REQUIRE_EQ(l1_min_on(1, 2, 3, 7), 7);
344     REQUIRE_EQ(l1_min_on(1, 2, 3, 6, 77), 77);
345     REQUIRE_EQ(fplus::min_on(mod7)(1), 1);
346     REQUIRE_EQ(fplus::min_on(mod7)(1, 2), 1);
347     REQUIRE_EQ(fplus::min_on(mod7)(1, 2, 3, 7), 7);
348     REQUIRE_EQ(fplus::min_on(mod7)(1, 2, 3, 6, 77), 77);
349 }
350 
351 TEST_CASE("numeric_test - max_on")
352 {
353     REQUIRE_EQ(fplus::max_on(mod2)(4, 4), 4);
354     REQUIRE_EQ(fplus::max_on(mod2)(4, 3), 3);
355     REQUIRE_EQ(fplus::max_on(mod2)(4, 3, 7), 3);
356     REQUIRE_EQ(fplus::max_on(mod2)(5, 3, 7), 5);
357     REQUIRE_EQ(fplus::max_on(mod2)(5, 3, 7, 9, 2), 5);
358     REQUIRE_EQ(fplus::max_on(mod2)(5, 3, 7, 13, 19, 4), 5);
359 
360     REQUIRE_EQ(fplus::max_on(mod7)(4, 4), 4);
361     REQUIRE_EQ(fplus::max_on(mod7)(4, 3), 4);
362     REQUIRE_EQ(fplus::max_on(mod7)(4, 3, 7), 4);
363     REQUIRE_EQ(fplus::max_on(mod7)(5, 3, 7, 9, 9), 5);
364     REQUIRE_EQ(fplus::max_on(mod7)(5, 3, 7, 9, 9, 6, 6, 6, 6, 6, 6), 6);
365     REQUIRE_EQ(fplus::max_on(mod7)(70, 3, 7, 9, 9, 6, 6, 6, 6, 6, 6), 6);
366 
367     const std::string s1("AAA");
368     const std::string s2("AAABB");
369     const std::string s3("AAABBCCC");
370     REQUIRE_EQ(fplus::max_on(string_length)(s1, s2), s2);
371     REQUIRE_EQ(fplus::max_on(string_length)(s2, s3), s3);
372     REQUIRE_EQ(fplus::max_on(string_length)(s1, s2, s3), s3);
373     REQUIRE_EQ(fplus::max_on(string_length)(s1, s3), s3);
374 
375     auto l1_max_on = fplus::max_on(mod7);
376     REQUIRE_EQ(l1_max_on(1), 1);
377     REQUIRE_EQ(l1_max_on(1, 2), 2);
378     REQUIRE_EQ(l1_max_on(1, 2, 3, 7), 3);
379     REQUIRE_EQ(l1_max_on(1, 2, 3, 6, 77), 6);
380     REQUIRE_EQ(fplus::max_on(mod7)(1), 1);
381     REQUIRE_EQ(fplus::max_on(mod7)(1, 2), 2);
382     REQUIRE_EQ(fplus::max_on(mod7)(1, 2, 3, 7), 3);
383     REQUIRE_EQ(fplus::max_on(mod7)(1, 2, 3, 6, 77), 6);
384 }
385 
386 TEST_CASE("numeric_test - mean")
387 {
388     using namespace fplus;
389     Ints xs = {1,4,4};
390     REQUIRE_EQ(mean<int>(xs), 3);
391 }
392 
393 TEST_CASE("numeric_test - mean_obj")
394 {
395     using namespace fplus;
396     struct vec_2d
397     {
398         double x;
399         double y;
operator +vec_2d400         vec_2d operator + (const vec_2d& rhs) const
401         {
402             return {x + rhs.x, y + rhs.y};
403         };
operator /vec_2d404         vec_2d operator / (double scalar) const
405         {
406             double scalar_d = static_cast<double>(scalar);
407             return {x / scalar_d, y / scalar_d};
408         };
operator /vec_2d409         vec_2d operator / (std::size_t scalar) const
410         {
411             return *this / static_cast<double>(scalar);
412         };
413     };
414 
415     auto vec_2d_length_squared = [](const vec_2d& v) -> double
__anon71ed84a80202(const vec_2d& v) 416     {
417         return v.x * v.x + v.y * v.y;
418     };
419     std::vector<vec_2d> vecs = {{1,1}, {3,3}};
420     auto mean_vec_div_double = mean_obj_div_double(vecs);
421     auto mean_vec_div_size_t = mean_obj_div_size_t(vecs);
422     double mean_vec_length_squared_dest = 2*2 + 2*2;
423     REQUIRE(is_in_interval_around(0.001, mean_vec_length_squared_dest,
424         vec_2d_length_squared(mean_vec_div_double)));
425     REQUIRE(is_in_interval_around(0.001, mean_vec_length_squared_dest,
426         vec_2d_length_squared(mean_vec_div_size_t)));
427 }
428 
429 TEST_CASE("numeric_test - variadic")
430 {
431     using namespace fplus;
432     REQUIRE_EQ(min(1,2,3,4,5), 1);
433     REQUIRE_EQ(min(1.01,1.02,1.03,1.04,1.05), 1.01);
434     REQUIRE_EQ(min(-54,2,3,54,5), -54);
435     REQUIRE_EQ(min(-54.2,2.7,3,54,5), -54.2);
436     REQUIRE_EQ(min(123,123,123,124), 123);
437     REQUIRE_EQ(min(123), 123);
438     REQUIRE_EQ(min(123,123), 123);
439     REQUIRE_EQ(min(123,123,123), 123);
440     REQUIRE_EQ(min(-1), -1);
441     REQUIRE_EQ(min(-1,-2), -2);
442     REQUIRE_EQ(min(-1,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), -2);
443     REQUIRE_EQ(min('a','b','c'), 'a');
444 
445     REQUIRE_EQ(max(1,2,3,4,5), 5);
446     REQUIRE_EQ(max(1.01,1.02,1.03,1.04,1.05), 1.05);
447     REQUIRE_EQ(max(-54,2,3,54,5), 54);
448     REQUIRE_EQ(max(-54.2,2.7,3,54.85,5), 54.85);
449     REQUIRE_EQ(max(123,123,123,124), 124);
450     REQUIRE_EQ(max(123), 123);
451     REQUIRE_EQ(max(123,123), 123);
452     REQUIRE_EQ(max(123,123,123), 123);
453     REQUIRE_EQ(max(123,123,123,123), 123);
454     REQUIRE_EQ(max(123,123,123,123,123), 123);
455     REQUIRE_EQ(max(123,123,123,123,123,123), 123);
456     REQUIRE_EQ(max(-1), -1);
457     REQUIRE_EQ(max(-1,-2), -1);
458     REQUIRE_EQ(max(-1,-2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0), 0);
459     REQUIRE_EQ(max('a','b','c'), 'c');
460 
461     REQUIRE_EQ(max_2(2, 3), 3);
462     REQUIRE_EQ(min_2(2, 3), 2);
463 }
464 
465 TEST_CASE("numeric_test - normalize")
466 {
467     using namespace fplus;
468 
469     REQUIRE_EQ(normalize_min_max(0.0, 10.0, Doubles({1, 3, 6})), Doubles({0, 4, 10}));
470     REQUIRE_EQ(normalize_mean_stddev(3.0, 2.0, Doubles({7, 8})), Doubles({1, 5}));
471     REQUIRE_EQ(standardize(Doubles({2, 6})), Doubles({-1, 1}));
472 
473     REQUIRE_EQ(normalize_min_max(0.0f, 10.0f, Floats({1, 3, 6})), Floats({0, 4, 10}));
474     REQUIRE_EQ(normalize_mean_stddev(3.0f, 2.0f, Floats({7, 8})), Floats({1, 5}));
475     REQUIRE_EQ(standardize(Floats({2, 6})), Floats({-1, 1}));
476 
477     Floats xs1 = {1, 3, 6};
478     Floats xs2 = {7, 8};
479     Floats xs3 = {2.0, 6.0};
480     REQUIRE_EQ(normalize_min_max(0.0f, 10.0f, xs1), Floats({0, 4, 10}));
481     REQUIRE_EQ(normalize_mean_stddev(3.0f, 2.0f, xs2), Floats({1, 5}));
482     REQUIRE_EQ(standardize(xs3), Floats({-1, 1}));
483 
484 }
485 
486 TEST_CASE("numeric_test - winsorize")
487 {
488     using namespace fplus;
489 
490     REQUIRE_EQ(winsorize(0.1, Doubles()), Doubles());
491     REQUIRE_EQ(winsorize(0.1, Doubles({1})), Doubles({1}));
492     REQUIRE_EQ(winsorize(0.4, Doubles({1,2})), Doubles({1,2}));
493     REQUIRE_EQ(winsorize(0.32, Doubles({1,2,3})), Doubles({1,2,3}));
494     REQUIRE_EQ(winsorize(0.34, Doubles({1,2,3})), Doubles({2,2,2}));
495     REQUIRE_EQ(winsorize(0.1, Doubles({1,3,4,4,4,4,4,4,6,8})), Doubles({3,3,4,4,4,4,4,4,6,6}));
496     REQUIRE_EQ(winsorize(-0.1, Doubles({1,3,4,4,4,4,4,4,6,8})), Doubles({1,3,4,4,4,4,4,4,6,8}));
497     REQUIRE_EQ(winsorize(0.1, Doubles({4,4,4,3,8,4,6,4,3,4})), Doubles({3,3,4,4,4,4,4,4,6,6}));
498     REQUIRE_EQ(winsorize(0, Doubles({1,3,4,4,4,4,4,4,6,8})), Doubles({1,3,4,4,4,4,4,4,6,8}));
499 
500     const auto median_result = winsorize(0.6, Doubles({1,2}));
501     REQUIRE_EQ(median_result.size(), 2);
502     REQUIRE(fplus::is_in_interval_around(0.001, 1.5, median_result[0]));
503     REQUIRE(fplus::is_in_interval_around(0.001, 1.5, median_result[1]));
504 }
505 
506 TEST_CASE("numeric_test - histogram")
507 {
508     using namespace fplus;
509 
510     typedef std::vector<int> ints;
511     typedef std::pair<int, int> interval;
512     typedef std::vector<interval> intervals;
513     typedef std::pair<interval, std::size_t> bin;
514     typedef std::vector<bin> bins;
515 
516     const ints xs = {0,1,4,5,6,7,8,9};
517     const intervals intervals1 = {{0,4}, {4,5}, {6,8}};
518     const bins result1 = {{{0, 4}, 2}, {{4, 5}, 1}, {{6, 8}, 2}};
519 
520     REQUIRE_EQ(histogram_using_intervals(intervals1, xs), result1);
521 }
522 
523 TEST_CASE("numeric_test - generate_consecutive_intervals")
524 {
525     using namespace fplus;
526 
527     typedef std::pair<int, int> interval;
528     typedef std::vector<interval> intervals;
529 
530     const intervals result = {{0,2}, {2,4}, {4,6}, {6,8}};
531 
532     REQUIRE_EQ(generate_consecutive_intervals(0, 2, 4), result);
533 }
534 
535 TEST_CASE("numeric_test - histogram_intervals")
536 {
537     using namespace fplus;
538 
539     typedef std::vector<int> ints;
540     typedef std::pair<int, std::size_t> bin;
541     typedef std::vector<bin> bins;
542 
543     const ints xs = {0,1,4,5,7,8,9};
544     const bins result1 = {{1, 2}, {3, 0}, {5, 2}, {7, 1}};
545 
546     REQUIRE_EQ(histogram(1, 2, 4, xs), result1);
547 }
548 
549 TEST_CASE("numeric_test - modulo_chain")
550 {
551     using namespace fplus;
552     typedef std::vector<int> ints;
553     REQUIRE_EQ(modulo_chain(ints({24, 60, 60}), 23), ints({0, 0, 0, 23}));
554     REQUIRE_EQ(modulo_chain(ints({24, 60, 60}), 7223), ints({0, 2, 0, 23}));
555     REQUIRE_EQ(
556         modulo_chain(ints({24, 60, 60, 1000}),
557             3 * 24 * 60 * 60 * 1000 +
558             17 * 60 * 60 * 1000 +
559             4 * 60 * 1000 +
560             31 * 1000 +
561             256),
562         ints({3, 17, 4, 31, 256}));
563 }
564 
565 TEST_CASE("numeric_test - line_equation")
566 {
567     using namespace fplus;
568 
569     REQUIRE(is_in_interval_around(0.001, 2.0, line_equation(
570         std::make_pair(0.0, 0.0),
571         std::make_pair(2.0, 1.0), 4.0)));
572     REQUIRE(is_in_interval_around(0.001, -2.0, line_equation(
573         std::make_pair(-1.0, 1.0),
574         std::make_pair(-2.0, 4.0), 0.0)));
575 }
576