forked from OSchip/llvm-project
[libc][math] Added atanf function.
Performance by core-math (core-math/glibc 2.31/current llvm-14): 28.879/20.843/20.15 Differential Revision: https://reviews.llvm.org/D132842
This commit is contained in:
parent
6c1fc7e430
commit
77e1d9beed
|
@ -105,6 +105,7 @@ set(TARGET_LIBM_ENTRYPOINTS
|
||||||
libc.src.fenv.feupdateenv
|
libc.src.fenv.feupdateenv
|
||||||
|
|
||||||
# math.h entrypoints
|
# math.h entrypoints
|
||||||
|
libc.src.math.atanf
|
||||||
libc.src.math.atanhf
|
libc.src.math.atanhf
|
||||||
libc.src.math.copysign
|
libc.src.math.copysign
|
||||||
libc.src.math.copysignf
|
libc.src.math.copysignf
|
||||||
|
|
|
@ -149,6 +149,7 @@ set(TARGET_LIBM_ENTRYPOINTS
|
||||||
libc.src.fenv.feupdateenv
|
libc.src.fenv.feupdateenv
|
||||||
|
|
||||||
# math.h entrypoints
|
# math.h entrypoints
|
||||||
|
libc.src.math.atanf
|
||||||
libc.src.math.atanhf
|
libc.src.math.atanhf
|
||||||
libc.src.math.copysign
|
libc.src.math.copysign
|
||||||
libc.src.math.copysignf
|
libc.src.math.copysignf
|
||||||
|
|
|
@ -149,7 +149,8 @@ set(TARGET_LIBM_ENTRYPOINTS
|
||||||
libc.src.fenv.feupdateenv
|
libc.src.fenv.feupdateenv
|
||||||
|
|
||||||
# math.h entrypoints
|
# math.h entrypoints
|
||||||
libc.src.math.atanhf
|
libc.src.math.atanf
|
||||||
|
libc.src.math.atanhf
|
||||||
libc.src.math.copysign
|
libc.src.math.copysign
|
||||||
libc.src.math.copysignf
|
libc.src.math.copysignf
|
||||||
libc.src.math.copysignl
|
libc.src.math.copysignl
|
||||||
|
|
|
@ -106,6 +106,7 @@ set(TARGET_LIBM_ENTRYPOINTS
|
||||||
libc.src.fenv.feupdateenv
|
libc.src.fenv.feupdateenv
|
||||||
|
|
||||||
# math.h entrypoints
|
# math.h entrypoints
|
||||||
|
libc.src.math.atanf
|
||||||
libc.src.math.atanhf
|
libc.src.math.atanhf
|
||||||
libc.src.math.copysign
|
libc.src.math.copysign
|
||||||
libc.src.math.copysignf
|
libc.src.math.copysignf
|
||||||
|
|
|
@ -480,7 +480,9 @@ def StdC : StandardSpec<"stdc"> {
|
||||||
FunctionSpec<"sinhf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
|
FunctionSpec<"sinhf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
|
||||||
FunctionSpec<"tanhf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
|
FunctionSpec<"tanhf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
|
||||||
|
|
||||||
FunctionSpec<"atanhf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
|
FunctionSpec<"atanf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
|
||||||
|
|
||||||
|
FunctionSpec<"atanhf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
|
||||||
]
|
]
|
||||||
>;
|
>;
|
||||||
|
|
||||||
|
|
|
@ -196,6 +196,15 @@ template <typename T> struct FPBits {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline static FPBits<T> create_value(bool sign, UIntType unbiased_exp,
|
||||||
|
UIntType mantissa) {
|
||||||
|
FPBits<T> result;
|
||||||
|
result.set_sign(sign);
|
||||||
|
result.set_unbiased_exponent(unbiased_exp);
|
||||||
|
result.set_mantissa(mantissa);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace fputil
|
} // namespace fputil
|
||||||
|
|
|
@ -184,6 +184,15 @@ template <> struct FPBits<long double> {
|
||||||
bits.set_mantissa(v);
|
bits.set_mantissa(v);
|
||||||
return bits;
|
return bits;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline static FPBits<long double>
|
||||||
|
create_value(bool sign, UIntType unbiased_exp, UIntType mantissa) {
|
||||||
|
FPBits<long double> result;
|
||||||
|
result.set_sign(sign);
|
||||||
|
result.set_unbiased_exponent(unbiased_exp);
|
||||||
|
result.set_mantissa(mantissa);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(
|
static_assert(
|
||||||
|
|
|
@ -66,6 +66,7 @@ add_entrypoint_object(
|
||||||
-O3
|
-O3
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_math_entrypoint_object(atanf)
|
||||||
add_math_entrypoint_object(atanhf)
|
add_math_entrypoint_object(atanhf)
|
||||||
|
|
||||||
add_math_entrypoint_object(ceil)
|
add_math_entrypoint_object(ceil)
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
//===-- Implementation header for atanf -------------------------*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef LLVM_LIBC_SRC_MATH_ATANF_H
|
||||||
|
#define LLVM_LIBC_SRC_MATH_ATANF_H
|
||||||
|
|
||||||
|
namespace __llvm_libc {
|
||||||
|
|
||||||
|
float atanf(float x);
|
||||||
|
|
||||||
|
} // namespace __llvm_libc
|
||||||
|
|
||||||
|
#endif // LLVM_LIBC_SRC_MATH_ATANF_H
|
|
@ -1242,3 +1242,28 @@ add_entrypoint_object(
|
||||||
-O3
|
-O3
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_object_library(
|
||||||
|
inv_trigf_utils
|
||||||
|
HDRS
|
||||||
|
inv_trigf_utils.h
|
||||||
|
SRCS
|
||||||
|
inv_trigf_utils.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_entrypoint_object(
|
||||||
|
atanf
|
||||||
|
SRCS
|
||||||
|
atanf.cpp
|
||||||
|
HDRS
|
||||||
|
../atanf.h
|
||||||
|
DEPENDS
|
||||||
|
.inv_trigf_utils
|
||||||
|
libc.src.__support.FPUtil.fputil
|
||||||
|
libc.src.__support.FPUtil.multiply_add
|
||||||
|
libc.src.__support.FPUtil.nearest_integer
|
||||||
|
libc.src.__support.FPUtil.polyeval
|
||||||
|
libc.include.math
|
||||||
|
COMPILE_OPTIONS
|
||||||
|
-O3
|
||||||
|
)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,57 @@
|
||||||
|
//===-- Single-precision atan function ------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "src/math/atanf.h"
|
||||||
|
#include "math_utils.h"
|
||||||
|
#include "src/__support/FPUtil/FPBits.h"
|
||||||
|
#include "src/math/generic/inv_trigf_utils.h"
|
||||||
|
|
||||||
|
namespace __llvm_libc {
|
||||||
|
|
||||||
|
LLVM_LIBC_FUNCTION(float, atanf, (float x)) {
|
||||||
|
using FPBits = typename fputil::FPBits<float>;
|
||||||
|
FPBits xbits(x);
|
||||||
|
bool sign = xbits.get_sign();
|
||||||
|
xbits.set_sign(false);
|
||||||
|
|
||||||
|
if (unlikely(xbits.is_inf_or_nan())) {
|
||||||
|
if (xbits.is_inf())
|
||||||
|
return opt_barrier(sign ? -M_MATH_PI_2 : M_MATH_PI_2);
|
||||||
|
else
|
||||||
|
return x + 1.0f;
|
||||||
|
}
|
||||||
|
// |x| == 0.06905200332403183
|
||||||
|
if (unlikely(xbits.uintval() == 0x3d8d6b23U)) {
|
||||||
|
if (fputil::get_round() == FE_TONEAREST) {
|
||||||
|
// 0.06894256919622421
|
||||||
|
FPBits br(0x3d8d31c3U);
|
||||||
|
br.set_sign(sign);
|
||||||
|
return br.get_val();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// |x| == 1.8670953512191772
|
||||||
|
if (unlikely(xbits.uintval() == 0x3feefcfbU)) {
|
||||||
|
int rounding_mode = fputil::get_round();
|
||||||
|
if (sign) {
|
||||||
|
if (rounding_mode == FE_DOWNWARD) {
|
||||||
|
// -1.0790828466415405
|
||||||
|
return FPBits(0xbf8a1f63U).get_val();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (rounding_mode == FE_UPWARD) {
|
||||||
|
// 1.0790828466415405
|
||||||
|
return FPBits(0x3f8a1f63U).get_val();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return atan_eval(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace __llvm_libc
|
|
@ -9,7 +9,6 @@
|
||||||
#ifndef LLVM_LIBC_SRC_MATH_GENERIC_EXPLOGXF_H
|
#ifndef LLVM_LIBC_SRC_MATH_GENERIC_EXPLOGXF_H
|
||||||
#define LLVM_LIBC_SRC_MATH_GENERIC_EXPLOGXF_H
|
#define LLVM_LIBC_SRC_MATH_GENERIC_EXPLOGXF_H
|
||||||
|
|
||||||
#include "common_constants.h" // Lookup tables EXP_M
|
|
||||||
#include "math_utils.h"
|
#include "math_utils.h"
|
||||||
#include "src/__support/FPUtil/FEnvImpl.h"
|
#include "src/__support/FPUtil/FEnvImpl.h"
|
||||||
#include "src/__support/FPUtil/FPBits.h"
|
#include "src/__support/FPUtil/FPBits.h"
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
//===-- Single-precision general exp/log functions ------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "inv_trigf_utils.h"
|
||||||
|
|
||||||
|
namespace __llvm_libc {
|
||||||
|
|
||||||
|
// N[Table[ArcTan[x], {x, 1/16, 16/16, 1/16}], 40]
|
||||||
|
alignas(64) const double ATAN_T[ATAN_T_SIZE] = {
|
||||||
|
0x1.ff55bb72cfdeap-5, 0x1.fd5ba9aac2f6ep-4, 0x1.7b97b4bce5b02p-3,
|
||||||
|
0x1.f5b75f92c80ddp-3, 0x1.362773707ebccp-2, 0x1.6f61941e4def1p-2,
|
||||||
|
0x1.a64eec3cc23fdp-2, 0x1.dac670561bb4fp-2, 0x1.0657e94db30d0p-1,
|
||||||
|
0x1.1e00babdefeb4p-1, 0x1.345f01cce37bbp-1, 0x1.4978fa3269ee1p-1,
|
||||||
|
0x1.5d58987169b18p-1, 0x1.700a7c5784634p-1, 0x1.819d0b7158a4dp-1,
|
||||||
|
0x1.921fb54442d18p-1};
|
||||||
|
|
||||||
|
// for(int i = 0; i < 5; i++)
|
||||||
|
// printf("%.13a,\n", (-2 * (i % 2) + 1) * 1.0 / (2 * i + 1));
|
||||||
|
alignas(64) const double ATAN_K[5] = {
|
||||||
|
0x1.0000000000000p+0, -0x1.5555555555555p-2, 0x1.999999999999ap-3,
|
||||||
|
-0x1.2492492492492p-3, 0x1.c71c71c71c71cp-4};
|
||||||
|
|
||||||
|
} // namespace __llvm_libc
|
|
@ -0,0 +1,94 @@
|
||||||
|
//===-- Single-precision general inverse trigonometric functions ----------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#ifndef LLVM_LIBC_SRC_MATH_GENERIC_INV_TRIGF_UTILS_H
|
||||||
|
#define LLVM_LIBC_SRC_MATH_GENERIC_INV_TRIGF_UTILS_H
|
||||||
|
|
||||||
|
#include "math_utils.h"
|
||||||
|
#include "src/__support/FPUtil/FEnvImpl.h"
|
||||||
|
#include "src/__support/FPUtil/FPBits.h"
|
||||||
|
#include "src/__support/FPUtil/PolyEval.h"
|
||||||
|
#include "src/__support/FPUtil/nearest_integer.h"
|
||||||
|
#include "src/__support/common.h"
|
||||||
|
#include <src/__support/FPUtil/NearestIntegerOperations.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
namespace __llvm_libc {
|
||||||
|
|
||||||
|
// PI / 2
|
||||||
|
constexpr double M_MATH_PI_2 = 0x1.921fb54442d18p+0;
|
||||||
|
|
||||||
|
// atan table size
|
||||||
|
constexpr int ATAN_T_BITS = 4;
|
||||||
|
constexpr int ATAN_T_SIZE = 1 << ATAN_T_BITS;
|
||||||
|
|
||||||
|
// N[Table[ArcTan[x], {x, 1/8, 8/8, 1/8}], 40]
|
||||||
|
extern const double ATAN_T[ATAN_T_SIZE];
|
||||||
|
extern const double ATAN_K[5];
|
||||||
|
|
||||||
|
// The main idea of the function is to use formula
|
||||||
|
// atan(u) + atan(v) = atan((u+v)/(1-uv))
|
||||||
|
|
||||||
|
// x should be positive, normal finite value
|
||||||
|
inline static double atan_eval(double x) {
|
||||||
|
using FPB = fputil::FPBits<double>;
|
||||||
|
// Added some small value to umin and umax mantissa to avoid possible rounding
|
||||||
|
// errors.
|
||||||
|
FPB::UIntType umin =
|
||||||
|
FPB::create_value(false, FPB::EXPONENT_BIAS - ATAN_T_BITS - 1,
|
||||||
|
0x100000000000UL)
|
||||||
|
.uintval();
|
||||||
|
FPB::UIntType umax =
|
||||||
|
FPB::create_value(false, FPB::EXPONENT_BIAS + ATAN_T_BITS,
|
||||||
|
0xF000000000000UL)
|
||||||
|
.uintval();
|
||||||
|
|
||||||
|
FPB bs(x);
|
||||||
|
bool sign = bs.get_sign();
|
||||||
|
auto x_abs = bs.uintval() & FPB::FloatProp::EXP_MANT_MASK;
|
||||||
|
|
||||||
|
if (x_abs <= umin) {
|
||||||
|
double pe = __llvm_libc::fputil::polyeval(x * x, 0.0, ATAN_K[1], ATAN_K[2],
|
||||||
|
ATAN_K[3], ATAN_K[4]);
|
||||||
|
return fputil::multiply_add(pe, x, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (x_abs >= umax) {
|
||||||
|
double one_over_x_m = -1.0 / x;
|
||||||
|
double one_over_x2 = one_over_x_m * one_over_x_m;
|
||||||
|
double pe = __llvm_libc::fputil::polyeval(one_over_x2, ATAN_K[0], ATAN_K[1],
|
||||||
|
ATAN_K[2], ATAN_K[3]);
|
||||||
|
return fputil::multiply_add(pe, one_over_x_m, sign ? (-M_MATH_PI_2) : (M_MATH_PI_2));
|
||||||
|
}
|
||||||
|
|
||||||
|
double pos_x = FPB(x_abs).get_val();
|
||||||
|
bool one_over_x = pos_x > 1.0;
|
||||||
|
if (one_over_x) {
|
||||||
|
pos_x = 1.0 / pos_x;
|
||||||
|
}
|
||||||
|
|
||||||
|
double near_x = fputil::nearest_integer(pos_x * ATAN_T_SIZE);
|
||||||
|
int val = static_cast<int>(near_x);
|
||||||
|
near_x *= 1.0 / ATAN_T_SIZE;
|
||||||
|
|
||||||
|
double v = (pos_x - near_x) / fputil::multiply_add(near_x, pos_x, 1.0);
|
||||||
|
double v2 = v * v;
|
||||||
|
double pe = __llvm_libc::fputil::polyeval(v2, ATAN_K[0], ATAN_K[1], ATAN_K[2],
|
||||||
|
ATAN_K[3], ATAN_K[4]);
|
||||||
|
double result;
|
||||||
|
if (one_over_x)
|
||||||
|
result = M_PI_2 - fputil::multiply_add(pe, v, ATAN_T[val - 1]);
|
||||||
|
else
|
||||||
|
result = fputil::multiply_add(pe, v, ATAN_T[val - 1]);
|
||||||
|
return sign ? -result : result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace __llvm_libc
|
||||||
|
|
||||||
|
#endif // LLVM_LIBC_SRC_MATH_GENERIC_INV_TRIGF_UTILS_H
|
|
@ -1388,6 +1388,32 @@ add_fp_unittest(
|
||||||
libc.src.__support.FPUtil.fputil
|
libc.src.__support.FPUtil.fputil
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_fp_unittest(
|
||||||
|
atanf_test
|
||||||
|
NEED_MPFR
|
||||||
|
SUITE
|
||||||
|
libc_math_unittests
|
||||||
|
SRCS
|
||||||
|
atanf_test.cpp
|
||||||
|
DEPENDS
|
||||||
|
libc.src.math.atanf
|
||||||
|
libc.src.__support.FPUtil.fputil
|
||||||
|
)
|
||||||
|
|
||||||
|
add_fp_unittest(
|
||||||
|
inv_trigf_utils_test
|
||||||
|
NEED_MPFR
|
||||||
|
SUITE
|
||||||
|
libc_math_unittests
|
||||||
|
HDRS
|
||||||
|
in_float_range_test_helper.h
|
||||||
|
SRCS
|
||||||
|
inv_trigf_utils_test.cpp
|
||||||
|
DEPENDS
|
||||||
|
libc.src.math.generic.inv_trigf_utils
|
||||||
|
libc.src.__support.FPUtil.fputil
|
||||||
|
)
|
||||||
|
|
||||||
add_subdirectory(generic)
|
add_subdirectory(generic)
|
||||||
add_subdirectory(exhaustive)
|
add_subdirectory(exhaustive)
|
||||||
add_subdirectory(differential_testing)
|
add_subdirectory(differential_testing)
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
//===-- Unittests for atanf -----------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "src/__support/FPUtil/FPBits.h"
|
||||||
|
#include "src/math/atanf.h"
|
||||||
|
#include "utils/MPFRWrapper/MPFRUtils.h"
|
||||||
|
#include "utils/UnitTest/FPMatcher.h"
|
||||||
|
#include "utils/UnitTest/Test.h"
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <initializer_list>
|
||||||
|
|
||||||
|
using FPBits = __llvm_libc::fputil::FPBits<float>;
|
||||||
|
|
||||||
|
namespace mpfr = __llvm_libc::testing::mpfr;
|
||||||
|
|
||||||
|
DECLARE_SPECIAL_CONSTANTS(float)
|
||||||
|
|
||||||
|
TEST(LlvmLibcAtanfTest, SpecialNumbers) {
|
||||||
|
errno = 0;
|
||||||
|
__llvm_libc::fputil::clear_except(FE_ALL_EXCEPT);
|
||||||
|
EXPECT_FP_EQ(aNaN, __llvm_libc::atanf(aNaN));
|
||||||
|
EXPECT_FP_EXCEPTION(FE_INVALID);
|
||||||
|
EXPECT_MATH_ERRNO(0);
|
||||||
|
|
||||||
|
__llvm_libc::fputil::clear_except(FE_ALL_EXCEPT);
|
||||||
|
EXPECT_FP_EQ(0.0f, __llvm_libc::atanf(0.0f));
|
||||||
|
EXPECT_FP_EXCEPTION(0);
|
||||||
|
EXPECT_MATH_ERRNO(0);
|
||||||
|
|
||||||
|
__llvm_libc::fputil::clear_except(FE_ALL_EXCEPT);
|
||||||
|
EXPECT_FP_EQ(-0.0f, __llvm_libc::atanf(-0.0f));
|
||||||
|
EXPECT_FP_EXCEPTION(0);
|
||||||
|
EXPECT_MATH_ERRNO(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(LlvmLibcAtanfTest, InFloatRange) {
|
||||||
|
constexpr uint32_t COUNT = 1000000;
|
||||||
|
const uint32_t STEP = FPBits(inf).uintval() / COUNT;
|
||||||
|
for (uint32_t i = 0, v = 0; i <= COUNT; ++i, v += STEP) {
|
||||||
|
float x = float(FPBits(v));
|
||||||
|
EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Atan, x,
|
||||||
|
__llvm_libc::atanf(x), 0.5);
|
||||||
|
EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Atan, -x,
|
||||||
|
__llvm_libc::atanf(-x), 0.5);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// For small values, tanh(x) is x.
|
||||||
|
TEST(LlvmLibcAtanfTest, SpecialValues) {
|
||||||
|
for (uint32_t v : {0x3d8d6b23U, 0x3feefcfbU, 0xbd8d6b23U, 0xbfeefcfbU,
|
||||||
|
0x7F800000U, 0xFF800000U}) {
|
||||||
|
float x = float(FPBits(v));
|
||||||
|
EXPECT_MPFR_MATCH_ALL_ROUNDING(mpfr::Operation::Atan, x,
|
||||||
|
__llvm_libc::atanf(x), 0.5);
|
||||||
|
}
|
||||||
|
}
|
|
@ -307,3 +307,21 @@ add_fp_unittest(
|
||||||
LINK_LIBRARIES
|
LINK_LIBRARIES
|
||||||
-lpthread
|
-lpthread
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_fp_unittest(
|
||||||
|
atanf_test
|
||||||
|
NO_RUN_POSTBUILD
|
||||||
|
NEED_MPFR
|
||||||
|
SUITE
|
||||||
|
libc_math_exhaustive_tests
|
||||||
|
SRCS
|
||||||
|
atanf_test.cpp
|
||||||
|
DEPENDS
|
||||||
|
.exhaustive_test
|
||||||
|
libc.include.math
|
||||||
|
libc.src.math.atanf
|
||||||
|
libc.src.__support.FPUtil.fputil
|
||||||
|
LINK_LIBRARIES
|
||||||
|
-lpthread
|
||||||
|
)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
//===-- Exhaustive test for atanf -----------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "exhaustive_test.h"
|
||||||
|
#include "src/__support/FPUtil/FPBits.h"
|
||||||
|
#include "src/math/atanf.h"
|
||||||
|
#include "utils/MPFRWrapper/MPFRUtils.h"
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
using FPBits = __llvm_libc::fputil::FPBits<float>;
|
||||||
|
|
||||||
|
namespace mpfr = __llvm_libc::testing::mpfr;
|
||||||
|
|
||||||
|
struct LlvmLibcAtanfExhaustiveTest : public LlvmLibcExhaustiveTest<uint32_t> {
|
||||||
|
bool check(uint32_t start, uint32_t stop,
|
||||||
|
mpfr::RoundingMode rounding) override {
|
||||||
|
mpfr::ForceRoundingMode r(rounding);
|
||||||
|
uint32_t bits = start;
|
||||||
|
bool result = true;
|
||||||
|
do {
|
||||||
|
FPBits xbits(bits);
|
||||||
|
float x = float(xbits);
|
||||||
|
result &= EXPECT_MPFR_MATCH(mpfr::Operation::Atan, x,
|
||||||
|
__llvm_libc::atanf(x), 0.5, rounding);
|
||||||
|
} while (bits++ < stop);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const int NUM_THREADS = std::thread::hardware_concurrency();
|
||||||
|
|
||||||
|
// Range: [0, 1.0];
|
||||||
|
static const uint32_t POS_START = 0x0000'0000U;
|
||||||
|
static const uint32_t POS_STOP = FPBits::inf().uintval();
|
||||||
|
|
||||||
|
TEST_F(LlvmLibcAtanfExhaustiveTest, PostiveRangeRoundNearestTieToEven) {
|
||||||
|
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::Nearest);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LlvmLibcAtanfExhaustiveTest, PostiveRangeRoundUp) {
|
||||||
|
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::Upward);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LlvmLibcAtanfExhaustiveTest, PostiveRangeRoundDown) {
|
||||||
|
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::Downward);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LlvmLibcAtanfExhaustiveTest, PostiveRangeRoundTowardZero) {
|
||||||
|
test_full_range(POS_START, POS_STOP, mpfr::RoundingMode::TowardZero);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Range: [-1.0, 0];
|
||||||
|
static const uint32_t NEG_START = 0x8000'0000U;
|
||||||
|
static const uint32_t NEG_STOP = FPBits::neg_inf().uintval();
|
||||||
|
|
||||||
|
TEST_F(LlvmLibcAtanfExhaustiveTest, NegativeRangeRoundNearestTieToEven) {
|
||||||
|
test_full_range(NEG_START, NEG_STOP, mpfr::RoundingMode::Nearest);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LlvmLibcAtanfExhaustiveTest, NegativeRangeRoundUp) {
|
||||||
|
test_full_range(NEG_START, NEG_STOP, mpfr::RoundingMode::Upward);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LlvmLibcAtanfExhaustiveTest, NegativeRangeRoundDown) {
|
||||||
|
test_full_range(NEG_START, NEG_STOP, mpfr::RoundingMode::Downward);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(LlvmLibcAtanfExhaustiveTest, NegativeRangeRoundTowardZero) {
|
||||||
|
test_full_range(NEG_START, NEG_STOP, mpfr::RoundingMode::TowardZero);
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
//===-- Unittests for explogxf --------------------------------------------===//
|
//===-- Unittests for supfuncf --------------------------------------------===//
|
||||||
//
|
//
|
||||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
// See https://llvm.org/LICENSE.txt for license information.
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
//===-- Unittests for supfuncf --------------------------------------------===//
|
||||||
|
//
|
||||||
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||||
|
// See https://llvm.org/LICENSE.txt for license information.
|
||||||
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||||
|
//
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "in_float_range_test_helper.h"
|
||||||
|
#include "src/__support/FPUtil/FPBits.h"
|
||||||
|
#include "src/math/generic/inv_trigf_utils.h"
|
||||||
|
#include "utils/MPFRWrapper/MPFRUtils.h"
|
||||||
|
#include "utils/UnitTest/FPMatcher.h"
|
||||||
|
#include "utils/UnitTest/Test.h"
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
namespace mpfr = __llvm_libc::testing::mpfr;
|
||||||
|
|
||||||
|
DECLARE_SPECIAL_CONSTANTS(float)
|
||||||
|
|
||||||
|
constexpr int def_count = 100003;
|
||||||
|
constexpr float def_prec = 0.500001f;
|
||||||
|
|
||||||
|
TEST(LlvmLibcAtanfPosTest, InFloatRange) {
|
||||||
|
CHECK_DATA(0.0f, inf, mpfr::Operation::Atan, __llvm_libc::atan_eval, isfinite,
|
||||||
|
def_count, def_prec);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(LlvmLibcAtanfNegTest, InFloatRange) {
|
||||||
|
CHECK_DATA(-0.0f, neg_inf, mpfr::Operation::Atan, __llvm_libc::atan_eval,
|
||||||
|
isfinite, def_count, def_prec);
|
||||||
|
}
|
|
@ -182,6 +182,12 @@ public:
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MPFRNumber atan() const {
|
||||||
|
MPFRNumber result(*this);
|
||||||
|
mpfr_atan(result.value, value, mpfr_rounding);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
MPFRNumber atanh() const {
|
MPFRNumber atanh() const {
|
||||||
MPFRNumber result(*this);
|
MPFRNumber result(*this);
|
||||||
mpfr_atanh(result.value, value, mpfr_rounding);
|
mpfr_atanh(result.value, value, mpfr_rounding);
|
||||||
|
@ -506,6 +512,8 @@ unary_operation(Operation op, InputType input, unsigned int precision,
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case Operation::Abs:
|
case Operation::Abs:
|
||||||
return mpfrInput.abs();
|
return mpfrInput.abs();
|
||||||
|
case Operation::Atan:
|
||||||
|
return mpfrInput.atan();
|
||||||
case Operation::Atanh:
|
case Operation::Atanh:
|
||||||
return mpfrInput.atanh();
|
return mpfrInput.atanh();
|
||||||
case Operation::Ceil:
|
case Operation::Ceil:
|
||||||
|
|
|
@ -25,6 +25,7 @@ enum class Operation : int {
|
||||||
// and output floating point numbers are of the same kind.
|
// and output floating point numbers are of the same kind.
|
||||||
BeginUnaryOperationsSingleOutput,
|
BeginUnaryOperationsSingleOutput,
|
||||||
Abs,
|
Abs,
|
||||||
|
Atan,
|
||||||
Atanh,
|
Atanh,
|
||||||
Ceil,
|
Ceil,
|
||||||
Cos,
|
Cos,
|
||||||
|
|
Loading…
Reference in New Issue