2 * This file is part of the GROMACS molecular simulation package.
4 * Copyright (c) 2014,2015,2016,2017,2018 by the GROMACS development team.
5 * Copyright (c) 2019,2020,2021, by the GROMACS development team, led by
6 * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
7 * and including many others, as listed in the AUTHORS file in the
8 * top-level source directory and at http://www.gromacs.org.
10 * GROMACS is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public License
12 * as published by the Free Software Foundation; either version 2.1
13 * of the License, or (at your option) any later version.
15 * GROMACS is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with GROMACS; if not, see
22 * http://www.gnu.org/licenses, or write to the Free Software Foundation,
23 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
25 * If you want to redistribute modifications to GROMACS, please
26 * consider that scientific software is very special. Version
27 * control is crucial - bugs must be traceable. We will be happy to
28 * consider code for inclusion in the official distribution, but
29 * derived work must not be called official GROMACS. Details are found
30 * in the README & COPYING files - if they are missing, get the
31 * official version at http://www.gromacs.org.
33 * To help us fund GROMACS development, we humbly ask that you cite
34 * the research papers on the package. Check out http://www.gromacs.org.
40 #include <gtest/gtest.h>
42 #include "gromacs/math/units.h"
43 #include "gromacs/math/utilities.h"
44 #include "gromacs/simd/simd.h"
45 #include "gromacs/utility/basedefinitions.h"
47 #include "testutils/testasserts.h"
60 /*! \addtogroup module_simd */
63 // Since these functions are mostly wrappers for similar standard library
64 // functions, we typically just test 1-2 values to make sure we call the right
67 /******************************************
68 * Default floating-point precision tests *
69 ******************************************/
71 TEST(SimdScalarMathTest, copysign)
73 EXPECT_EQ(real(-c1), copysign(real(c1), real(-c2)));
74 EXPECT_EQ(real(c2), copysign(real(c2), real(c3)));
77 TEST(SimdScalarMathTest, invsqrtPair)
84 invsqrtPair(x0, x1, &out0, &out1);
86 EXPECT_EQ(invsqrt(x0), out0);
87 EXPECT_EQ(invsqrt(x1), out1);
90 TEST(SimdScalarMathTest, inv)
94 EXPECT_EQ(real(1.0) / x0, inv(x0));
97 TEST(SimdScalarMathTest, maskzInvsqrt)
101 EXPECT_EQ(invsqrt(x0), maskzInvsqrt(x0, true));
102 EXPECT_EQ(real(0), maskzInvsqrt(x0, false));
105 TEST(SimdScalarMathTest, log)
109 EXPECT_EQ(std::log(x0), log(x0));
112 TEST(SimdScalarMathTest, exp2)
116 EXPECT_EQ(std::exp2(x0), exp2(x0));
119 TEST(SimdScalarMathTest, exp)
123 EXPECT_EQ(std::exp(x0), exp(x0));
126 TEST(SimdScalarMathTest, erf)
130 EXPECT_EQ(std::erf(x0), erf(x0));
133 TEST(SimdScalarMathTest, erfc)
137 EXPECT_EQ(std::erfc(x0), erfc(x0));
140 TEST(SimdScalarMathTest, sincos)
147 EXPECT_EQ(std::sin(x0), s);
148 EXPECT_EQ(std::cos(x0), c);
151 TEST(SimdScalarMathTest, sin)
155 EXPECT_EQ(std::sin(x0), sin(x0));
158 TEST(SimdScalarMathTest, cos)
162 EXPECT_EQ(std::cos(x0), cos(x0));
165 TEST(SimdScalarMathTest, tan)
169 EXPECT_EQ(std::tan(x0), tan(x0));
173 TEST(SimdScalarMathTest, asin)
177 EXPECT_EQ(std::asin(x0), asin(x0));
180 TEST(SimdScalarMathTest, acos)
184 EXPECT_EQ(std::acos(x0), acos(x0));
187 TEST(SimdScalarMathTest, atan)
191 EXPECT_EQ(std::atan(x0), atan(x0));
194 TEST(SimdScalarMathTest, atan2)
197 real y = std::sqrt(c0);
200 EXPECT_EQ(std::atan2(y, x), atan2(y, x));
203 TEST(SimdScalarMathTest, pmeForceCorrection)
207 // Calculate reference value for z2!=0
208 real z = std::sqrt(z2);
209 real ref = 2.0 * std::exp(-z2) / (std::sqrt(M_PI) * z2) - std::erf(z) / (z2 * z);
211 // Pme correction only needs to be ~1e-6 accuracy single, 1e-10 double
213 FloatingPointTolerance tolerance(relativeToleranceAsFloatingPoint(1.0, 5e-10));
215 FloatingPointTolerance tolerance(relativeToleranceAsFloatingPoint(1.0, 5e-6));
218 EXPECT_REAL_EQ_TOL(ref, pmeForceCorrection(z2), tolerance);
221 TEST(SimdScalarMathTest, pmePotentialCorrection)
225 // Calculate reference value for z2!=0
226 real z = std::sqrt(z2);
227 real ref = std::erf(z) / z;
229 // Pme correction only needs to be ~1e-6 accuracy single, 1e-10 double
231 FloatingPointTolerance tolerance(relativeToleranceAsFloatingPoint(1.0, 5e-10));
233 FloatingPointTolerance tolerance(relativeToleranceAsFloatingPoint(1.0, 5e-6));
236 EXPECT_REAL_EQ_TOL(ref, pmePotentialCorrection(z2), tolerance);
239 /*******************************************
240 * Double precision, single accuracy tests *
241 *******************************************/
243 TEST(SimdScalarMathTest, invsqrtPairSingleAccuracy)
250 invsqrtPairSingleAccuracy(x0, x1, &out0, &out1);
252 EXPECT_EQ(invsqrt(static_cast<float>(x0)), static_cast<float>(out0));
253 EXPECT_EQ(invsqrt(static_cast<float>(x1)), static_cast<float>(out1));
256 TEST(SimdScalarMathTest, invSingleAccuracy)
260 EXPECT_EQ(1.0F / static_cast<float>(x0), static_cast<float>(invSingleAccuracy(x0)));
263 TEST(SimdScalarMathTest, maskzInvsqrtSingleAccuracy)
267 EXPECT_EQ(invsqrt(static_cast<float>(x0)), static_cast<float>(maskzInvsqrtSingleAccuracy(x0, true)));
268 EXPECT_EQ(0.0F, static_cast<float>(maskzInvsqrtSingleAccuracy(x0, false)));
271 TEST(SimdScalarMathTest, logSingleAccuracy)
275 EXPECT_EQ(std::log(static_cast<float>(x0)), static_cast<float>(logSingleAccuracy(x0)));
278 TEST(SimdScalarMathTest, exp2SingleAccuracy)
282 EXPECT_EQ(std::exp2(static_cast<float>(x0)), static_cast<float>(exp2SingleAccuracy(x0)));
285 TEST(SimdScalarMathTest, expSingleAccuracy)
289 EXPECT_EQ(std::exp(static_cast<float>(x0)), static_cast<float>(expSingleAccuracy(x0)));
292 TEST(SimdScalarMathTest, erfSingleAccuracy)
296 EXPECT_EQ(std::erf(static_cast<float>(x0)), static_cast<float>(erfSingleAccuracy(x0)));
299 TEST(SimdScalarMathTest, erfcSingleAccuracy)
303 EXPECT_EQ(std::erfc(static_cast<float>(x0)), static_cast<float>(erfcSingleAccuracy(x0)));
306 TEST(SimdScalarMathTest, sincosSingleAccuracy)
311 sincosSingleAccuracy(x0, &s, &c);
313 EXPECT_EQ(std::sin(static_cast<float>(x0)), static_cast<float>(s));
314 EXPECT_EQ(std::cos(static_cast<float>(x0)), static_cast<float>(c));
317 TEST(SimdScalarMathTest, sinSingleAccuracy)
321 EXPECT_EQ(std::sin(static_cast<float>(x0)), static_cast<float>(sinSingleAccuracy(x0)));
324 TEST(SimdScalarMathTest, cosSingleAccuracy)
328 EXPECT_EQ(std::cos(static_cast<float>(x0)), static_cast<float>(cosSingleAccuracy(x0)));
331 TEST(SimdScalarMathTest, tanSingleAccuracy)
335 EXPECT_EQ(std::tan(static_cast<float>(x0)), static_cast<float>(tanSingleAccuracy(x0)));
339 TEST(SimdScalarMathTest, asinSingleAccuracy)
343 EXPECT_EQ(std::asin(static_cast<float>(x0)), static_cast<float>(asinSingleAccuracy(x0)));
346 TEST(SimdScalarMathTest, acosSingleAccuracy)
350 EXPECT_EQ(std::acos(static_cast<float>(x0)), static_cast<float>(acosSingleAccuracy(x0)));
353 TEST(SimdScalarMathTest, atanSingleAccuracy)
357 EXPECT_EQ(std::atan(static_cast<float>(x0)), static_cast<float>(atanSingleAccuracy(x0)));
360 TEST(SimdScalarMathTest, atan2SingleAccuracy)
363 double y = std::sqrt(c0);
366 EXPECT_EQ(std::atan2(static_cast<float>(y), static_cast<float>(x)),
367 static_cast<float>(atan2SingleAccuracy(y, x)));
370 TEST(SimdScalarMathTest, pmeForceCorrectionSingleAccuracy)
374 // Calculate reference value for z2!=0 in single precision
375 float z = std::sqrt(static_cast<float>(z2));
376 float ref = 2.0 * std::exp(static_cast<float>(-z2)) / (std::sqrt(static_cast<float>(M_PI)) * z2)
377 - std::erf(z) / (z2 * z);
379 // Pme correction only needs to be ~1e-6 accuracy single
380 FloatingPointTolerance tolerance(relativeToleranceAsFloatingPoint(1.0, 5e-6));
382 EXPECT_REAL_EQ_TOL(ref, static_cast<float>(pmeForceCorrectionSingleAccuracy(z2)), tolerance);
385 TEST(SimdScalarMathTest, pmePotentialCorrectionSingleAccuracy)
389 // Calculate reference value for z2!=0 in single precision
390 float z = std::sqrt(static_cast<float>(z2));
391 float ref = std::erf(z) / z;
393 // Pme correction only needs to be ~1e-6 accuracy single
394 FloatingPointTolerance tolerance(relativeToleranceAsFloatingPoint(1.0, 5e-6));
396 EXPECT_REAL_EQ_TOL(ref, static_cast<float>(pmePotentialCorrectionSingleAccuracy(z2)), tolerance);
400 /*! \endcond internal */