Fix precision loss in tabulated normal distribution
[gromacs.git] / src / gromacs / math / tests / functions.cpp
blobcbd80479e5a974f1e69eaceb216453f459b2a192
1 /*
2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2015,2016, 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.
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.
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.
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.
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.
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.
35 /*! \internal \file
36 * \brief
37 * Tests for simple math functions.
39 * \author Erik Lindahl <erik.lindahl@gmail.com>
40 * \ingroup module_math
42 #include "gmxpre.h"
44 #include "gromacs/math/functions.h"
46 #include <cmath>
47 #include <cstdint>
49 #include <gtest/gtest.h>
51 #include "testutils/refdata.h"
52 #include "testutils/testasserts.h"
54 namespace
57 TEST(FunctionTest, StaticLog2)
59 gmx::test::TestReferenceData data;
60 gmx::test::TestReferenceChecker checker(data.rootChecker());
61 std::vector<int> result(11);
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;
77 checker.checkSequence(result.begin(), result.end(), "StaticLog2");
80 TEST(FunctionTest, Log2I32Bit)
82 gmx::test::TestReferenceData data;
83 gmx::test::TestReferenceChecker checker(data.rootChecker());
84 std::vector<int> result;
86 for (std::uint32_t i = 1; i <= 0xF; i++)
88 result.push_back(gmx::log2I(i));
91 for (std::uint32_t i = 0; i <= 0xF; i++)
93 result.push_back(gmx::log2I(static_cast<std::uint32_t>(0xFFFFFFF0+i)));
95 checker.checkSequence(result.begin(), result.end(), "Log2I32Bit");
98 TEST(FunctionTest, Log2I64Bit)
100 gmx::test::TestReferenceData data;
101 gmx::test::TestReferenceChecker checker(data.rootChecker());
102 std::vector<int> result;
104 for (std::uint64_t i = 1; i <= 0xF; i++)
106 result.push_back(gmx::log2I(i));
109 for (std::uint64_t i = 0; i <= 0x1F; i++)
111 result.push_back(gmx::log2I(static_cast<std::uint64_t>(0xFFFFFFF0ULL+i)));
114 for (std::uint64_t i = 0; i <= 0xF; i++)
116 result.push_back(gmx::log2I(static_cast<std::uint64_t>(0xFFFFFFFFFFFFFFF0ULL+i)));
118 checker.checkSequence(result.begin(), result.end(), "Log2I64Bit");
121 TEST(FunctionTest, GreatestCommonDivisor)
123 EXPECT_EQ(8, gmx::greatestCommonDivisor(24, 64));
124 EXPECT_EQ(8, gmx::greatestCommonDivisor(64, 24));
125 EXPECT_EQ(1, gmx::greatestCommonDivisor(169, 289));
128 TEST(FunctionTest, InvsqrtFloat)
130 gmx::test::TestReferenceData data;
131 gmx::test::TestReferenceChecker checker(data.rootChecker());
132 std::vector<float> result;
134 for (float f = 1.0; f < 10.0; f += 1.0)
136 result.push_back(gmx::invsqrt(f));
138 checker.checkSequence(result.begin(), result.end(), "InvsqrtFloat");
141 TEST(FunctionTest, InvsqrtDouble)
143 gmx::test::TestReferenceData data;
144 gmx::test::TestReferenceChecker checker(data.rootChecker());
145 std::vector<double> result;
147 for (double f = 1.0; f < 10.0; f += 1.0)
149 result.push_back(gmx::invsqrt(f));
151 checker.checkSequence(result.begin(), result.end(), "InvsqrtDouble");
154 TEST(FunctionTest, InvsqrtInteger)
156 gmx::test::TestReferenceData data;
157 gmx::test::TestReferenceChecker checker(data.rootChecker());
158 std::vector<double> result;
160 for (int i = 1; i < 10; i++)
162 result.push_back(gmx::invsqrt(i));
164 checker.checkSequence(result.begin(), result.end(), "InvsqrtInteger");
167 TEST(FunctionTest, InvcbrtFloat)
169 gmx::test::TestReferenceData data;
170 gmx::test::TestReferenceChecker checker(data.rootChecker());
171 std::vector<float> result;
173 for (float f : {-5, -4, -3, -2, -1, 1, 2, 3, 4})
175 result.push_back(gmx::invcbrt(f));
177 checker.checkSequence(result.begin(), result.end(), "InvcbrtFloat");
180 TEST(FunctionTest, InvcbrtDouble)
182 gmx::test::TestReferenceData data;
183 gmx::test::TestReferenceChecker checker(data.rootChecker());
184 std::vector<double> result;
186 for (double d : {-5, -4, -3, -2, -1, 1, 2, 3, 4})
188 result.push_back(gmx::invcbrt(d));
190 checker.checkSequence(result.begin(), result.end(), "InvcbrtDouble");
193 TEST(FunctionTest, InvcbrtInteger)
195 gmx::test::TestReferenceData data;
196 gmx::test::TestReferenceChecker checker(data.rootChecker());
197 std::vector<double> result;
199 for (int i : {-5, -4, -3, -2, -1, 1, 2, 3, 4})
201 result.push_back(gmx::invcbrt(i));
203 checker.checkSequence(result.begin(), result.end(), "InvcbrtInteger");
207 TEST(FunctionTest, SixthrootFloat)
209 gmx::test::TestReferenceData data;
210 gmx::test::TestReferenceChecker checker(data.rootChecker());
211 std::vector<float> result;
213 for (float f = 0; f < 10.0; f += 1.0)
215 result.push_back(gmx::sixthroot(f));
217 checker.checkSequence(result.begin(), result.end(), "SixthrootFloat");
220 TEST(FunctionTest, SixthrootDouble)
222 gmx::test::TestReferenceData data;
223 gmx::test::TestReferenceChecker checker(data.rootChecker());
224 std::vector<double> result;
226 for (double d = 0; d < 10.0; d += 1.0)
228 result.push_back(gmx::sixthroot(d));
230 checker.checkSequence(result.begin(), result.end(), "SixthrootDouble");
233 TEST(FunctionTest, SixthrootInteger)
235 gmx::test::TestReferenceData data;
236 gmx::test::TestReferenceChecker checker(data.rootChecker());
237 std::vector<double> result;
239 for (int i = 0; i < 10; i++)
241 result.push_back(gmx::sixthroot(i));
243 checker.checkSequence(result.begin(), result.end(), "SixthrootInteger");
246 TEST(FunctionTest, InvsixthrootFloat)
248 gmx::test::TestReferenceData data;
249 gmx::test::TestReferenceChecker checker(data.rootChecker());
250 std::vector<float> result;
252 for (float f = 1.0; f < 10.0; f += 1.0)
254 result.push_back(gmx::sixthroot(f));
256 checker.checkSequence(result.begin(), result.end(), "InvsixthrootFloat");
259 TEST(FunctionTest, InvsixthrootDouble)
261 gmx::test::TestReferenceData data;
262 gmx::test::TestReferenceChecker checker(data.rootChecker());
263 std::vector<double> result;
265 for (double d = 1.0; d < 10.0; d += 1.0)
267 result.push_back(gmx::sixthroot(d));
269 checker.checkSequence(result.begin(), result.end(), "InvsixthrootDouble");
272 TEST(FunctionTest, InvsixthrootInteger)
274 gmx::test::TestReferenceData data;
275 gmx::test::TestReferenceChecker checker(data.rootChecker());
276 std::vector<double> result;
278 for (int i = 1; i < 10; i++)
280 result.push_back(gmx::sixthroot(i));
282 checker.checkSequence(result.begin(), result.end(), "InvsixthrootInteger");
285 TEST(FunctionTest, Powers)
287 // These should be remarkably difficult to screw up, but test each
288 // of them once anyway with integer and fp arguments to catch typos.
289 EXPECT_EQ(4, gmx::square(2));
290 EXPECT_EQ(8, gmx::power3(2));
291 EXPECT_EQ(16, gmx::power4(2));
292 EXPECT_EQ(32, gmx::power5(2));
293 EXPECT_EQ(64, gmx::power6(2));
294 EXPECT_EQ(4096, gmx::power12(2));
296 EXPECT_EQ(6.25, gmx::square(2.5));
297 EXPECT_EQ(15.625, gmx::power3(2.5));
298 EXPECT_EQ(39.0625, gmx::power4(2.5));
299 EXPECT_EQ(97.65625, gmx::power5(2.5));
300 EXPECT_EQ(244.140625, gmx::power6(2.5));
301 EXPECT_EQ(59604.644775390625, gmx::power12(2.5));
304 TEST(FunctionTest, ErfInvFloat)
306 gmx::test::TestReferenceData data;
307 gmx::test::TestReferenceChecker checker(data.rootChecker());
308 std::vector<float> result;
309 int npoints = 10;
311 for (int i = 0; i < npoints; i++)
313 float r = -1.0 + 2.0 * (float(i) + 0.5) / npoints;
315 result.push_back(gmx::erfinv(r));
317 checker.checkSequence(result.begin(), result.end(), "ErfInvFloat");
320 TEST(FunctionTest, ErfInvDouble)
322 gmx::test::TestReferenceData data;
323 gmx::test::TestReferenceChecker checker(data.rootChecker());
324 std::vector<double> result;
325 int npoints = 10;
327 for (int i = 0; i < npoints; i++)
329 double r = -1.0 + 2.0 * (double(i) + 0.5) / npoints;
331 result.push_back(gmx::erfinv(r));
333 checker.checkSequence(result.begin(), result.end(), "ErfInvDouble");
336 TEST(FunctionTest, ErfAndErfInvAreInversesFloat)
338 int npoints = 1000;
340 for (int i = 0; i < npoints; i++)
342 float r = -1.0 + 2.0 * (float(i) + 0.5) / npoints;
343 EXPECT_FLOAT_EQ_TOL(r, std::erf(gmx::erfinv(r)), gmx::test::ulpTolerance(10));
347 TEST(FunctionTest, ErfAndErfInvAreInversesDouble)
349 int npoints = 1000;
351 for (int i = 0; i < npoints; i++)
353 double r = -1.0 + 2.0 * (double(i) + 0.5) / npoints;
354 EXPECT_DOUBLE_EQ_TOL(r, std::erf(gmx::erfinv(r)), gmx::test::ulpTolerance(10));
358 } // namespace