[libc] Add long double flavors of the floating point manipulation functions.
Specifically: copysignl, frexpl, logbl and modfl have been added. Reviewers: asteinhauser Differential Revision: https://reviews.llvm.org/D82357
This commit is contained in:
parent
31c40f2d6b
commit
a00fb593b4
|
@ -152,6 +152,7 @@ def MathAPI : PublicAPI<"math.h"> {
|
|||
let Functions = [
|
||||
"copysign",
|
||||
"copysignf",
|
||||
"copysignl",
|
||||
"ceil",
|
||||
"ceilf",
|
||||
"cosf",
|
||||
|
@ -162,10 +163,13 @@ def MathAPI : PublicAPI<"math.h"> {
|
|||
"floorf",
|
||||
"frexp",
|
||||
"frexpf",
|
||||
"frexpl",
|
||||
"logb",
|
||||
"logbf",
|
||||
"logbl",
|
||||
"modf",
|
||||
"modff",
|
||||
"modfl",
|
||||
"expf",
|
||||
"exp2f",
|
||||
"round",
|
||||
|
|
|
@ -48,6 +48,7 @@ set(TARGET_LIBM_ENTRYPOINTS
|
|||
# math.h entrypoints
|
||||
libc.src.math.copysign
|
||||
libc.src.math.copysignf
|
||||
libc.src.math.copysignl
|
||||
libc.src.math.ceil
|
||||
libc.src.math.ceilf
|
||||
libc.src.math.cosf
|
||||
|
@ -60,10 +61,13 @@ set(TARGET_LIBM_ENTRYPOINTS
|
|||
libc.src.math.floorf
|
||||
libc.src.math.frexp
|
||||
libc.src.math.frexpf
|
||||
libc.src.math.frexpl
|
||||
libc.src.math.logb
|
||||
libc.src.math.logbf
|
||||
libc.src.math.logbl
|
||||
libc.src.math.modf
|
||||
libc.src.math.modff
|
||||
libc.src.math.modfl
|
||||
libc.src.math.round
|
||||
libc.src.math.roundf
|
||||
libc.src.math.sincosf
|
||||
|
|
|
@ -49,6 +49,7 @@ def VoidPtr : PtrType<VoidType>;
|
|||
def ConstVoidPtr : ConstType<VoidPtr>;
|
||||
def SizeTType : NamedType<"size_t">;
|
||||
def FloatPtr : PtrType<FloatType>;
|
||||
def LongDoublePtr : PtrType<LongDoubleType>;
|
||||
|
||||
// _Noreturn is really not a type, but it is convenient to treat it as a type.
|
||||
def NoReturn : NamedType<"_Noreturn void">;
|
||||
|
|
|
@ -191,6 +191,7 @@ def StdC : StandardSpec<"stdc"> {
|
|||
[
|
||||
FunctionSpec<"copysign", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<DoubleType>]>,
|
||||
FunctionSpec<"copysignf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<FloatType>]>,
|
||||
FunctionSpec<"copysignl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<LongDoubleType>]>,
|
||||
|
||||
FunctionSpec<"ceil", RetValSpec<DoubleType>, [ArgSpec<DoubleType>]>,
|
||||
FunctionSpec<"ceilf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
|
||||
|
@ -204,12 +205,15 @@ def StdC : StandardSpec<"stdc"> {
|
|||
|
||||
FunctionSpec<"frexp", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<IntPtr>]>,
|
||||
FunctionSpec<"frexpf", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<IntPtr>]>,
|
||||
FunctionSpec<"frexpl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<IntPtr>]>,
|
||||
|
||||
FunctionSpec<"logb", RetValSpec<DoubleType>, [ArgSpec<DoubleType>]>,
|
||||
FunctionSpec<"logbf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
|
||||
FunctionSpec<"logbl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>]>,
|
||||
|
||||
FunctionSpec<"modf", RetValSpec<DoubleType>, [ArgSpec<DoubleType>, ArgSpec<DoublePtr>]>,
|
||||
FunctionSpec<"modff", RetValSpec<FloatType>, [ArgSpec<FloatType>, ArgSpec<FloatPtr>]>,
|
||||
FunctionSpec<"modfl", RetValSpec<LongDoubleType>, [ArgSpec<LongDoubleType>, ArgSpec<LongDoublePtr>]>,
|
||||
|
||||
FunctionSpec<"cosf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
|
||||
FunctionSpec<"sinf", RetValSpec<FloatType>, [ArgSpec<FloatType>]>,
|
||||
|
|
|
@ -238,6 +238,8 @@ add_entrypoint_object(
|
|||
copysign.h
|
||||
DEPENDS
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
|
@ -248,6 +250,20 @@ add_entrypoint_object(
|
|||
copysignf.h
|
||||
DEPENDS
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
copysignl
|
||||
SRCS
|
||||
copysignl.cpp
|
||||
HDRS
|
||||
copysignl.h
|
||||
DEPENDS
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
|
@ -258,6 +274,8 @@ add_entrypoint_object(
|
|||
frexp.h
|
||||
DEPENDS
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
|
@ -268,6 +286,20 @@ add_entrypoint_object(
|
|||
frexpf.h
|
||||
DEPENDS
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
frexpl
|
||||
SRCS
|
||||
frexpl.cpp
|
||||
HDRS
|
||||
frexpl.h
|
||||
DEPENDS
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
|
@ -278,6 +310,8 @@ add_entrypoint_object(
|
|||
logb.h
|
||||
DEPENDS
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
|
@ -288,6 +322,20 @@ add_entrypoint_object(
|
|||
logbf.h
|
||||
DEPENDS
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
logbl
|
||||
SRCS
|
||||
logbl.cpp
|
||||
HDRS
|
||||
logbl.h
|
||||
DEPENDS
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
|
@ -298,6 +346,8 @@ add_entrypoint_object(
|
|||
modf.h
|
||||
DEPENDS
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
|
@ -308,4 +358,18 @@ add_entrypoint_object(
|
|||
modff.h
|
||||
DEPENDS
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
modfl
|
||||
SRCS
|
||||
modfl.cpp
|
||||
HDRS
|
||||
modfl.h
|
||||
DEPENDS
|
||||
libc.utils.FPUtil.fputil
|
||||
COMPILE_OPTIONS
|
||||
-O2
|
||||
)
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
//===-- Implementation of copysignl 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 {
|
||||
|
||||
long double LLVM_LIBC_ENTRYPOINT(copysignl)(long double x, long double y) {
|
||||
return fputil::copysign(x, y);
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
|
@ -0,0 +1,18 @@
|
|||
//===-- Implementation header for copysignl ---------------------*- 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_COPYSIGNL_H
|
||||
#define LLVM_LIBC_SRC_MATH_COPYSIGNL_H
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
long double copysignl(long double x, long double y);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_MATH_COPYSIGNL_H
|
|
@ -0,0 +1,18 @@
|
|||
//===-- Implementation of frexpl 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 {
|
||||
|
||||
long double LLVM_LIBC_ENTRYPOINT(frexpl)(long double x, int *exp) {
|
||||
return fputil::frexp(x, *exp);
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
|
@ -0,0 +1,18 @@
|
|||
//===-- Implementation header for frexpl ------------------------*- 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_FREXPL_H
|
||||
#define LLVM_LIBC_SRC_MATH_FREXPL_H
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
long double frexpl(long double x, int *exp);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_MATH_FREXPL_H
|
|
@ -0,0 +1,18 @@
|
|||
//===-- Implementation of logbl 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 {
|
||||
|
||||
long double LLVM_LIBC_ENTRYPOINT(logbl)(long double x) {
|
||||
return fputil::logb(x);
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
|
@ -0,0 +1,18 @@
|
|||
//===-- Implementation header for logbl -------------------------*- 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_LOGBL_H
|
||||
#define LLVM_LIBC_SRC_MATH_LOGBL_H
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
long double logbl(long double x);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_MATH_LOGBL_H
|
|
@ -0,0 +1,18 @@
|
|||
//===-- Implementation of modfl 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 {
|
||||
|
||||
long double LLVM_LIBC_ENTRYPOINT(modfl)(long double x, long double *iptr) {
|
||||
return fputil::modf(x, *iptr);
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
|
@ -0,0 +1,18 @@
|
|||
//===-- Implementation header for modfl -------------------------*- 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_MODFL_H
|
||||
#define LLVM_LIBC_SRC_MATH_MODFL_H
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
long double modfl(long double x, long double *iptr);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_MATH_MODFL_H
|
|
@ -279,6 +279,18 @@ add_math_unittest(
|
|||
libc.utils.FPUtil.fputil
|
||||
)
|
||||
|
||||
add_math_unittest(
|
||||
copysignl_test
|
||||
SUITE
|
||||
libc_math_unittests
|
||||
SRCS
|
||||
copysignl_test.cpp
|
||||
DEPENDS
|
||||
libc.include.math
|
||||
libc.src.math.copysignl
|
||||
libc.utils.FPUtil.fputil
|
||||
)
|
||||
|
||||
add_math_unittest(
|
||||
frexp_test
|
||||
SUITE
|
||||
|
@ -303,6 +315,18 @@ add_math_unittest(
|
|||
libc.utils.FPUtil.fputil
|
||||
)
|
||||
|
||||
add_math_unittest(
|
||||
frexpl_test
|
||||
SUITE
|
||||
libc_math_unittests
|
||||
SRCS
|
||||
frexpl_test.cpp
|
||||
DEPENDS
|
||||
libc.include.math
|
||||
libc.src.math.frexpl
|
||||
libc.utils.FPUtil.fputil
|
||||
)
|
||||
|
||||
add_math_unittest(
|
||||
logb_test
|
||||
SUITE
|
||||
|
@ -327,6 +351,18 @@ add_math_unittest(
|
|||
libc.utils.FPUtil.fputil
|
||||
)
|
||||
|
||||
add_math_unittest(
|
||||
logbl_test
|
||||
SUITE
|
||||
libc_math_unittests
|
||||
SRCS
|
||||
logbl_test.cpp
|
||||
DEPENDS
|
||||
libc.include.math
|
||||
libc.src.math.logbl
|
||||
libc.utils.FPUtil.fputil
|
||||
)
|
||||
|
||||
add_math_unittest(
|
||||
modf_test
|
||||
SUITE
|
||||
|
@ -350,3 +386,15 @@ add_math_unittest(
|
|||
libc.src.math.modff
|
||||
libc.utils.FPUtil.fputil
|
||||
)
|
||||
|
||||
add_math_unittest(
|
||||
modfl_test
|
||||
SUITE
|
||||
libc_math_unittests
|
||||
SRCS
|
||||
modfl_test.cpp
|
||||
DEPENDS
|
||||
libc.include.math
|
||||
libc.src.math.modfl
|
||||
libc.utils.FPUtil.fputil
|
||||
)
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
//===-- Unittests for copysignl
|
||||
//--------------------------------------------===//
|
||||
//
|
||||
// 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/copysignl.h"
|
||||
#include "utils/FPUtil/FPBits.h"
|
||||
#include "utils/UnitTest/Test.h"
|
||||
|
||||
using FPBits = __llvm_libc::fputil::FPBits<long double>;
|
||||
|
||||
TEST(CopysignlTest, SpecialNumbers) {
|
||||
EXPECT_TRUE(FPBits::negZero() ==
|
||||
__llvm_libc::copysignl(FPBits::zero(), -1.0l));
|
||||
EXPECT_TRUE(FPBits::zero() ==
|
||||
__llvm_libc::copysignl(FPBits::negZero(), 1.0l));
|
||||
|
||||
EXPECT_TRUE(FPBits::negZero() ==
|
||||
__llvm_libc::copysignl(FPBits::zero(), -1.0l));
|
||||
EXPECT_TRUE(FPBits::zero() ==
|
||||
__llvm_libc::copysignl(FPBits::negZero(), 1.0l));
|
||||
|
||||
EXPECT_TRUE(
|
||||
FPBits(__llvm_libc::copysignl(FPBits::buildNaN(1), -1.0l)).isNaN());
|
||||
}
|
||||
|
||||
TEST(CopysignlTest, InDoubleRange) {
|
||||
using UIntType = FPBits::UIntType;
|
||||
constexpr UIntType count = 10000000;
|
||||
constexpr UIntType step = UIntType(-1) / count;
|
||||
for (UIntType i = 0, v = 0; i <= count; ++i, v += step) {
|
||||
long double x = FPBits(v);
|
||||
if (isnan(x) || isinf(x) || x == 0)
|
||||
continue;
|
||||
|
||||
long double res1 = __llvm_libc::copysignl(x, -x);
|
||||
ASSERT_TRUE(res1 == -x);
|
||||
|
||||
long double res2 = __llvm_libc::copysignl(x, x);
|
||||
ASSERT_TRUE(res2 == x);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
//===-- Unittests for frexpl ----------------------------------------------===//
|
||||
//
|
||||
// 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/frexpl.h"
|
||||
#include "utils/FPUtil/BasicOperations.h"
|
||||
#include "utils/FPUtil/FPBits.h"
|
||||
#include "utils/UnitTest/Test.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
using FPBits = __llvm_libc::fputil::FPBits<long double>;
|
||||
|
||||
TEST(FrexplTest, SpecialNumbers) {
|
||||
int exponent;
|
||||
|
||||
EXPECT_TRUE(FPBits::inf() == __llvm_libc::frexpl(FPBits::inf(), &exponent));
|
||||
EXPECT_TRUE(FPBits::negInf() ==
|
||||
__llvm_libc::frexpl(FPBits::negInf(), &exponent));
|
||||
|
||||
EXPECT_TRUE(FPBits::zero() == __llvm_libc::frexpl(FPBits::zero(), &exponent));
|
||||
EXPECT_EQ(exponent, 0);
|
||||
|
||||
EXPECT_TRUE(FPBits::negZero() ==
|
||||
__llvm_libc::frexpl(FPBits::negZero(), &exponent));
|
||||
EXPECT_EQ(exponent, 0);
|
||||
|
||||
EXPECT_TRUE(
|
||||
FPBits(__llvm_libc::frexpl(FPBits::buildNaN(1), &exponent)).isNaN());
|
||||
}
|
||||
|
||||
TEST(FrexplTest, PowersOfTwo) {
|
||||
int exponent;
|
||||
|
||||
EXPECT_TRUE(0.5l == __llvm_libc::frexpl(1.0l, &exponent));
|
||||
EXPECT_EQ(exponent, 1);
|
||||
EXPECT_TRUE(-0.5l == __llvm_libc::frexpl(-1.0l, &exponent));
|
||||
EXPECT_EQ(exponent, 1);
|
||||
|
||||
EXPECT_TRUE(0.5l == __llvm_libc::frexpl(2.0l, &exponent));
|
||||
EXPECT_EQ(exponent, 2);
|
||||
EXPECT_TRUE(-0.5l == __llvm_libc::frexpl(-2.0l, &exponent));
|
||||
EXPECT_EQ(exponent, 2);
|
||||
|
||||
EXPECT_TRUE(0.5l == __llvm_libc::frexpl(4.0l, &exponent));
|
||||
EXPECT_EQ(exponent, 3);
|
||||
EXPECT_TRUE(-0.5l == __llvm_libc::frexpl(-4.0l, &exponent));
|
||||
EXPECT_EQ(exponent, 3);
|
||||
|
||||
EXPECT_TRUE(0.5l == __llvm_libc::frexpl(8.0l, &exponent));
|
||||
EXPECT_EQ(exponent, 4);
|
||||
EXPECT_TRUE(-0.5l == __llvm_libc::frexpl(-8.0l, &exponent));
|
||||
EXPECT_EQ(exponent, 4);
|
||||
|
||||
EXPECT_TRUE(0.5l == __llvm_libc::frexpl(16.0l, &exponent));
|
||||
EXPECT_EQ(exponent, 5);
|
||||
EXPECT_TRUE(-0.5l == __llvm_libc::frexpl(-16.0l, &exponent));
|
||||
EXPECT_EQ(exponent, 5);
|
||||
|
||||
EXPECT_TRUE(0.5l == __llvm_libc::frexpl(32.0l, &exponent));
|
||||
EXPECT_EQ(exponent, 6);
|
||||
EXPECT_TRUE(-0.5l == __llvm_libc::frexpl(-32.0l, &exponent));
|
||||
EXPECT_EQ(exponent, 6);
|
||||
}
|
||||
|
||||
TEST(FrexplTest, SomeIntegers) {
|
||||
int exponent;
|
||||
|
||||
EXPECT_TRUE(0.75l == __llvm_libc::frexpl(24.0l, &exponent));
|
||||
EXPECT_EQ(exponent, 5);
|
||||
EXPECT_TRUE(-0.75l == __llvm_libc::frexpl(-24.0l, &exponent));
|
||||
EXPECT_EQ(exponent, 5);
|
||||
|
||||
EXPECT_TRUE(0.625l == __llvm_libc::frexpl(40.0l, &exponent));
|
||||
EXPECT_EQ(exponent, 6);
|
||||
EXPECT_TRUE(-0.625l == __llvm_libc::frexpl(-40.0l, &exponent));
|
||||
EXPECT_EQ(exponent, 6);
|
||||
|
||||
EXPECT_TRUE(0.78125l == __llvm_libc::frexpl(800.0l, &exponent));
|
||||
EXPECT_EQ(exponent, 10);
|
||||
EXPECT_TRUE(-0.78125l == __llvm_libc::frexpl(-800.0l, &exponent));
|
||||
EXPECT_EQ(exponent, 10);
|
||||
}
|
||||
|
||||
TEST(FrexplTest, LongDoubleRange) {
|
||||
using UIntType = FPBits::UIntType;
|
||||
constexpr UIntType count = 10000000;
|
||||
constexpr UIntType step = UIntType(-1) / count;
|
||||
for (UIntType i = 0, v = 0; i <= count; ++i, v += step) {
|
||||
long double x = FPBits(v);
|
||||
if (isnan(x) || isinf(x) || x == 0.0l)
|
||||
continue;
|
||||
|
||||
int exponent;
|
||||
long double frac = __llvm_libc::frexpl(x, &exponent);
|
||||
|
||||
ASSERT_TRUE(__llvm_libc::fputil::abs(frac) < 1.0l);
|
||||
ASSERT_TRUE(__llvm_libc::fputil::abs(frac) >= 0.5l);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
//===-- Unittests for logbl -----------------------------------------------===//
|
||||
//
|
||||
// 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/logbl.h"
|
||||
#include "utils/FPUtil/FPBits.h"
|
||||
#include "utils/FPUtil/ManipulationFunctions.h"
|
||||
#include "utils/UnitTest/Test.h"
|
||||
|
||||
using FPBits = __llvm_libc::fputil::FPBits<long double>;
|
||||
|
||||
TEST(logblTest, SpecialNumbers) {
|
||||
EXPECT_TRUE(FPBits::inf() == __llvm_libc::logbl(FPBits::inf()));
|
||||
EXPECT_TRUE(FPBits::inf() == __llvm_libc::logbl(FPBits::negInf()));
|
||||
|
||||
EXPECT_TRUE(FPBits::negInf() == __llvm_libc::logbl(FPBits::zero()));
|
||||
EXPECT_TRUE(FPBits::negInf() == __llvm_libc::logbl(FPBits::negZero()));
|
||||
|
||||
EXPECT_TRUE(FPBits(__llvm_libc::logbl(FPBits::buildNaN(1))).isNaN());
|
||||
}
|
||||
|
||||
TEST(logblTest, PowersOfTwo) {
|
||||
EXPECT_TRUE(0.0l == __llvm_libc::logbl(1.0l));
|
||||
EXPECT_TRUE(0.0l == __llvm_libc::logbl(-1.0l));
|
||||
|
||||
EXPECT_TRUE(1.0l == __llvm_libc::logbl(2.0l));
|
||||
EXPECT_TRUE(1.0l == __llvm_libc::logbl(-2.0l));
|
||||
|
||||
EXPECT_TRUE(2.0l == __llvm_libc::logbl(4.0l));
|
||||
EXPECT_TRUE(2.0l == __llvm_libc::logbl(-4.0l));
|
||||
|
||||
EXPECT_TRUE(3.0l == __llvm_libc::logbl(8.0l));
|
||||
EXPECT_TRUE(3.0l == __llvm_libc::logbl(-8.0l));
|
||||
|
||||
EXPECT_TRUE(4.0l == __llvm_libc::logbl(16.0l));
|
||||
EXPECT_TRUE(4.0l == __llvm_libc::logbl(-16.0l));
|
||||
|
||||
EXPECT_TRUE(5.0l == __llvm_libc::logbl(32.0l));
|
||||
EXPECT_TRUE(5.0l == __llvm_libc::logbl(-32.0l));
|
||||
}
|
||||
|
||||
TEST(LogbTest, SomeIntegers) {
|
||||
EXPECT_TRUE(1.0l == __llvm_libc::logbl(3.0l));
|
||||
EXPECT_TRUE(1.0l == __llvm_libc::logbl(-3.0l));
|
||||
|
||||
EXPECT_TRUE(2.0l == __llvm_libc::logbl(7.0l));
|
||||
EXPECT_TRUE(2.0l == __llvm_libc::logbl(-7.0l));
|
||||
|
||||
EXPECT_TRUE(3.0l == __llvm_libc::logbl(10.0l));
|
||||
EXPECT_TRUE(3.0l == __llvm_libc::logbl(-10.0l));
|
||||
|
||||
EXPECT_TRUE(4.0l == __llvm_libc::logbl(31.0l));
|
||||
EXPECT_TRUE(4.0l == __llvm_libc::logbl(-31.0l));
|
||||
|
||||
EXPECT_TRUE(5.0l == __llvm_libc::logbl(55.0l));
|
||||
EXPECT_TRUE(5.0l == __llvm_libc::logbl(-55.0l));
|
||||
}
|
||||
|
||||
TEST(LogblTest, LongDoubleRange) {
|
||||
using UIntType = FPBits::UIntType;
|
||||
constexpr UIntType count = 10000000;
|
||||
constexpr UIntType step = UIntType(-1) / count;
|
||||
for (UIntType i = 0, v = 0; i <= count; ++i, v += step) {
|
||||
long double x = FPBits(v);
|
||||
if (isnan(x) || isinf(x) || x == 0.0l)
|
||||
continue;
|
||||
|
||||
int exponent;
|
||||
__llvm_libc::fputil::frexp(x, exponent);
|
||||
ASSERT_TRUE((long double)(exponent) == __llvm_libc::logbl(x) + 1.0l);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
//===-- Unittests for modfl -----------------------------------------------===//
|
||||
//
|
||||
// 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/modfl.h"
|
||||
#include "utils/FPUtil/BasicOperations.h"
|
||||
#include "utils/FPUtil/FPBits.h"
|
||||
#include "utils/FPUtil/NearestIntegerOperations.h"
|
||||
#include "utils/UnitTest/Test.h"
|
||||
|
||||
using FPBits = __llvm_libc::fputil::FPBits<long double>;
|
||||
|
||||
TEST(modflTest, SpecialNumbers) {
|
||||
long double integral;
|
||||
|
||||
EXPECT_TRUE(FPBits::zero() == __llvm_libc::modfl(FPBits::inf(), &integral));
|
||||
EXPECT_TRUE(FPBits::inf() == integral);
|
||||
|
||||
EXPECT_TRUE(FPBits::negZero() ==
|
||||
__llvm_libc::modfl(FPBits::negInf(), &integral));
|
||||
EXPECT_TRUE(FPBits::negInf() == integral);
|
||||
|
||||
EXPECT_TRUE(FPBits::zero() == __llvm_libc::modfl(FPBits::zero(), &integral));
|
||||
EXPECT_TRUE(integral == 0.0l);
|
||||
|
||||
EXPECT_TRUE(FPBits::negZero() ==
|
||||
__llvm_libc::modfl(FPBits::negZero(), &integral));
|
||||
EXPECT_TRUE(integral == 0.0l);
|
||||
|
||||
EXPECT_TRUE(
|
||||
FPBits(__llvm_libc::modfl(FPBits::buildNaN(1), &integral)).isNaN());
|
||||
}
|
||||
|
||||
TEST(modflTest, Integers) {
|
||||
long double integral;
|
||||
|
||||
EXPECT_TRUE(FPBits::zero() == __llvm_libc::modfl(1.0l, &integral));
|
||||
EXPECT_TRUE(integral == 1.0l);
|
||||
|
||||
EXPECT_TRUE(FPBits::negZero() == __llvm_libc::modfl(-1.0l, &integral));
|
||||
EXPECT_TRUE(integral == -1.0l);
|
||||
|
||||
EXPECT_TRUE(FPBits::zero() == __llvm_libc::modfl(10.0l, &integral));
|
||||
EXPECT_TRUE(integral == 10.0l);
|
||||
|
||||
EXPECT_TRUE(FPBits::negZero() == __llvm_libc::modfl(-10.0l, &integral));
|
||||
EXPECT_TRUE(integral == -10.0l);
|
||||
|
||||
EXPECT_TRUE(FPBits::zero() == __llvm_libc::modfl(12345.0l, &integral));
|
||||
EXPECT_TRUE(integral == 12345.0l);
|
||||
|
||||
EXPECT_TRUE(FPBits::negZero() == __llvm_libc::modfl(-12345.0l, &integral));
|
||||
EXPECT_TRUE(integral == -12345.0l);
|
||||
}
|
||||
|
||||
TEST(ModfTest, Fractions) {
|
||||
long double integral;
|
||||
|
||||
EXPECT_TRUE(0.5l == __llvm_libc::modfl(1.5l, &integral));
|
||||
EXPECT_TRUE(integral == 1.0l);
|
||||
|
||||
EXPECT_TRUE(-0.5l == __llvm_libc::modfl(-1.5l, &integral));
|
||||
EXPECT_TRUE(integral == -1.0l);
|
||||
|
||||
EXPECT_TRUE(0.75l == __llvm_libc::modfl(10.75l, &integral));
|
||||
EXPECT_TRUE(integral == 10.0l);
|
||||
|
||||
EXPECT_TRUE(-0.75l == __llvm_libc::modfl(-10.75l, &integral));
|
||||
EXPECT_TRUE(integral == -10.0l);
|
||||
|
||||
EXPECT_TRUE(0.125l == __llvm_libc::modfl(100.125l, &integral));
|
||||
EXPECT_TRUE(integral == 100.0l);
|
||||
|
||||
EXPECT_TRUE(-0.125l == __llvm_libc::modfl(-100.125l, &integral));
|
||||
EXPECT_TRUE(integral == -100.0l);
|
||||
}
|
||||
|
||||
TEST(ModflTest, LongDoubleRange) {
|
||||
using UIntType = FPBits::UIntType;
|
||||
constexpr UIntType count = 10000000;
|
||||
constexpr UIntType step = UIntType(-1) / count;
|
||||
for (UIntType i = 0, v = 0; i <= count; ++i, v += step) {
|
||||
long double x = FPBits(v);
|
||||
if (isnan(x) || isinf(x) || x == 0.0l)
|
||||
continue;
|
||||
|
||||
long double integral;
|
||||
long double frac = __llvm_libc::modfl(x, &integral);
|
||||
ASSERT_TRUE(__llvm_libc::fputil::abs(frac) < 1.0l);
|
||||
ASSERT_TRUE(__llvm_libc::fputil::trunc(x) == integral);
|
||||
ASSERT_TRUE(integral + frac == x);
|
||||
}
|
||||
}
|
|
@ -6,10 +6,7 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "BitPatterns.h"
|
||||
#include "ClassificationFunctions.h"
|
||||
#include "FloatOperations.h"
|
||||
#include "FloatProperties.h"
|
||||
#include "FPBits.h"
|
||||
#include "NearestIntegerOperations.h"
|
||||
|
||||
#include "utils/CPP/TypeTraits.h"
|
||||
|
@ -20,52 +17,87 @@
|
|||
namespace __llvm_libc {
|
||||
namespace fputil {
|
||||
|
||||
template <typename T,
|
||||
cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
|
||||
static inline T frexp(T x, int &exp) {
|
||||
using Properties = FloatProperties<T>;
|
||||
using BitsType = typename Properties::BitsType;
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
template <typename T> struct Standard754Type {
|
||||
static constexpr bool Value =
|
||||
cpp::IsSame<float, cpp::RemoveCVType<T>>::Value ||
|
||||
cpp::IsSame<double, cpp::RemoveCVType<T>>::Value;
|
||||
};
|
||||
#else
|
||||
template <typename T> struct Standard754Type {
|
||||
static constexpr bool Value = cpp::IsFloatingPointType<T>::Value;
|
||||
};
|
||||
#endif
|
||||
|
||||
auto bits = valueAsBits(x);
|
||||
if (bitsAreInfOrNaN(bits))
|
||||
template <typename T> static inline T frexp_impl(FPBits<T> &bits, int &exp) {
|
||||
exp = bits.getExponent() + 1;
|
||||
static constexpr uint16_t resultExponent = FPBits<T>::exponentBias - 1;
|
||||
bits.exponent = resultExponent;
|
||||
return bits;
|
||||
}
|
||||
|
||||
template <typename T, cpp::EnableIfType<Standard754Type<T>::Value, int> = 0>
|
||||
static inline T frexp(T x, int &exp) {
|
||||
FPBits<T> bits(x);
|
||||
if (bits.isInfOrNaN())
|
||||
return x;
|
||||
if (bitsAreZero(bits)) {
|
||||
if (bits.isZero()) {
|
||||
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);
|
||||
return frexp_impl(bits, exp);
|
||||
}
|
||||
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
static inline long double frexp(long double x, int &exp) {
|
||||
FPBits<long double> bits(x);
|
||||
if (bits.isInfOrNaN())
|
||||
return x;
|
||||
if (bits.isZero()) {
|
||||
exp = 0;
|
||||
return x;
|
||||
}
|
||||
|
||||
if (bits.exponent != 0 || bits.implicitBit == 1)
|
||||
return frexp_impl(bits, exp);
|
||||
|
||||
exp = bits.getExponent();
|
||||
int shiftCount = 0;
|
||||
uint64_t fullMantissa = *reinterpret_cast<uint64_t *>(&bits);
|
||||
static constexpr uint64_t msBitMask = uint64_t(1) << 63;
|
||||
for (; (fullMantissa & msBitMask) == uint64_t(0);
|
||||
fullMantissa <<= 1, ++shiftCount) {
|
||||
// This for loop will terminate as fullMantissa is != 0. If it were 0,
|
||||
// then x will be NaN and handled before control reaches here.
|
||||
// When the loop terminates, fullMantissa will represent the full mantissa
|
||||
// of a normal long double value. That is, the implicit bit has the value
|
||||
// of 1.
|
||||
}
|
||||
|
||||
exp = exp - shiftCount + 1;
|
||||
*reinterpret_cast<uint64_t *>(&bits) = fullMantissa;
|
||||
bits.exponent = FPBits<long double>::exponentBias - 1;
|
||||
return bits;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename T,
|
||||
cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
|
||||
static inline T modf(T x, T &iptr) {
|
||||
auto bits = valueAsBits(x);
|
||||
if (bitsAreZero(bits) || bitsAreNaN(bits)) {
|
||||
FPBits<T> bits(x);
|
||||
if (bits.isZero() || bits.isNaN()) {
|
||||
iptr = x;
|
||||
return x;
|
||||
} else if (bitsAreInf(bits)) {
|
||||
} else if (bits.isInf()) {
|
||||
iptr = x;
|
||||
return bits & FloatProperties<T>::signMask
|
||||
? valueFromBits(BitPatterns<T>::negZero)
|
||||
: valueFromBits(BitPatterns<T>::zero);
|
||||
return bits.sign ? FPBits<T>::negZero() : FPBits<T>::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<T>::signMask
|
||||
? valueFromBits(BitPatterns<T>::negZero)
|
||||
: valueFromBits(BitPatterns<T>::zero);
|
||||
return bits.sign ? FPBits<T>::negZero() : FPBits<T>::zero();
|
||||
} else {
|
||||
return x - iptr;
|
||||
}
|
||||
|
@ -75,29 +107,66 @@ static inline T modf(T x, T &iptr) {
|
|||
template <typename T,
|
||||
cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
|
||||
static inline T copysign(T x, T y) {
|
||||
constexpr auto signMask = FloatProperties<T>::signMask;
|
||||
auto xbits = valueAsBits(x);
|
||||
auto ybits = valueAsBits(y);
|
||||
return valueFromBits((xbits & ~signMask) | (ybits & signMask));
|
||||
FPBits<T> xbits(x);
|
||||
xbits.sign = FPBits<T>(y).sign;
|
||||
return xbits;
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
|
||||
template <typename T> static inline T logb_impl(const FPBits<T> &bits) {
|
||||
return bits.getExponent();
|
||||
}
|
||||
|
||||
template <typename T, cpp::EnableIfType<Standard754Type<T>::Value, int> = 0>
|
||||
static inline T logb(T x) {
|
||||
auto bits = valueAsBits(x);
|
||||
if (bitsAreZero(bits)) {
|
||||
FPBits<T> bits(x);
|
||||
if (bits.isZero()) {
|
||||
// TODO(Floating point exception): Raise div-by-zero exception.
|
||||
// TODO(errno): POSIX requires setting errno to ERANGE.
|
||||
return valueFromBits(BitPatterns<T>::negInf);
|
||||
} else if (bitsAreInf(bits)) {
|
||||
return valueFromBits(BitPatterns<T>::inf);
|
||||
} else if (bitsAreNaN(bits)) {
|
||||
return FPBits<T>::negInf();
|
||||
} else if (bits.isNaN()) {
|
||||
return x;
|
||||
} else {
|
||||
return getExponentFromBits(bits);
|
||||
} else if (bits.isInf()) {
|
||||
// Return positive infinity.
|
||||
return FPBits<T>::inf();
|
||||
}
|
||||
|
||||
return logb_impl(bits);
|
||||
}
|
||||
|
||||
#if defined(__x86_64__) || defined(__i386__)
|
||||
static inline long double logb(long double x) {
|
||||
FPBits<long double> bits(x);
|
||||
if (bits.isZero()) {
|
||||
// TODO(Floating point exception): Raise div-by-zero exception.
|
||||
// TODO(errno): POSIX requires setting errno to ERANGE.
|
||||
return FPBits<long double>::negInf();
|
||||
} else if (bits.isNaN()) {
|
||||
return x;
|
||||
} else if (bits.isInf()) {
|
||||
// Return positive infinity.
|
||||
return FPBits<long double>::inf();
|
||||
}
|
||||
|
||||
if (bits.exponent != 0 || bits.implicitBit == 1)
|
||||
return logb_impl(bits);
|
||||
|
||||
int exp = bits.getExponent();
|
||||
int shiftCount = 0;
|
||||
uint64_t fullMantissa = *reinterpret_cast<uint64_t *>(&bits);
|
||||
static constexpr uint64_t msBitMask = uint64_t(1) << 63;
|
||||
for (; (fullMantissa & msBitMask) == uint64_t(0);
|
||||
fullMantissa <<= 1, ++shiftCount) {
|
||||
// This for loop will terminate as fullMantissa is != 0. If it were 0,
|
||||
// then x will be NaN and handled before control reaches here.
|
||||
// When the loop terminates, fullMantissa will represent the full mantissa
|
||||
// of a normal long double value. That is, the implicit bit has the value
|
||||
// of 1.
|
||||
}
|
||||
|
||||
return exp - shiftCount;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace fputil
|
||||
} // namespace __llvm_libc
|
||||
|
||||
|
|
Loading…
Reference in New Issue