1*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 2*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 3*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 4*0fca6ea1SDimitry Andric 5*0fca6ea1SDimitry Andric // Do not attempt to use LLVM ostream etc from gtest. 6*0fca6ea1SDimitry Andric // #define GTEST_NO_LLVM_SUPPORT 1 7*0fca6ea1SDimitry Andric 8*0fca6ea1SDimitry Andric #include "../nsan.h" 9*0fca6ea1SDimitry Andric #include "gtest/gtest.h" 10*0fca6ea1SDimitry Andric 11*0fca6ea1SDimitry Andric #include <cmath> 12*0fca6ea1SDimitry Andric 13*0fca6ea1SDimitry Andric namespace __nsan { 14*0fca6ea1SDimitry Andric 15*0fca6ea1SDimitry Andric template <typename FT, auto next> void TestFT() { 16*0fca6ea1SDimitry Andric // Basic local tests anchored at 0.0. 17*0fca6ea1SDimitry Andric ASSERT_EQ(GetULPDiff<FT>(0.0, 0.0), 0); 18*0fca6ea1SDimitry Andric ASSERT_EQ(GetULPDiff<FT>(-0.0, 0.0), 0); 19*0fca6ea1SDimitry Andric ASSERT_EQ(GetULPDiff<FT>(next(-0.0, -1.0), 0.0), 1); 20*0fca6ea1SDimitry Andric ASSERT_EQ(GetULPDiff<FT>(next(0.0, 1.0), -0.0), 1); 21*0fca6ea1SDimitry Andric ASSERT_EQ(GetULPDiff<FT>(next(-0.0, -1.0), next(0.0, 1.0)), 2); 22*0fca6ea1SDimitry Andric // Basic local tests anchored at 2.0. 23*0fca6ea1SDimitry Andric ASSERT_EQ(GetULPDiff<FT>(next(2.0, 1.0), 2.0), 1); 24*0fca6ea1SDimitry Andric ASSERT_EQ(GetULPDiff<FT>(next(2.0, 3.0), 2.0), 1); 25*0fca6ea1SDimitry Andric ASSERT_EQ(GetULPDiff<FT>(next(2.0, 1.0), next(2.0, 3.0)), 2); 26*0fca6ea1SDimitry Andric 27*0fca6ea1SDimitry Andric ASSERT_NE(GetULPDiff<FT>(-0.01, 0.01), kMaxULPDiff); 28*0fca6ea1SDimitry Andric 29*0fca6ea1SDimitry Andric // Basic local tests anchored at a random number. 30*0fca6ea1SDimitry Andric const FT X = 4863.5123; 31*0fca6ea1SDimitry Andric const FT To = 2 * X; 32*0fca6ea1SDimitry Andric FT Y = X; 33*0fca6ea1SDimitry Andric ASSERT_EQ(GetULPDiff<FT>(X, Y), 0); 34*0fca6ea1SDimitry Andric ASSERT_EQ(GetULPDiff<FT>(-X, -Y), 0); 35*0fca6ea1SDimitry Andric Y = next(Y, To); 36*0fca6ea1SDimitry Andric ASSERT_EQ(GetULPDiff<FT>(X, Y), 1); 37*0fca6ea1SDimitry Andric ASSERT_EQ(GetULPDiff<FT>(-X, -Y), 1); 38*0fca6ea1SDimitry Andric Y = next(Y, To); 39*0fca6ea1SDimitry Andric ASSERT_EQ(GetULPDiff<FT>(X, Y), 2); 40*0fca6ea1SDimitry Andric ASSERT_EQ(GetULPDiff<FT>(-X, -Y), 2); 41*0fca6ea1SDimitry Andric Y = next(Y, To); 42*0fca6ea1SDimitry Andric ASSERT_EQ(GetULPDiff<FT>(X, Y), 3); 43*0fca6ea1SDimitry Andric ASSERT_EQ(GetULPDiff<FT>(-X, -Y), 3); 44*0fca6ea1SDimitry Andric 45*0fca6ea1SDimitry Andric // Values with larger differences. 46*0fca6ea1SDimitry Andric static constexpr const __sanitizer::u64 MantissaSize = 47*0fca6ea1SDimitry Andric __sanitizer::u64{1} << FTInfo<FT>::kMantissaBits; 48*0fca6ea1SDimitry Andric ASSERT_EQ(GetULPDiff<FT>(1.0, next(2.0, 1.0)), MantissaSize - 1); 49*0fca6ea1SDimitry Andric ASSERT_EQ(GetULPDiff<FT>(1.0, 2.0), MantissaSize); 50*0fca6ea1SDimitry Andric ASSERT_EQ(GetULPDiff<FT>(1.0, next(2.0, 3.0)), MantissaSize + 1); 51*0fca6ea1SDimitry Andric ASSERT_EQ(GetULPDiff<FT>(1.0, 3.0), (3 * MantissaSize) / 2); 52*0fca6ea1SDimitry Andric } 53*0fca6ea1SDimitry Andric 54*0fca6ea1SDimitry Andric TEST(NSanTest, Float) { TestFT<float, nextafterf>(); } 55*0fca6ea1SDimitry Andric 56*0fca6ea1SDimitry Andric TEST(NSanTest, Double) { 57*0fca6ea1SDimitry Andric TestFT<double, static_cast<double (*)(double, double)>(nextafter)>(); 58*0fca6ea1SDimitry Andric } 59*0fca6ea1SDimitry Andric 60*0fca6ea1SDimitry Andric TEST(NSanTest, Float128) { 61*0fca6ea1SDimitry Andric // Very basic tests. FIXME: improve when we have nextafter<__float128>. 62*0fca6ea1SDimitry Andric ASSERT_EQ(GetULPDiff<__float128>(0.0, 0.0), 0); 63*0fca6ea1SDimitry Andric ASSERT_EQ(GetULPDiff<__float128>(-0.0, 0.0), 0); 64*0fca6ea1SDimitry Andric ASSERT_NE(GetULPDiff<__float128>(-0.01, 0.01), kMaxULPDiff); 65*0fca6ea1SDimitry Andric } 66*0fca6ea1SDimitry Andric 67*0fca6ea1SDimitry Andric } // end namespace __nsan 68