Apply clang-format to source tree
[alexxy/gromacs.git] / src / gromacs / math / tests / functions.cpp
1 /*
2  * This file is part of the GROMACS molecular simulation package.
3  *
4  * Copyright (c) 2015,2016,2017,2018,2019, by the GROMACS development team, led by
5  * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
6  * and including many others, as listed in the AUTHORS file in the
7  * top-level source directory and at http://www.gromacs.org.
8  *
9  * GROMACS is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public License
11  * as published by the Free Software Foundation; either version 2.1
12  * of the License, or (at your option) any later version.
13  *
14  * GROMACS is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with GROMACS; if not, see
21  * http://www.gnu.org/licenses, or write to the Free Software Foundation,
22  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA.
23  *
24  * If you want to redistribute modifications to GROMACS, please
25  * consider that scientific software is very special. Version
26  * control is crucial - bugs must be traceable. We will be happy to
27  * consider code for inclusion in the official distribution, but
28  * derived work must not be called official GROMACS. Details are found
29  * in the README & COPYING files - if they are missing, get the
30  * official version at http://www.gromacs.org.
31  *
32  * To help us fund GROMACS development, we humbly ask that you cite
33  * the research papers on the package. Check out http://www.gromacs.org.
34  */
35 /*! \internal \file
36  * \brief
37  * Tests for simple math functions.
38  *
39  * \author Erik Lindahl <erik.lindahl@gmail.com>
40  * \ingroup module_math
41  */
42 #include "gmxpre.h"
43
44 #include "gromacs/math/functions.h"
45
46 #include <cmath>
47 #include <cstdint>
48
49 #include <gtest/gtest.h>
50
51 #include "testutils/refdata.h"
52 #include "testutils/testasserts.h"
53
54 namespace
55 {
56
57 TEST(FunctionTest, StaticLog2)
58 {
59     gmx::test::TestReferenceData    data;
60     gmx::test::TestReferenceChecker checker(data.rootChecker());
61     std::vector<int>                result(11);
62
63     // This needs to be expanded manually since it is evaluated at compile time,
64     // and the compiler chokes if we put it as formal arguments to push_back
65     result[0]  = gmx::StaticLog2<1>::value;
66     result[1]  = gmx::StaticLog2<2>::value;
67     result[2]  = gmx::StaticLog2<3>::value;
68     result[3]  = gmx::StaticLog2<4>::value;
69     result[4]  = gmx::StaticLog2<5>::value;
70     result[5]  = gmx::StaticLog2<6>::value;
71     result[6]  = gmx::StaticLog2<7>::value;
72     result[7]  = gmx::StaticLog2<8>::value;
73     result[8]  = gmx::StaticLog2<0xFFFFFFFF>::value;
74     result[9]  = gmx::StaticLog2<9876543210>::value; // > 32 bits
75     result[10] = gmx::StaticLog2<0xFFFFFFFFFFFFFFFFULL>::value;
76
77     checker.checkSequence(result.begin(), result.end(), "StaticLog2");
78 }
79
80 TEST(FunctionTest, Log2I32Bit)
81 {
82     gmx::test::TestReferenceData    data;
83     gmx::test::TestReferenceChecker checker(data.rootChecker());
84     std::vector<int>                result;
85
86     for (std::uint32_t i = 1; i <= 0xF; i++)
87     {
88         result.push_back(gmx::log2I(i));
89     }
90
91     for (std::uint32_t i = 0; i <= 0xF; i++)
92     {
93         result.push_back(gmx::log2I(static_cast<std::uint32_t>(0xFFFFFFF0 + i)));
94     }
95     checker.checkSequence(result.begin(), result.end(), "Log2I32Bit");
96 }
97
98 TEST(FunctionTest, Log2I64Bit)
99 {
100     gmx::test::TestReferenceData    data;
101     gmx::test::TestReferenceChecker checker(data.rootChecker());
102     std::vector<int>                result;
103
104     for (std::uint64_t i = 1; i <= 0xF; i++)
105     {
106         result.push_back(gmx::log2I(i));
107     }
108
109     for (std::uint64_t i = 0; i <= 0x1F; i++)
110     {
111         result.push_back(gmx::log2I(static_cast<std::uint64_t>(0xFFFFFFF0ULL + i)));
112     }
113
114     for (std::uint64_t i = 0; i <= 0xF; i++)
115     {
116         result.push_back(gmx::log2I(static_cast<std::uint64_t>(0xFFFFFFFFFFFFFFF0ULL + i)));
117     }
118     checker.checkSequence(result.begin(), result.end(), "Log2I64Bit");
119 }
120
121 TEST(FunctionTest, GreatestCommonDivisor)
122 {
123     EXPECT_EQ(8, gmx::greatestCommonDivisor(24, 64));
124     EXPECT_EQ(8, gmx::greatestCommonDivisor(64, 24));
125     EXPECT_EQ(1, gmx::greatestCommonDivisor(169, 289));
126 }
127
128 TEST(FunctionTest, InvsqrtFloat)
129 {
130     gmx::test::TestReferenceData    data;
131     gmx::test::TestReferenceChecker checker(data.rootChecker());
132     std::vector<float>              result;
133
134     for (float f = 1.0; f < 10.0; f += 1.0)
135     {
136         result.push_back(gmx::invsqrt(f));
137     }
138     checker.checkSequence(result.begin(), result.end(), "InvsqrtFloat");
139 }
140
141 TEST(FunctionTest, InvsqrtDouble)
142 {
143     gmx::test::TestReferenceData    data;
144     gmx::test::TestReferenceChecker checker(data.rootChecker());
145     std::vector<double>             result;
146
147     for (double f = 1.0; f < 10.0; f += 1.0) // NOLINT(clang-analyzer-security.FloatLoopCounter)
148     {
149         result.push_back(gmx::invsqrt(f));
150     }
151     checker.checkSequence(result.begin(), result.end(), "InvsqrtDouble");
152 }
153
154 TEST(FunctionTest, InvsqrtInteger)
155 {
156     gmx::test::TestReferenceData    data;
157     gmx::test::TestReferenceChecker checker(data.rootChecker());
158     std::vector<double>             result;
159
160     for (int i = 1; i < 10; i++)
161     {
162         result.push_back(gmx::invsqrt(i));
163     }
164     checker.checkSequence(result.begin(), result.end(), "InvsqrtInteger");
165 }
166
167 TEST(FunctionTest, InvcbrtFloat)
168 {
169     gmx::test::TestReferenceData    data;
170     gmx::test::TestReferenceChecker checker(data.rootChecker());
171     std::vector<float>              result;
172
173     for (int f : { -5, -4, -3, -2, -1, 1, 2, 3, 4 })
174     {
175         result.push_back(gmx::invcbrt(f));
176     }
177     checker.checkSequence(result.begin(), result.end(), "InvcbrtFloat");
178 }
179
180 TEST(FunctionTest, InvcbrtDouble)
181 {
182     gmx::test::TestReferenceData    data;
183     gmx::test::TestReferenceChecker checker(data.rootChecker());
184     std::vector<double>             result;
185
186     for (double d : { -5, -4, -3, -2, -1, 1, 2, 3, 4 })
187     {
188         result.push_back(gmx::invcbrt(d));
189     }
190     checker.checkSequence(result.begin(), result.end(), "InvcbrtDouble");
191 }
192
193 TEST(FunctionTest, InvcbrtInteger)
194 {
195     gmx::test::TestReferenceData    data;
196     gmx::test::TestReferenceChecker checker(data.rootChecker());
197     std::vector<double>             result;
198
199     for (int i : { -5, -4, -3, -2, -1, 1, 2, 3, 4 })
200     {
201         result.push_back(gmx::invcbrt(i));
202     }
203     checker.checkSequence(result.begin(), result.end(), "InvcbrtInteger");
204 }
205
206
207 TEST(FunctionTest, SixthrootFloat)
208 {
209     gmx::test::TestReferenceData    data;
210     gmx::test::TestReferenceChecker checker(data.rootChecker());
211     std::vector<float>              result;
212
213     for (float f = 0; f < 10.0; f += 1.0)
214     {
215         result.push_back(gmx::sixthroot(f));
216     }
217     checker.checkSequence(result.begin(), result.end(), "SixthrootFloat");
218 }
219
220 TEST(FunctionTest, SixthrootDouble)
221 {
222     gmx::test::TestReferenceData    data;
223     gmx::test::TestReferenceChecker checker(data.rootChecker());
224     std::vector<double>             result;
225
226     for (double d = 0; d < 10.0; d += 1.0) // NOLINT(clang-analyzer-security.FloatLoopCounter)
227     {
228         result.push_back(gmx::sixthroot(d));
229     }
230     checker.checkSequence(result.begin(), result.end(), "SixthrootDouble");
231 }
232
233 TEST(FunctionTest, SixthrootInteger)
234 {
235     gmx::test::TestReferenceData    data;
236     gmx::test::TestReferenceChecker checker(data.rootChecker());
237     std::vector<double>             result;
238
239     result.reserve(10);
240     for (int i = 0; i < 10; i++)
241     {
242         result.push_back(gmx::sixthroot(i));
243     }
244     checker.checkSequence(result.begin(), result.end(), "SixthrootInteger");
245 }
246
247 TEST(FunctionTest, InvsixthrootFloat)
248 {
249     gmx::test::TestReferenceData    data;
250     gmx::test::TestReferenceChecker checker(data.rootChecker());
251     std::vector<float>              result;
252
253     for (float f = 1.0; f < 10.0; f += 1.0)
254     {
255         result.push_back(gmx::invsixthroot(f));
256     }
257     checker.checkSequence(result.begin(), result.end(), "InvsixthrootFloat");
258 }
259
260 TEST(FunctionTest, InvsixthrootDouble)
261 {
262     gmx::test::TestReferenceData    data;
263     gmx::test::TestReferenceChecker checker(data.rootChecker());
264     std::vector<double>             result;
265
266     for (double d = 1.0; d < 10.0; d += 1.0) // NOLINT(clang-analyzer-security.FloatLoopCounter)
267     {
268         result.push_back(gmx::invsixthroot(d));
269     }
270     checker.checkSequence(result.begin(), result.end(), "InvsixthrootDouble");
271 }
272
273 TEST(FunctionTest, InvsixthrootInteger)
274 {
275     gmx::test::TestReferenceData    data;
276     gmx::test::TestReferenceChecker checker(data.rootChecker());
277     std::vector<double>             result;
278
279     for (int i = 1; i < 10; i++)
280     {
281         result.push_back(gmx::invsixthroot(i));
282     }
283     checker.checkSequence(result.begin(), result.end(), "InvsixthrootInteger");
284 }
285
286 TEST(FunctionTest, Powers)
287 {
288     // These should be remarkably difficult to screw up, but test each
289     // of them once anyway with integer and fp arguments to catch typos.
290     EXPECT_EQ(4, gmx::square(2));
291     EXPECT_EQ(8, gmx::power3(2));
292     EXPECT_EQ(16, gmx::power4(2));
293     EXPECT_EQ(32, gmx::power5(2));
294     EXPECT_EQ(64, gmx::power6(2));
295     EXPECT_EQ(4096, gmx::power12(2));
296
297     EXPECT_EQ(6.25, gmx::square(2.5));
298     EXPECT_EQ(15.625, gmx::power3(2.5));
299     EXPECT_EQ(39.0625, gmx::power4(2.5));
300     EXPECT_EQ(97.65625, gmx::power5(2.5));
301     EXPECT_EQ(244.140625, gmx::power6(2.5));
302     EXPECT_EQ(59604.644775390625, gmx::power12(2.5));
303 }
304
305 TEST(FunctionTest, ErfInvFloat)
306 {
307     gmx::test::TestReferenceData    data;
308     gmx::test::TestReferenceChecker checker(data.rootChecker());
309     std::vector<float>              result;
310     int                             npoints = 10;
311
312     for (int i = 0; i < npoints; i++)
313     {
314         float r = float(2 * i - npoints + 1) / float(npoints);
315
316         result.push_back(gmx::erfinv(r));
317     }
318     checker.checkSequence(result.begin(), result.end(), "ErfInvFloat");
319 }
320
321 TEST(FunctionTest, ErfInvDouble)
322 {
323     gmx::test::TestReferenceData    data;
324     gmx::test::TestReferenceChecker checker(data.rootChecker());
325     std::vector<double>             result;
326     int                             npoints = 10;
327
328     for (int i = 0; i < npoints; i++)
329     {
330         double r = double(2 * i - npoints + 1) / npoints;
331
332         result.push_back(gmx::erfinv(r));
333     }
334     checker.checkSequence(result.begin(), result.end(), "ErfInvDouble");
335 }
336
337 TEST(FunctionTest, ErfAndErfInvAreInversesFloat)
338 {
339     int npoints = 1000;
340
341     for (int i = 0; i < npoints; i++)
342     {
343         float r = float(2 * i - npoints + 1) / float(npoints);
344         EXPECT_FLOAT_EQ_TOL(r, std::erf(gmx::erfinv(r)), gmx::test::ulpTolerance(10));
345     }
346 }
347
348 TEST(FunctionTest, ErfAndErfInvAreInversesDouble)
349 {
350     int npoints = 1000;
351
352     for (int i = 0; i < npoints; i++)
353     {
354         double r = double(2 * i - npoints + 1) / npoints;
355         EXPECT_DOUBLE_EQ_TOL(r, std::erf(gmx::erfinv(r)), gmx::test::ulpTolerance(10));
356     }
357 }
358
359 } // namespace