diff --git a/libc/config/linux/aarch64/entrypoints.txt b/libc/config/linux/aarch64/entrypoints.txt --- a/libc/config/linux/aarch64/entrypoints.txt +++ b/libc/config/linux/aarch64/entrypoints.txt @@ -8,6 +8,8 @@ set(TARGET_LIBM_ENTRYPOINTS # math.h entrypoints + libc.src.math.copysign + libc.src.math.copysignf libc.src.math.ceil libc.src.math.ceilf libc.src.math.cosf @@ -17,6 +19,12 @@ libc.src.math.fabsf libc.src.math.floor libc.src.math.floorf + libc.src.math.frexp + libc.src.math.frexpf + libc.src.math.logb + libc.src.math.logbf + libc.src.math.modf + libc.src.math.modff libc.src.math.round libc.src.math.roundf libc.src.math.sincosf diff --git a/libc/config/linux/api.td b/libc/config/linux/api.td --- a/libc/config/linux/api.td +++ b/libc/config/linux/api.td @@ -150,6 +150,8 @@ FloatT, ]; let Functions = [ + "copysign", + "copysignf", "ceil", "ceilf", "cosf", @@ -157,6 +159,12 @@ "fabsf", "floor", "floorf", + "frexp", + "frexpf", + "logb", + "logbf", + "modf", + "modff", "expf", "exp2f", "round", diff --git a/libc/config/linux/x86_64/entrypoints.txt b/libc/config/linux/x86_64/entrypoints.txt --- a/libc/config/linux/x86_64/entrypoints.txt +++ b/libc/config/linux/x86_64/entrypoints.txt @@ -45,6 +45,8 @@ set(TARGET_LIBM_ENTRYPOINTS # math.h entrypoints + libc.src.math.copysign + libc.src.math.copysignf libc.src.math.ceil libc.src.math.ceilf libc.src.math.cosf @@ -54,6 +56,12 @@ libc.src.math.fabsf libc.src.math.floor libc.src.math.floorf + libc.src.math.frexp + libc.src.math.frexpf + libc.src.math.logb + libc.src.math.logbf + libc.src.math.modf + libc.src.math.modff libc.src.math.round libc.src.math.roundf libc.src.math.sincosf diff --git a/libc/spec/stdc.td b/libc/spec/stdc.td --- a/libc/spec/stdc.td +++ b/libc/spec/stdc.td @@ -20,6 +20,8 @@ PtrType ThrdTTypePtr = PtrType; PtrType IntPtr = PtrType; + PtrType FloatPtr = PtrType; + PtrType DoublePtr = PtrType; NamedType SigHandlerT = NamedType<"__sighandler_t">; @@ -187,6 +189,9 @@ ], [], // Enumerations [ + FunctionSpec<"copysign", RetValSpec, [ArgSpec, ArgSpec]>, + FunctionSpec<"copysignf", RetValSpec, [ArgSpec, ArgSpec]>, + FunctionSpec<"ceil", RetValSpec, [ArgSpec]>, FunctionSpec<"ceilf", RetValSpec, [ArgSpec]>, @@ -196,6 +201,15 @@ FunctionSpec<"floor", RetValSpec, [ArgSpec]>, FunctionSpec<"floorf", RetValSpec, [ArgSpec]>, + FunctionSpec<"frexp", RetValSpec, [ArgSpec, ArgSpec]>, + FunctionSpec<"frexpf", RetValSpec, [ArgSpec, ArgSpec]>, + + FunctionSpec<"logb", RetValSpec, [ArgSpec]>, + FunctionSpec<"logbf", RetValSpec, [ArgSpec]>, + + FunctionSpec<"modf", RetValSpec, [ArgSpec, ArgSpec]>, + FunctionSpec<"modff", RetValSpec, [ArgSpec, ArgSpec]>, + FunctionSpec<"cosf", RetValSpec, [ArgSpec]>, FunctionSpec<"sinf", RetValSpec, [ArgSpec]>, diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt --- a/libc/src/math/CMakeLists.txt +++ b/libc/src/math/CMakeLists.txt @@ -189,3 +189,83 @@ .math_utils libc.include.math ) + +add_entrypoint_object( + copysign + SRCS + copysign.cpp + HDRS + copysign.h + DEPENDS + libc.utils.FPUtil.fputil +) + +add_entrypoint_object( + copysignf + SRCS + copysignf.cpp + HDRS + copysignf.h + DEPENDS + libc.utils.FPUtil.fputil +) + +add_entrypoint_object( + frexp + SRCS + frexp.cpp + HDRS + frexp.h + DEPENDS + libc.utils.FPUtil.fputil +) + +add_entrypoint_object( + frexpf + SRCS + frexpf.cpp + HDRS + frexpf.h + DEPENDS + libc.utils.FPUtil.fputil +) + +add_entrypoint_object( + logb + SRCS + logb.cpp + HDRS + logb.h + DEPENDS + libc.utils.FPUtil.fputil +) + +add_entrypoint_object( + logbf + SRCS + logbf.cpp + HDRS + logbf.h + DEPENDS + libc.utils.FPUtil.fputil +) + +add_entrypoint_object( + modf + SRCS + modf.cpp + HDRS + modf.h + DEPENDS + libc.utils.FPUtil.fputil +) + +add_entrypoint_object( + modff + SRCS + modff.cpp + HDRS + modff.h + DEPENDS + libc.utils.FPUtil.fputil +) diff --git a/libc/src/math/copysign.h b/libc/src/math/copysign.h new file mode 100644 --- /dev/null +++ b/libc/src/math/copysign.h @@ -0,0 +1,18 @@ +//===-- Implementation header for copysign ----------------------*- 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_COPYSIGN_H +#define LLVM_LIBC_SRC_MATH_COPYSIGN_H + +namespace __llvm_libc { + +double copysign(double x, double y); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_MATH_COPYSIGN_H diff --git a/libc/src/math/copysign.cpp b/libc/src/math/copysign.cpp new file mode 100644 --- /dev/null +++ b/libc/src/math/copysign.cpp @@ -0,0 +1,18 @@ +//===-- Implementation of copysign 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/__support/common.h" +#include "utils/FPUtil/ManipulationFunctions.h" + +namespace __llvm_libc { + +double LLVM_LIBC_ENTRYPOINT(copysign)(double x, double y) { + return fputil::copysign(x, y); +} + +} // namespace __llvm_libc diff --git a/libc/src/math/copysignf.h b/libc/src/math/copysignf.h new file mode 100644 --- /dev/null +++ b/libc/src/math/copysignf.h @@ -0,0 +1,18 @@ +//===-- Implementation header for copysignf ---------------------*- 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_COPYSIGNF_H +#define LLVM_LIBC_SRC_MATH_COPYSIGNF_H + +namespace __llvm_libc { + +float copysignf(float x, float y); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_MATH_COPYSIGNF_H diff --git a/libc/src/math/copysignf.cpp b/libc/src/math/copysignf.cpp new file mode 100644 --- /dev/null +++ b/libc/src/math/copysignf.cpp @@ -0,0 +1,18 @@ +//===-- Implementation of copysignf 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/__support/common.h" +#include "utils/FPUtil/ManipulationFunctions.h" + +namespace __llvm_libc { + +float LLVM_LIBC_ENTRYPOINT(copysignf)(float x, float y) { + return fputil::copysign(x, y); +} + +} // namespace __llvm_libc diff --git a/libc/src/math/frexp.h b/libc/src/math/frexp.h new file mode 100644 --- /dev/null +++ b/libc/src/math/frexp.h @@ -0,0 +1,18 @@ +//===-- Implementation header for frexp -------------------------*- 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_FREXP_H +#define LLVM_LIBC_SRC_MATH_FREXP_H + +namespace __llvm_libc { + +double frexp(double x, int *exp); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_MATH_FREXP_H diff --git a/libc/src/math/frexp.cpp b/libc/src/math/frexp.cpp new file mode 100644 --- /dev/null +++ b/libc/src/math/frexp.cpp @@ -0,0 +1,18 @@ +//===-- Implementation of frexp 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/__support/common.h" +#include "utils/FPUtil/ManipulationFunctions.h" + +namespace __llvm_libc { + +double LLVM_LIBC_ENTRYPOINT(frexp)(double x, int *exp) { + return fputil::frexp(x, *exp); +} + +} // namespace __llvm_libc diff --git a/libc/src/math/frexpf.h b/libc/src/math/frexpf.h new file mode 100644 --- /dev/null +++ b/libc/src/math/frexpf.h @@ -0,0 +1,18 @@ +//===-- Implementation header for frexpf ------------------------*- 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_FREXPF_H +#define LLVM_LIBC_SRC_MATH_FREXPF_H + +namespace __llvm_libc { + +float frexpf(float x, int *exp); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_MATH_FREXPF_H diff --git a/libc/src/math/frexpf.cpp b/libc/src/math/frexpf.cpp new file mode 100644 --- /dev/null +++ b/libc/src/math/frexpf.cpp @@ -0,0 +1,18 @@ +//===-- Implementation of frexpf 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/__support/common.h" +#include "utils/FPUtil/ManipulationFunctions.h" + +namespace __llvm_libc { + +float LLVM_LIBC_ENTRYPOINT(frexpf)(float x, int *exp) { + return fputil::frexp(x, *exp); +} + +} // namespace __llvm_libc diff --git a/libc/src/math/logb.h b/libc/src/math/logb.h new file mode 100644 --- /dev/null +++ b/libc/src/math/logb.h @@ -0,0 +1,18 @@ +//===-- Implementation header for logb --------------------------*- 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_LOGB_H +#define LLVM_LIBC_SRC_MATH_LOGB_H + +namespace __llvm_libc { + +double logb(double x); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_MATH_LOGB_H diff --git a/libc/src/math/logb.cpp b/libc/src/math/logb.cpp new file mode 100644 --- /dev/null +++ b/libc/src/math/logb.cpp @@ -0,0 +1,16 @@ +//===-- Implementation of logb 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/__support/common.h" +#include "utils/FPUtil/ManipulationFunctions.h" + +namespace __llvm_libc { + +double LLVM_LIBC_ENTRYPOINT(logb)(double x) { return fputil::logb(x); } + +} // namespace __llvm_libc diff --git a/libc/src/math/logbf.h b/libc/src/math/logbf.h new file mode 100644 --- /dev/null +++ b/libc/src/math/logbf.h @@ -0,0 +1,18 @@ +//===-- Implementation header for logbf -------------------------*- 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_LOGBF_H +#define LLVM_LIBC_SRC_MATH_LOGBF_H + +namespace __llvm_libc { + +float logbf(float x); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_MATH_LOGBF_H diff --git a/libc/src/math/logbf.cpp b/libc/src/math/logbf.cpp new file mode 100644 --- /dev/null +++ b/libc/src/math/logbf.cpp @@ -0,0 +1,16 @@ +//===-- Implementation of logbf 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/__support/common.h" +#include "utils/FPUtil/ManipulationFunctions.h" + +namespace __llvm_libc { + +float LLVM_LIBC_ENTRYPOINT(logbf)(float x) { return fputil::logb(x); } + +} // namespace __llvm_libc diff --git a/libc/src/math/modf.h b/libc/src/math/modf.h new file mode 100644 --- /dev/null +++ b/libc/src/math/modf.h @@ -0,0 +1,18 @@ +//===-- Implementation header for modf --------------------------*- 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_MODF_H +#define LLVM_LIBC_SRC_MATH_MODF_H + +namespace __llvm_libc { + +double modf(double x, double *iptr); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_MATH_MODF_H diff --git a/libc/src/math/modf.cpp b/libc/src/math/modf.cpp new file mode 100644 --- /dev/null +++ b/libc/src/math/modf.cpp @@ -0,0 +1,18 @@ +//===-- Implementation of modf 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/__support/common.h" +#include "utils/FPUtil/ManipulationFunctions.h" + +namespace __llvm_libc { + +double LLVM_LIBC_ENTRYPOINT(modf)(double x, double *iptr) { + return fputil::modf(x, *iptr); +} + +} // namespace __llvm_libc diff --git a/libc/src/math/modff.h b/libc/src/math/modff.h new file mode 100644 --- /dev/null +++ b/libc/src/math/modff.h @@ -0,0 +1,18 @@ +//===-- Implementation header for modff -------------------------*- 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_MODFF_H +#define LLVM_LIBC_SRC_MATH_MODFF_H + +namespace __llvm_libc { + +float modff(float x, float *iptr); + +} // namespace __llvm_libc + +#endif // LLVM_LIBC_SRC_MATH_MODFF_H diff --git a/libc/src/math/modff.cpp b/libc/src/math/modff.cpp new file mode 100644 --- /dev/null +++ b/libc/src/math/modff.cpp @@ -0,0 +1,18 @@ +//===-- Implementation of modf 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/__support/common.h" +#include "utils/FPUtil/ManipulationFunctions.h" + +namespace __llvm_libc { + +float LLVM_LIBC_ENTRYPOINT(modff)(float x, float *iptr) { + return fputil::modf(x, *iptr); +} + +} // namespace __llvm_libc diff --git a/libc/test/src/math/CMakeLists.txt b/libc/test/src/math/CMakeLists.txt --- a/libc/test/src/math/CMakeLists.txt +++ b/libc/test/src/math/CMakeLists.txt @@ -228,3 +228,99 @@ libc.src.math.exp2f libc.utils.FPUtil.fputil ) + +add_math_unittest( + copysign_test + SUITE + libc_math_unittests + SRCS + copysign_test.cpp + DEPENDS + libc.include.math + libc.src.math.copysign + libc.utils.FPUtil.fputil +) + +add_math_unittest( + copysignf_test + SUITE + libc_math_unittests + SRCS + copysignf_test.cpp + DEPENDS + libc.include.math + libc.src.math.copysignf + libc.utils.FPUtil.fputil +) + +add_math_unittest( + frexp_test + SUITE + libc_math_unittests + SRCS + frexp_test.cpp + DEPENDS + libc.include.math + libc.src.math.frexp + libc.utils.FPUtil.fputil +) + +add_math_unittest( + frexpf_test + SUITE + libc_math_unittests + SRCS + frexpf_test.cpp + DEPENDS + libc.include.math + libc.src.math.frexpf + libc.utils.FPUtil.fputil +) + +add_math_unittest( + logb_test + SUITE + libc_math_unittests + SRCS + logb_test.cpp + DEPENDS + libc.include.math + libc.src.math.logb + libc.utils.FPUtil.fputil +) + +add_math_unittest( + logbf_test + SUITE + libc_math_unittests + SRCS + logbf_test.cpp + DEPENDS + libc.include.math + libc.src.math.logbf + libc.utils.FPUtil.fputil +) + +add_math_unittest( + modf_test + SUITE + libc_math_unittests + SRCS + modf_test.cpp + DEPENDS + libc.include.math + libc.src.math.modf + libc.utils.FPUtil.fputil +) + +add_math_unittest( + modff_test + SUITE + libc_math_unittests + SRCS + modff_test.cpp + DEPENDS + libc.include.math + libc.src.math.modff + libc.utils.FPUtil.fputil +) diff --git a/libc/test/src/math/copysign_test.cpp b/libc/test/src/math/copysign_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/math/copysign_test.cpp @@ -0,0 +1,63 @@ +//===-- Unittests for copysign --------------------------------------------===// +// +// 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 "include/math.h" +#include "src/math/copysign.h" +#include "utils/FPUtil/BitPatterns.h" +#include "utils/FPUtil/FloatOperations.h" +#include "utils/FPUtil/FloatProperties.h" +#include "utils/UnitTest/Test.h" + +using __llvm_libc::fputil::valueAsBits; +using __llvm_libc::fputil::valueFromBits; + +using BitPatterns = __llvm_libc::fputil::BitPatterns; +using Properties = __llvm_libc::fputil::FloatProperties; + +TEST(CopySignTest, SpecialNumbers) { + EXPECT_EQ(BitPatterns::aNegativeQuietNaN, + valueAsBits(__llvm_libc::copysign( + valueFromBits(BitPatterns::aQuietNaN), -1.0))); + EXPECT_EQ(BitPatterns::aQuietNaN, + valueAsBits(__llvm_libc::copysign( + valueFromBits(BitPatterns::aNegativeQuietNaN), 1.0))); + + EXPECT_EQ(BitPatterns::aNegativeSignallingNaN, + valueAsBits(__llvm_libc::copysign( + valueFromBits(BitPatterns::aSignallingNaN), -1.0))); + EXPECT_EQ(BitPatterns::aSignallingNaN, + valueAsBits(__llvm_libc::copysign( + valueFromBits(BitPatterns::aNegativeSignallingNaN), 1.0))); + + EXPECT_EQ(BitPatterns::negInf, valueAsBits(__llvm_libc::copysign( + valueFromBits(BitPatterns::inf), -1.0))); + EXPECT_EQ(BitPatterns::inf, valueAsBits(__llvm_libc::copysign( + valueFromBits(BitPatterns::negInf), 1.0))); + + EXPECT_EQ(BitPatterns::negZero, valueAsBits(__llvm_libc::copysign( + valueFromBits(BitPatterns::zero), -1.0))); + EXPECT_EQ(BitPatterns::zero, valueAsBits(__llvm_libc::copysign( + valueFromBits(BitPatterns::negZero), 1.0))); +} + +TEST(CopySignTest, InDoubleRange) { + using BitsType = Properties::BitsType; + constexpr BitsType count = 1000000; + constexpr BitsType step = UINT64_MAX / count; + for (BitsType i = 0, v = 0; i <= count; ++i, v += step) { + double x = valueFromBits(v); + if (isnan(x) || isinf(x) || x == 0) + continue; + + double res1 = __llvm_libc::copysign(x, -x); + ASSERT_TRUE(res1 == -x); + + double res2 = __llvm_libc::copysign(x, x); + ASSERT_TRUE(res2 == x); + } +} diff --git a/libc/test/src/math/copysignf_test.cpp b/libc/test/src/math/copysignf_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/math/copysignf_test.cpp @@ -0,0 +1,65 @@ +//===-- Unittests for copysignf +//--------------------------------------------===// +// +// 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 "include/math.h" +#include "src/math/copysignf.h" +#include "utils/FPUtil/BitPatterns.h" +#include "utils/FPUtil/FloatOperations.h" +#include "utils/FPUtil/FloatProperties.h" +#include "utils/UnitTest/Test.h" + +using __llvm_libc::fputil::valueAsBits; +using __llvm_libc::fputil::valueFromBits; + +using BitPatterns = __llvm_libc::fputil::BitPatterns; +using Properties = __llvm_libc::fputil::FloatProperties; + +TEST(CopySignFTest, SpecialNumbers) { + EXPECT_EQ(BitPatterns::aNegativeQuietNaN, + valueAsBits(__llvm_libc::copysignf( + valueFromBits(BitPatterns::aQuietNaN), -1.0f))); + EXPECT_EQ(BitPatterns::aQuietNaN, + valueAsBits(__llvm_libc::copysignf( + valueFromBits(BitPatterns::aNegativeQuietNaN), 1.0f))); + + EXPECT_EQ(BitPatterns::aNegativeSignallingNaN, + valueAsBits(__llvm_libc::copysignf( + valueFromBits(BitPatterns::aSignallingNaN), -1.0f))); + EXPECT_EQ(BitPatterns::aSignallingNaN, + valueAsBits(__llvm_libc::copysignf( + valueFromBits(BitPatterns::aNegativeSignallingNaN), 1.0f))); + + EXPECT_EQ(BitPatterns::negInf, valueAsBits(__llvm_libc::copysignf( + valueFromBits(BitPatterns::inf), -1.0f))); + EXPECT_EQ(BitPatterns::inf, valueAsBits(__llvm_libc::copysignf( + valueFromBits(BitPatterns::negInf), 1.0f))); + + EXPECT_EQ(BitPatterns::negZero, + valueAsBits(__llvm_libc::copysignf(valueFromBits(BitPatterns::zero), + -1.0f))); + EXPECT_EQ(BitPatterns::zero, valueAsBits(__llvm_libc::copysignf( + valueFromBits(BitPatterns::negZero), 1.0f))); +} + +TEST(CopySignFTest, InDoubleRange) { + using BitsType = Properties::BitsType; + constexpr BitsType count = 1000000; + constexpr BitsType step = UINT32_MAX / count; + for (BitsType i = 0, v = 0; i <= count; ++i, v += step) { + float x = valueFromBits(v); + if (isnan(x) || isinf(x) || x == 0) + continue; + + float res1 = __llvm_libc::copysignf(x, -x); + ASSERT_TRUE(res1 == -x); + + float res2 = __llvm_libc::copysignf(x, x); + ASSERT_TRUE(res2 == x); + } +} diff --git a/libc/test/src/math/frexp_test.cpp b/libc/test/src/math/frexp_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/math/frexp_test.cpp @@ -0,0 +1,141 @@ +//===-- Unittests for frexp -----------------------------------------------===// +// +// 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 "include/math.h" +#include "src/math/frexp.h" +#include "utils/FPUtil/BitPatterns.h" +#include "utils/FPUtil/FloatOperations.h" +#include "utils/FPUtil/FloatProperties.h" +#include "utils/UnitTest/Test.h" + +using __llvm_libc::fputil::valueAsBits; +using __llvm_libc::fputil::valueFromBits; + +using BitPatterns = __llvm_libc::fputil::BitPatterns; +using Properties = __llvm_libc::fputil::FloatProperties; + +TEST(FrexpTest, SpecialNumbers) { + int exponent; + + EXPECT_EQ(BitPatterns::aQuietNaN, + valueAsBits(__llvm_libc::frexp( + valueFromBits(BitPatterns::aQuietNaN), &exponent))); + EXPECT_EQ(BitPatterns::aNegativeQuietNaN, + valueAsBits(__llvm_libc::frexp( + valueFromBits(BitPatterns::aNegativeQuietNaN), &exponent))); + + EXPECT_EQ(BitPatterns::aSignallingNaN, + valueAsBits(__llvm_libc::frexp( + valueFromBits(BitPatterns::aSignallingNaN), &exponent))); + EXPECT_EQ( + BitPatterns::aNegativeSignallingNaN, + valueAsBits(__llvm_libc::frexp( + valueFromBits(BitPatterns::aNegativeSignallingNaN), &exponent))); + + EXPECT_EQ(BitPatterns::inf, valueAsBits(__llvm_libc::frexp( + valueFromBits(BitPatterns::inf), &exponent))); + EXPECT_EQ(BitPatterns::negInf, + valueAsBits(__llvm_libc::frexp(valueFromBits(BitPatterns::negInf), + &exponent))); + + EXPECT_EQ(BitPatterns::zero, + valueAsBits(__llvm_libc::frexp(valueFromBits(BitPatterns::zero), + &exponent))); + EXPECT_EQ(exponent, 0); + EXPECT_EQ(BitPatterns::negZero, + valueAsBits(__llvm_libc::frexp(valueFromBits(BitPatterns::negZero), + &exponent))); + EXPECT_EQ(exponent, 0); +} + +TEST(FrexpTest, PowersOfTwo) { + int exponent; + + EXPECT_EQ(valueAsBits(0.5), valueAsBits(__llvm_libc::frexp(1.0, &exponent))); + EXPECT_EQ(exponent, 1); + EXPECT_EQ(valueAsBits(-0.5), + valueAsBits(__llvm_libc::frexp(-1.0, &exponent))); + EXPECT_EQ(exponent, 1); + + EXPECT_EQ(valueAsBits(0.5), valueAsBits(__llvm_libc::frexp(2.0, &exponent))); + EXPECT_EQ(exponent, 2); + EXPECT_EQ(valueAsBits(-0.5), + valueAsBits(__llvm_libc::frexp(-2.0, &exponent))); + EXPECT_EQ(exponent, 2); + + EXPECT_EQ(valueAsBits(0.5), valueAsBits(__llvm_libc::frexp(4.0, &exponent))); + EXPECT_EQ(exponent, 3); + EXPECT_EQ(valueAsBits(-0.5), + valueAsBits(__llvm_libc::frexp(-4.0, &exponent))); + EXPECT_EQ(exponent, 3); + + EXPECT_EQ(valueAsBits(0.5), valueAsBits(__llvm_libc::frexp(8.0, &exponent))); + EXPECT_EQ(exponent, 4); + EXPECT_EQ(valueAsBits(-0.5), + valueAsBits(__llvm_libc::frexp(-8.0, &exponent))); + EXPECT_EQ(exponent, 4); + + EXPECT_EQ(valueAsBits(0.5), valueAsBits(__llvm_libc::frexp(16.0, &exponent))); + EXPECT_EQ(exponent, 5); + EXPECT_EQ(valueAsBits(-0.5), + valueAsBits(__llvm_libc::frexp(-16.0, &exponent))); + EXPECT_EQ(exponent, 5); + + EXPECT_EQ(valueAsBits(0.5), valueAsBits(__llvm_libc::frexp(32.0, &exponent))); + EXPECT_EQ(exponent, 6); + EXPECT_EQ(valueAsBits(-0.5), + valueAsBits(__llvm_libc::frexp(-32.0, &exponent))); + EXPECT_EQ(exponent, 6); + + EXPECT_EQ(valueAsBits(0.5), valueAsBits(__llvm_libc::frexp(64.0, &exponent))); + EXPECT_EQ(exponent, 7); + EXPECT_EQ(valueAsBits(-0.5), + valueAsBits(__llvm_libc::frexp(-64.0, &exponent))); + EXPECT_EQ(exponent, 7); +} + +TEST(FrexpTest, SomeIntegers) { + int exponent; + + EXPECT_EQ(valueAsBits(0.75), + valueAsBits(__llvm_libc::frexp(24.0, &exponent))); + EXPECT_EQ(exponent, 5); + EXPECT_EQ(valueAsBits(-0.75), + valueAsBits(__llvm_libc::frexp(-24.0, &exponent))); + EXPECT_EQ(exponent, 5); + + EXPECT_EQ(valueAsBits(0.625), + valueAsBits(__llvm_libc::frexp(40.0, &exponent))); + EXPECT_EQ(exponent, 6); + EXPECT_EQ(valueAsBits(-0.625), + valueAsBits(__llvm_libc::frexp(-40.0, &exponent))); + EXPECT_EQ(exponent, 6); + + EXPECT_EQ(valueAsBits(0.78125), + valueAsBits(__llvm_libc::frexp(800.0, &exponent))); + EXPECT_EQ(exponent, 10); + EXPECT_EQ(valueAsBits(-0.78125), + valueAsBits(__llvm_libc::frexp(-800.0, &exponent))); + EXPECT_EQ(exponent, 10); +} + +TEST(FrexpTest, InDoubleRange) { + using BitsType = Properties::BitsType; + constexpr BitsType count = 1000000; + constexpr BitsType step = UINT64_MAX / count; + for (BitsType i = 0, v = 0; i <= count; ++i, v += step) { + double x = valueFromBits(v); + if (isnan(x) || isinf(x) || x == 0.0) + continue; + int exponent; + double frac = __llvm_libc::frexp(x, &exponent); + + ASSERT_TRUE(__llvm_libc::fputil::abs(frac) < 1.0); + ASSERT_TRUE(__llvm_libc::fputil::abs(frac) >= 0.5); + } +} diff --git a/libc/test/src/math/frexpf_test.cpp b/libc/test/src/math/frexpf_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/math/frexpf_test.cpp @@ -0,0 +1,150 @@ +//===-- Unittests for frexpf +//-----------------------------------------------===// +// +// 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 "include/math.h" +#include "src/math/frexpf.h" +#include "utils/FPUtil/BitPatterns.h" +#include "utils/FPUtil/FloatOperations.h" +#include "utils/FPUtil/FloatProperties.h" +#include "utils/MPFRWrapper/MPFRUtils.h" +#include "utils/UnitTest/Test.h" + +using __llvm_libc::fputil::valueAsBits; +using __llvm_libc::fputil::valueFromBits; + +using BitPatterns = __llvm_libc::fputil::BitPatterns; +using Properties = __llvm_libc::fputil::FloatProperties; + +TEST(FrexpfTest, SpecialNumbers) { + int exponent; + + EXPECT_EQ(BitPatterns::aQuietNaN, + valueAsBits(__llvm_libc::frexpf( + valueFromBits(BitPatterns::aQuietNaN), &exponent))); + EXPECT_EQ(BitPatterns::aNegativeQuietNaN, + valueAsBits(__llvm_libc::frexpf( + valueFromBits(BitPatterns::aNegativeQuietNaN), &exponent))); + + EXPECT_EQ(BitPatterns::aSignallingNaN, + valueAsBits(__llvm_libc::frexpf( + valueFromBits(BitPatterns::aSignallingNaN), &exponent))); + EXPECT_EQ( + BitPatterns::aNegativeSignallingNaN, + valueAsBits(__llvm_libc::frexpf( + valueFromBits(BitPatterns::aNegativeSignallingNaN), &exponent))); + + EXPECT_EQ(BitPatterns::inf, valueAsBits(__llvm_libc::frexpf( + valueFromBits(BitPatterns::inf), &exponent))); + EXPECT_EQ(BitPatterns::negInf, + valueAsBits(__llvm_libc::frexpf(valueFromBits(BitPatterns::negInf), + &exponent))); + + EXPECT_EQ(BitPatterns::zero, + valueAsBits(__llvm_libc::frexpf(valueFromBits(BitPatterns::zero), + &exponent))); + EXPECT_EQ(exponent, 0); + EXPECT_EQ(BitPatterns::negZero, + valueAsBits(__llvm_libc::frexpf(valueFromBits(BitPatterns::negZero), + &exponent))); + EXPECT_EQ(exponent, 0); +} + +TEST(FrexpfTest, PowersOfTwo) { + int exponent; + + EXPECT_EQ(valueAsBits(0.5f), + valueAsBits(__llvm_libc::frexpf(1.0f, &exponent))); + EXPECT_EQ(exponent, 1); + EXPECT_EQ(valueAsBits(-0.5f), + valueAsBits(__llvm_libc::frexpf(-1.0f, &exponent))); + EXPECT_EQ(exponent, 1); + + EXPECT_EQ(valueAsBits(0.5f), + valueAsBits(__llvm_libc::frexpf(2.0f, &exponent))); + EXPECT_EQ(exponent, 2); + EXPECT_EQ(valueAsBits(-0.5f), + valueAsBits(__llvm_libc::frexpf(-2.0f, &exponent))); + EXPECT_EQ(exponent, 2); + + EXPECT_EQ(valueAsBits(0.5f), + valueAsBits(__llvm_libc::frexpf(4.0f, &exponent))); + EXPECT_EQ(exponent, 3); + EXPECT_EQ(valueAsBits(-0.5f), + valueAsBits(__llvm_libc::frexpf(-4.0f, &exponent))); + EXPECT_EQ(exponent, 3); + + EXPECT_EQ(valueAsBits(0.5f), + valueAsBits(__llvm_libc::frexpf(8.0f, &exponent))); + EXPECT_EQ(exponent, 4); + EXPECT_EQ(valueAsBits(-0.5f), + valueAsBits(__llvm_libc::frexpf(-8.0f, &exponent))); + EXPECT_EQ(exponent, 4); + + EXPECT_EQ(valueAsBits(0.5f), + valueAsBits(__llvm_libc::frexpf(16.0f, &exponent))); + EXPECT_EQ(exponent, 5); + EXPECT_EQ(valueAsBits(-0.5f), + valueAsBits(__llvm_libc::frexpf(-16.0f, &exponent))); + EXPECT_EQ(exponent, 5); + + EXPECT_EQ(valueAsBits(0.5f), + valueAsBits(__llvm_libc::frexpf(32.0f, &exponent))); + EXPECT_EQ(exponent, 6); + EXPECT_EQ(valueAsBits(-0.5f), + valueAsBits(__llvm_libc::frexpf(-32.0f, &exponent))); + EXPECT_EQ(exponent, 6); + + EXPECT_EQ(valueAsBits(0.5f), + valueAsBits(__llvm_libc::frexpf(64.0f, &exponent))); + EXPECT_EQ(exponent, 7); + EXPECT_EQ(valueAsBits(-0.5f), + valueAsBits(__llvm_libc::frexpf(-64.0f, &exponent))); + EXPECT_EQ(exponent, 7); +} + +TEST(FrexpTest, SomeIntegers) { + int exponent; + + EXPECT_EQ(valueAsBits(0.75f), + valueAsBits(__llvm_libc::frexpf(24.0f, &exponent))); + EXPECT_EQ(exponent, 5); + EXPECT_EQ(valueAsBits(-0.75f), + valueAsBits(__llvm_libc::frexpf(-24.0f, &exponent))); + EXPECT_EQ(exponent, 5); + + EXPECT_EQ(valueAsBits(0.625f), + valueAsBits(__llvm_libc::frexpf(40.0f, &exponent))); + EXPECT_EQ(exponent, 6); + EXPECT_EQ(valueAsBits(-0.625f), + valueAsBits(__llvm_libc::frexpf(-40.0f, &exponent))); + EXPECT_EQ(exponent, 6); + + EXPECT_EQ(valueAsBits(0.78125f), + valueAsBits(__llvm_libc::frexpf(800.0f, &exponent))); + EXPECT_EQ(exponent, 10); + EXPECT_EQ(valueAsBits(-0.78125f), + valueAsBits(__llvm_libc::frexpf(-800.0f, &exponent))); + EXPECT_EQ(exponent, 10); +} + +TEST(FrexpfTest, InFloatRange) { + using BitsType = Properties::BitsType; + constexpr BitsType count = 1000000; + constexpr BitsType step = UINT32_MAX / count; + for (BitsType i = 0, v = 0; i <= count; ++i, v += step) { + float x = valueFromBits(v); + if (isnan(x) || isinf(x) || x == 0.0) + continue; + int exponent; + float frac = __llvm_libc::frexpf(x, &exponent); + + ASSERT_TRUE(__llvm_libc::fputil::abs(frac) < 1.0f); + ASSERT_TRUE(__llvm_libc::fputil::abs(frac) >= 0.5f); + } +} diff --git a/libc/test/src/math/logb_test.cpp b/libc/test/src/math/logb_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/math/logb_test.cpp @@ -0,0 +1,99 @@ +//===-- Unittests for logb ------------------------------------------------===// +// +// 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 "include/math.h" +#include "src/math/logb.h" +#include "utils/FPUtil/BitPatterns.h" +#include "utils/FPUtil/FloatOperations.h" +#include "utils/FPUtil/FloatProperties.h" +#include "utils/FPUtil/ManipulationFunctions.h" +#include "utils/UnitTest/Test.h" + +using __llvm_libc::fputil::valueAsBits; +using __llvm_libc::fputil::valueFromBits; + +using BitPatterns = __llvm_libc::fputil::BitPatterns; +using Properties = __llvm_libc::fputil::FloatProperties; + +TEST(LogbTest, SpecialNumbers) { + EXPECT_EQ( + BitPatterns::aQuietNaN, + valueAsBits(__llvm_libc::logb(valueFromBits(BitPatterns::aQuietNaN)))); + EXPECT_EQ(BitPatterns::aNegativeQuietNaN, + valueAsBits(__llvm_libc::logb( + valueFromBits(BitPatterns::aNegativeQuietNaN)))); + + EXPECT_EQ(BitPatterns::aSignallingNaN, + valueAsBits( + __llvm_libc::logb(valueFromBits(BitPatterns::aSignallingNaN)))); + EXPECT_EQ(BitPatterns::aNegativeSignallingNaN, + valueAsBits(__llvm_libc::logb( + valueFromBits(BitPatterns::aNegativeSignallingNaN)))); + + EXPECT_EQ(BitPatterns::inf, + valueAsBits(__llvm_libc::logb(valueFromBits(BitPatterns::inf)))); + EXPECT_EQ(BitPatterns::inf, + valueAsBits(__llvm_libc::logb(valueFromBits(BitPatterns::negInf)))); + + EXPECT_EQ(BitPatterns::negInf, + valueAsBits(__llvm_libc::logb(valueFromBits(BitPatterns::zero)))); + EXPECT_EQ(BitPatterns::negInf, valueAsBits(__llvm_libc::logb( + valueFromBits(BitPatterns::negZero)))); +} + +TEST(LogbTest, PowersOfTwo) { + EXPECT_EQ(valueAsBits(0.0), valueAsBits(__llvm_libc::logb(1.0))); + EXPECT_EQ(valueAsBits(0.0), valueAsBits(__llvm_libc::logb(-1.0))); + + EXPECT_EQ(valueAsBits(1.0), valueAsBits(__llvm_libc::logb(2.0))); + EXPECT_EQ(valueAsBits(1.0), valueAsBits(__llvm_libc::logb(-2.0))); + + EXPECT_EQ(valueAsBits(2.0), valueAsBits(__llvm_libc::logb(4.0))); + EXPECT_EQ(valueAsBits(2.0), valueAsBits(__llvm_libc::logb(-4.0))); + + EXPECT_EQ(valueAsBits(3.0), valueAsBits(__llvm_libc::logb(8.0))); + EXPECT_EQ(valueAsBits(3.0), valueAsBits(__llvm_libc::logb(-8.0))); + + EXPECT_EQ(valueAsBits(4.0), valueAsBits(__llvm_libc::logb(16.0))); + EXPECT_EQ(valueAsBits(4.0), valueAsBits(__llvm_libc::logb(-16.0))); + + EXPECT_EQ(valueAsBits(5.0), valueAsBits(__llvm_libc::logb(32.0))); + EXPECT_EQ(valueAsBits(5.0), valueAsBits(__llvm_libc::logb(-32.0))); +} + +TEST(LogbTest, SomeIntegers) { + EXPECT_EQ(valueAsBits(1.0), valueAsBits(__llvm_libc::logb(3.0))); + EXPECT_EQ(valueAsBits(1.0), valueAsBits(__llvm_libc::logb(-3.0))); + + EXPECT_EQ(valueAsBits(2.0), valueAsBits(__llvm_libc::logb(7.0))); + EXPECT_EQ(valueAsBits(2.0), valueAsBits(__llvm_libc::logb(-7.0))); + + EXPECT_EQ(valueAsBits(3.0), valueAsBits(__llvm_libc::logb(10.0))); + EXPECT_EQ(valueAsBits(3.0), valueAsBits(__llvm_libc::logb(-10.0))); + + EXPECT_EQ(valueAsBits(4.0), valueAsBits(__llvm_libc::logb(31.0))); + EXPECT_EQ(valueAsBits(4.0), valueAsBits(__llvm_libc::logb(-31.0))); + + EXPECT_EQ(valueAsBits(5.0), valueAsBits(__llvm_libc::logb(55.0))); + EXPECT_EQ(valueAsBits(5.0), valueAsBits(__llvm_libc::logb(-55.0))); +} + +TEST(LogbTest, InDoubleRange) { + using BitsType = Properties::BitsType; + constexpr BitsType count = 10000000; + constexpr BitsType step = UINT64_MAX / count; + for (BitsType i = 0, v = 0; i <= count; ++i, v += step) { + double x = valueFromBits(v); + if (isnan(x) || isinf(x) || x == 0.0) + continue; + + int exponent; + __llvm_libc::fputil::frexp(x, exponent); + ASSERT_TRUE(double(exponent) == __llvm_libc::logb(x) + 1.0); + } +} diff --git a/libc/test/src/math/logbf_test.cpp b/libc/test/src/math/logbf_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/math/logbf_test.cpp @@ -0,0 +1,99 @@ +//===-- Unittests for logbf -----------------------------------------------===// +// +// 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 "include/math.h" +#include "src/math/logbf.h" +#include "utils/FPUtil/BitPatterns.h" +#include "utils/FPUtil/FloatOperations.h" +#include "utils/FPUtil/FloatProperties.h" +#include "utils/FPUtil/ManipulationFunctions.h" +#include "utils/UnitTest/Test.h" + +using __llvm_libc::fputil::valueAsBits; +using __llvm_libc::fputil::valueFromBits; + +using BitPatterns = __llvm_libc::fputil::BitPatterns; +using Properties = __llvm_libc::fputil::FloatProperties; + +TEST(LogbfTest, SpecialNumbers) { + EXPECT_EQ( + BitPatterns::aQuietNaN, + valueAsBits(__llvm_libc::logbf(valueFromBits(BitPatterns::aQuietNaN)))); + EXPECT_EQ(BitPatterns::aNegativeQuietNaN, + valueAsBits(__llvm_libc::logbf( + valueFromBits(BitPatterns::aNegativeQuietNaN)))); + + EXPECT_EQ(BitPatterns::aSignallingNaN, + valueAsBits(__llvm_libc::logbf( + valueFromBits(BitPatterns::aSignallingNaN)))); + EXPECT_EQ(BitPatterns::aNegativeSignallingNaN, + valueAsBits(__llvm_libc::logbf( + valueFromBits(BitPatterns::aNegativeSignallingNaN)))); + + EXPECT_EQ(BitPatterns::inf, + valueAsBits(__llvm_libc::logbf(valueFromBits(BitPatterns::inf)))); + EXPECT_EQ(BitPatterns::inf, valueAsBits(__llvm_libc::logbf( + valueFromBits(BitPatterns::negInf)))); + + EXPECT_EQ(BitPatterns::negInf, + valueAsBits(__llvm_libc::logbf(valueFromBits(BitPatterns::zero)))); + EXPECT_EQ(BitPatterns::negInf, valueAsBits(__llvm_libc::logbf( + valueFromBits(BitPatterns::negZero)))); +} + +TEST(LogbfTest, PowersOfTwo) { + EXPECT_EQ(valueAsBits(0.0f), valueAsBits(__llvm_libc::logbf(1.0f))); + EXPECT_EQ(valueAsBits(0.0f), valueAsBits(__llvm_libc::logbf(-1.0f))); + + EXPECT_EQ(valueAsBits(1.0f), valueAsBits(__llvm_libc::logbf(2.0f))); + EXPECT_EQ(valueAsBits(1.0f), valueAsBits(__llvm_libc::logbf(-2.0f))); + + EXPECT_EQ(valueAsBits(2.0f), valueAsBits(__llvm_libc::logbf(4.0f))); + EXPECT_EQ(valueAsBits(2.0f), valueAsBits(__llvm_libc::logbf(-4.0f))); + + EXPECT_EQ(valueAsBits(3.0f), valueAsBits(__llvm_libc::logbf(8.0f))); + EXPECT_EQ(valueAsBits(3.0f), valueAsBits(__llvm_libc::logbf(-8.0f))); + + EXPECT_EQ(valueAsBits(4.0f), valueAsBits(__llvm_libc::logbf(16.0f))); + EXPECT_EQ(valueAsBits(4.0f), valueAsBits(__llvm_libc::logbf(-16.0f))); + + EXPECT_EQ(valueAsBits(5.0f), valueAsBits(__llvm_libc::logbf(32.0f))); + EXPECT_EQ(valueAsBits(5.0f), valueAsBits(__llvm_libc::logbf(-32.0f))); +} + +TEST(LogbTest, SomeIntegers) { + EXPECT_EQ(valueAsBits(1.0f), valueAsBits(__llvm_libc::logbf(3.0f))); + EXPECT_EQ(valueAsBits(1.0f), valueAsBits(__llvm_libc::logbf(-3.0f))); + + EXPECT_EQ(valueAsBits(2.0f), valueAsBits(__llvm_libc::logbf(7.0f))); + EXPECT_EQ(valueAsBits(2.0f), valueAsBits(__llvm_libc::logbf(-7.0f))); + + EXPECT_EQ(valueAsBits(3.0f), valueAsBits(__llvm_libc::logbf(10.0f))); + EXPECT_EQ(valueAsBits(3.0f), valueAsBits(__llvm_libc::logbf(-10.0f))); + + EXPECT_EQ(valueAsBits(4.0f), valueAsBits(__llvm_libc::logbf(31.0f))); + EXPECT_EQ(valueAsBits(4.0f), valueAsBits(__llvm_libc::logbf(-31.0f))); + + EXPECT_EQ(valueAsBits(5.0f), valueAsBits(__llvm_libc::logbf(55.0f))); + EXPECT_EQ(valueAsBits(5.0f), valueAsBits(__llvm_libc::logbf(-55.0f))); +} + +TEST(LogbfTest, InDoubleRange) { + using BitsType = Properties::BitsType; + constexpr BitsType count = 10000000; + constexpr BitsType step = UINT32_MAX / count; + for (BitsType i = 0, v = 0; i <= count; ++i, v += step) { + float x = valueFromBits(v); + if (isnan(x) || isinf(x) || x == 0.0) + continue; + + int exponent; + __llvm_libc::fputil::frexp(x, exponent); + ASSERT_TRUE(float(exponent) == __llvm_libc::logbf(x) + 1.0); + } +} diff --git a/libc/test/src/math/modf_test.cpp b/libc/test/src/math/modf_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/math/modf_test.cpp @@ -0,0 +1,130 @@ +//===-- Unittests for modf ------------------------------------------------===// +// +// 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 "include/math.h" +#include "src/math/modf.h" +#include "utils/FPUtil/BitPatterns.h" +#include "utils/FPUtil/FloatOperations.h" +#include "utils/FPUtil/FloatProperties.h" +#include "utils/UnitTest/Test.h" + +using __llvm_libc::fputil::valueAsBits; +using __llvm_libc::fputil::valueFromBits; + +using BitPatterns = __llvm_libc::fputil::BitPatterns; +using Properties = __llvm_libc::fputil::FloatProperties; + +TEST(ModfTest, SpecialNumbers) { + double integral; + + EXPECT_EQ(BitPatterns::aQuietNaN, + valueAsBits(__llvm_libc::modf(valueFromBits(BitPatterns::aQuietNaN), + &integral))); + EXPECT_EQ(BitPatterns::aNegativeQuietNaN, + valueAsBits(__llvm_libc::modf( + valueFromBits(BitPatterns::aNegativeQuietNaN), &integral))); + + EXPECT_EQ(BitPatterns::aSignallingNaN, + valueAsBits(__llvm_libc::modf( + valueFromBits(BitPatterns::aSignallingNaN), &integral))); + EXPECT_EQ( + BitPatterns::aNegativeSignallingNaN, + valueAsBits(__llvm_libc::modf( + valueFromBits(BitPatterns::aNegativeSignallingNaN), &integral))); + + EXPECT_EQ(BitPatterns::zero, + valueAsBits( + __llvm_libc::modf(valueFromBits(BitPatterns::inf), &integral))); + EXPECT_EQ(valueAsBits(integral), BitPatterns::inf); + + EXPECT_EQ(BitPatterns::negZero, + valueAsBits(__llvm_libc::modf(valueFromBits(BitPatterns::negInf), + &integral))); + EXPECT_EQ(valueAsBits(integral), BitPatterns::negInf); + + EXPECT_EQ(BitPatterns::zero, + valueAsBits(__llvm_libc::modf(valueFromBits(BitPatterns::zero), + &integral))); + EXPECT_EQ(valueAsBits(integral), BitPatterns::zero); + + EXPECT_EQ(BitPatterns::negZero, + valueAsBits(__llvm_libc::modf(valueFromBits(BitPatterns::negZero), + &integral))); + EXPECT_EQ(valueAsBits(integral), BitPatterns::negZero); +} + +TEST(ModfTest, Integers) { + double integral; + + EXPECT_EQ(BitPatterns::zero, valueAsBits(__llvm_libc::modf(1.0, &integral))); + EXPECT_EQ(valueAsBits(integral), valueAsBits(1.0)); + + EXPECT_EQ(BitPatterns::negZero, + valueAsBits(__llvm_libc::modf(-1.0, &integral))); + EXPECT_EQ(valueAsBits(integral), valueAsBits(-1.0)); + + EXPECT_EQ(BitPatterns::zero, valueAsBits(__llvm_libc::modf(10.0, &integral))); + EXPECT_EQ(valueAsBits(integral), valueAsBits(10.0)); + + EXPECT_EQ(BitPatterns::negZero, + valueAsBits(__llvm_libc::modf(-10.0, &integral))); + EXPECT_EQ(valueAsBits(integral), valueAsBits(-10.0)); + + EXPECT_EQ(BitPatterns::zero, + valueAsBits(__llvm_libc::modf(12345.0, &integral))); + EXPECT_EQ(valueAsBits(integral), valueAsBits(12345.0)); + + EXPECT_EQ(BitPatterns::negZero, + valueAsBits(__llvm_libc::modf(-12345.0, &integral))); + EXPECT_EQ(valueAsBits(integral), valueAsBits(-12345.0)); +} + +TEST(ModfTest, Fractions) { + double integral; + + EXPECT_EQ(valueAsBits(0.5), valueAsBits(__llvm_libc::modf(1.5, &integral))); + EXPECT_EQ(valueAsBits(integral), valueAsBits(1.0)); + + EXPECT_EQ(valueAsBits(-0.5), valueAsBits(__llvm_libc::modf(-1.5, &integral))); + EXPECT_EQ(valueAsBits(integral), valueAsBits(-1.0)); + + EXPECT_EQ(valueAsBits(0.75), + valueAsBits(__llvm_libc::modf(10.75, &integral))); + EXPECT_EQ(valueAsBits(integral), valueAsBits(10.0)); + + EXPECT_EQ(valueAsBits(-0.75), + valueAsBits(__llvm_libc::modf(-10.75, &integral))); + EXPECT_EQ(valueAsBits(integral), valueAsBits(-10.0)); + + EXPECT_EQ(valueAsBits(0.125), + valueAsBits(__llvm_libc::modf(100.125, &integral))); + EXPECT_EQ(valueAsBits(integral), valueAsBits(100.0)); + + EXPECT_EQ(valueAsBits(-0.125), + valueAsBits(__llvm_libc::modf(-100.125, &integral))); + EXPECT_EQ(valueAsBits(integral), valueAsBits(-100.0)); +} + +TEST(ModfTest, InDoubleRange) { + using BitsType = Properties::BitsType; + constexpr BitsType count = 10000000; + constexpr BitsType step = UINT64_MAX / count; + for (BitsType i = 0, v = 0; i <= count; ++i, v += step) { + double x = valueFromBits(v); + if (isnan(x) || isinf(x) || x == 0.0) { + // These conditions have been tested in other tests. + continue; + } + + double integral; + double frac = __llvm_libc::modf(x, &integral); + ASSERT_TRUE(__llvm_libc::fputil::abs(frac) < 1.0); + ASSERT_TRUE(__llvm_libc::fputil::trunc(x) == integral); + ASSERT_TRUE(integral + frac == x); + } +} diff --git a/libc/test/src/math/modff_test.cpp b/libc/test/src/math/modff_test.cpp new file mode 100644 --- /dev/null +++ b/libc/test/src/math/modff_test.cpp @@ -0,0 +1,135 @@ +//===-- Unittests for modfff +//-----------------------------------------------===// +// +// 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 "include/math.h" +#include "src/math/modff.h" +#include "utils/FPUtil/BitPatterns.h" +#include "utils/FPUtil/FloatOperations.h" +#include "utils/FPUtil/FloatProperties.h" +#include "utils/UnitTest/Test.h" + +using __llvm_libc::fputil::valueAsBits; +using __llvm_libc::fputil::valueFromBits; + +using BitPatterns = __llvm_libc::fputil::BitPatterns; +using Properties = __llvm_libc::fputil::FloatProperties; + +TEST(ModffTest, SpecialNumbers) { + float integral; + + EXPECT_EQ(BitPatterns::aQuietNaN, + valueAsBits(__llvm_libc::modff( + valueFromBits(BitPatterns::aQuietNaN), &integral))); + EXPECT_EQ(BitPatterns::aNegativeQuietNaN, + valueAsBits(__llvm_libc::modff( + valueFromBits(BitPatterns::aNegativeQuietNaN), &integral))); + + EXPECT_EQ(BitPatterns::aSignallingNaN, + valueAsBits(__llvm_libc::modff( + valueFromBits(BitPatterns::aSignallingNaN), &integral))); + EXPECT_EQ( + BitPatterns::aNegativeSignallingNaN, + valueAsBits(__llvm_libc::modff( + valueFromBits(BitPatterns::aNegativeSignallingNaN), &integral))); + + EXPECT_EQ(BitPatterns::zero, + valueAsBits(__llvm_libc::modff(valueFromBits(BitPatterns::inf), + &integral))); + EXPECT_EQ(valueAsBits(integral), BitPatterns::inf); + + EXPECT_EQ(BitPatterns::negZero, + valueAsBits(__llvm_libc::modff(valueFromBits(BitPatterns::negInf), + &integral))); + EXPECT_EQ(valueAsBits(integral), BitPatterns::negInf); + + EXPECT_EQ(BitPatterns::zero, + valueAsBits(__llvm_libc::modff(valueFromBits(BitPatterns::zero), + &integral))); + EXPECT_EQ(valueAsBits(integral), BitPatterns::zero); + + EXPECT_EQ(BitPatterns::negZero, + valueAsBits(__llvm_libc::modff(valueFromBits(BitPatterns::negZero), + &integral))); + EXPECT_EQ(valueAsBits(integral), BitPatterns::negZero); +} + +TEST(ModffTest, Integers) { + float integral; + + EXPECT_EQ(BitPatterns::zero, + valueAsBits(__llvm_libc::modff(1.0f, &integral))); + EXPECT_EQ(valueAsBits(integral), valueAsBits(1.0f)); + + EXPECT_EQ(BitPatterns::negZero, + valueAsBits(__llvm_libc::modff(-1.0f, &integral))); + EXPECT_EQ(valueAsBits(integral), valueAsBits(-1.0f)); + + EXPECT_EQ(BitPatterns::zero, + valueAsBits(__llvm_libc::modff(10.0f, &integral))); + EXPECT_EQ(valueAsBits(integral), valueAsBits(10.0f)); + + EXPECT_EQ(BitPatterns::negZero, + valueAsBits(__llvm_libc::modff(-10.0f, &integral))); + EXPECT_EQ(valueAsBits(integral), valueAsBits(-10.0f)); + + EXPECT_EQ(BitPatterns::zero, + valueAsBits(__llvm_libc::modff(12345.0f, &integral))); + EXPECT_EQ(valueAsBits(integral), valueAsBits(12345.0f)); + + EXPECT_EQ(BitPatterns::negZero, + valueAsBits(__llvm_libc::modff(-12345.0f, &integral))); + EXPECT_EQ(valueAsBits(integral), valueAsBits(-12345.0f)); +} + +TEST(ModfTest, Fractions) { + float integral; + + EXPECT_EQ(valueAsBits(0.5f), + valueAsBits(__llvm_libc::modff(1.5f, &integral))); + EXPECT_EQ(valueAsBits(integral), valueAsBits(1.0f)); + + EXPECT_EQ(valueAsBits(-0.5f), + valueAsBits(__llvm_libc::modff(-1.5f, &integral))); + EXPECT_EQ(valueAsBits(integral), valueAsBits(-1.0f)); + + EXPECT_EQ(valueAsBits(0.75f), + valueAsBits(__llvm_libc::modff(10.75f, &integral))); + EXPECT_EQ(valueAsBits(integral), valueAsBits(10.0f)); + + EXPECT_EQ(valueAsBits(-0.75f), + valueAsBits(__llvm_libc::modff(-10.75f, &integral))); + EXPECT_EQ(valueAsBits(integral), valueAsBits(-10.0f)); + + EXPECT_EQ(valueAsBits(0.125f), + valueAsBits(__llvm_libc::modff(100.125f, &integral))); + EXPECT_EQ(valueAsBits(integral), valueAsBits(100.0f)); + + EXPECT_EQ(valueAsBits(-0.125f), + valueAsBits(__llvm_libc::modff(-100.125f, &integral))); + EXPECT_EQ(valueAsBits(integral), valueAsBits(-100.0f)); +} + +TEST(ModffTest, InDoubleRange) { + using BitsType = Properties::BitsType; + constexpr BitsType count = 10000000; + constexpr BitsType step = UINT32_MAX / count; + for (BitsType i = 0, v = 0; i <= count; ++i, v += step) { + float x = valueFromBits(v); + if (isnan(x) || isinf(x) || x == 0.0f) { + // These conditions have been tested in other tests. + continue; + } + + float integral; + float frac = __llvm_libc::modff(x, &integral); + ASSERT_TRUE(__llvm_libc::fputil::abs(frac) < 1.0f); + ASSERT_TRUE(__llvm_libc::fputil::trunc(x) == integral); + ASSERT_TRUE(integral + frac == x); + } +} diff --git a/libc/utils/FPUtil/BitPatterns.h b/libc/utils/FPUtil/BitPatterns.h --- a/libc/utils/FPUtil/BitPatterns.h +++ b/libc/utils/FPUtil/BitPatterns.h @@ -11,6 +11,12 @@ #include "FloatProperties.h" +#include + +static_assert( + FLT_RADIX == 2, + "LLVM libc only supports radix 2 IEEE 754 floating point formats."); + namespace __llvm_libc { namespace fputil { diff --git a/libc/utils/FPUtil/CMakeLists.txt b/libc/utils/FPUtil/CMakeLists.txt --- a/libc/utils/FPUtil/CMakeLists.txt +++ b/libc/utils/FPUtil/CMakeLists.txt @@ -4,6 +4,7 @@ BitPatterns.h FloatOperations.h FloatProperties.h + ManipulationFunctions.h DEPS libc.utils.CPP.standalone_cpp ) diff --git a/libc/utils/FPUtil/FloatOperations.h b/libc/utils/FPUtil/FloatOperations.h --- a/libc/utils/FPUtil/FloatOperations.h +++ b/libc/utils/FPUtil/FloatOperations.h @@ -57,26 +57,30 @@ return getExponentFromBits(valueAsBits(x)); } +template static inline bool bitsAreInf(BitsType bits) { + using FPType = typename FloatType::Type; + return ((bits & BitPatterns::inf) == BitPatterns::inf) && + ((bits & FloatProperties::mantissaMask) == 0); +} + // Return true if x is infinity (positive or negative.) template ::Value, int> = 0> static inline bool isInf(T x) { - using Properties = FloatProperties; - using BitsType = typename FloatProperties::BitsType; - BitsType bits = valueAsBits(x); - return ((bits & BitPatterns::inf) == BitPatterns::inf) && - ((bits & Properties::mantissaMask) == 0); + return bitsAreInf(valueAsBits(x)); +} + +template static inline bool bitsAreNaN(BitsType bits) { + using FPType = typename FloatType::Type; + return ((bits & BitPatterns::inf) == BitPatterns::inf) && + ((bits & FloatProperties::mantissaMask) != 0); } // Return true if x is a NAN (quiet or signalling.) template ::Value, int> = 0> static inline bool isNaN(T x) { - using Properties = FloatProperties; - using BitsType = typename FloatProperties::BitsType; - BitsType bits = valueAsBits(x); - return ((bits & BitPatterns::inf) == BitPatterns::inf) && - ((bits & Properties::mantissaMask) != 0); + return bitsAreNaN(valueAsBits(x)); } template static inline bool bitsAreInfOrNaN(BitsType bits) { diff --git a/libc/utils/FPUtil/ManipulationFunctions.h b/libc/utils/FPUtil/ManipulationFunctions.h new file mode 100644 --- /dev/null +++ b/libc/utils/FPUtil/ManipulationFunctions.h @@ -0,0 +1,102 @@ +//===-- Common operations on floating point numbers -------------*- 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 +// +//===----------------------------------------------------------------------===// + +#include "BitPatterns.h" +#include "FloatOperations.h" +#include "FloatProperties.h" + +#include "utils/CPP/TypeTraits.h" + +#ifndef LLVM_LIBC_UTILS_FPUTIL_MANIPULATION_FUNCTIONS_H +#define LLVM_LIBC_UTILS_FPUTIL_MANIPULATION_FUNCTIONS_H + +namespace __llvm_libc { +namespace fputil { + +template ::Value, int> = 0> +static inline T frexp(T x, int &exp) { + using Properties = FloatProperties; + using BitsType = typename Properties::BitsType; + + auto bits = valueAsBits(x); + if (bitsAreInfOrNaN(bits)) + return x; + if (bitsAreZero(bits)) { + exp = 0; + return x; + } + + exp = getExponentFromBits(bits) + 1; + + static constexpr BitsType resultExponent = + Properties::exponentOffset - BitsType(1); + // Capture the sign and mantissa part. + bits &= (Properties::mantissaMask | Properties::signMask); + // Insert the new exponent. + bits |= (resultExponent << Properties::mantissaWidth); + + return valueFromBits(bits); +} + +template ::Value, int> = 0> +static inline T modf(T x, T &iptr) { + auto bits = valueAsBits(x); + if (bitsAreZero(bits) || bitsAreNaN(bits)) { + iptr = x; + return x; + } else if (bitsAreInf(bits)) { + iptr = x; + return bits & FloatProperties::signMask + ? valueFromBits(BitPatterns::negZero) + : valueFromBits(BitPatterns::zero); + } else { + iptr = trunc(x); + if (x == iptr) { + // If x is already an integer value, then return zero with the right + // sign. + return bits & FloatProperties::signMask + ? valueFromBits(BitPatterns::negZero) + : valueFromBits(BitPatterns::zero); + } else { + return x - iptr; + } + } +} + +template ::Value, int> = 0> +static inline T copysign(T x, T y) { + constexpr auto signMask = FloatProperties::signMask; + auto xbits = valueAsBits(x); + auto ybits = valueAsBits(y); + return valueFromBits((xbits & ~signMask) | (ybits & signMask)); +} + +template ::Value, int> = 0> +static inline T logb(T x) { + auto bits = valueAsBits(x); + if (bitsAreZero(bits)) { + // TODO(Floating point exception): Raise div-by-zero exception. + // TODO(errno): POSIX requires setting errno to ERANGE. + return valueFromBits(BitPatterns::negInf); + } else if (bitsAreInf(bits)) { + return valueFromBits(BitPatterns::inf); + } else if (bitsAreNaN(bits)) { + return x; + } else { + return getExponentFromBits(bits); + } +} + +} // namespace fputil +} // namespace __llvm_libc + +#endif // LLVM_LIBC_UTILS_FPUTIL_MANIPULATION_FUNCTIONS_H