[libc] Add implementations of ceil[f], floor[f] and trunc[f] from math.h.

Reviewers: abrachet

Differential Revision: https://reviews.llvm.org/D80612
This commit is contained in:
Siva Chandra Reddy 2020-05-18 15:06:01 -07:00
parent 26c78e3095
commit 1caedd0c55
25 changed files with 948 additions and 8 deletions

View File

@ -50,14 +50,20 @@ add_entrypoint_library(
llvmlibm
DEPENDS
# math.h entrypoints
libc.src.math.ceil
libc.src.math.ceilf
libc.src.math.cosf
libc.src.math.fabs
libc.src.math.fabsf
libc.src.math.floor
libc.src.math.floorf
libc.src.math.expf
libc.src.math.exp2f
libc.src.math.round
libc.src.math.sincosf
libc.src.math.sinf
libc.src.math.trunc
libc.src.math.truncf
)
add_redirector_library(

View File

@ -91,6 +91,66 @@ add_entrypoint_object(
libc.utils.FPUtil.fputil
)
add_entrypoint_object(
trunc
SRCS
trunc.cpp
HDRS
trunc.h
DEPENDS
libc.utils.FPUtil.fputil
)
add_entrypoint_object(
truncf
SRCS
truncf.cpp
HDRS
truncf.h
DEPENDS
libc.utils.FPUtil.fputil
)
add_entrypoint_object(
ceil
SRCS
ceil.cpp
HDRS
ceil.h
DEPENDS
libc.utils.FPUtil.fputil
)
add_entrypoint_object(
ceilf
SRCS
ceilf.cpp
HDRS
ceilf.h
DEPENDS
libc.utils.FPUtil.fputil
)
add_entrypoint_object(
floor
SRCS
floor.cpp
HDRS
floor.h
DEPENDS
libc.utils.FPUtil.fputil
)
add_entrypoint_object(
floorf
SRCS
floorf.cpp
HDRS
floorf.h
DEPENDS
libc.utils.FPUtil.fputil
)
add_object_library(
exp_utils
HDRS

16
libc/src/math/ceil.cpp Normal file
View File

@ -0,0 +1,16 @@
//===-- Implementation of ceil 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/FloatOperations.h"
namespace __llvm_libc {
double LLVM_LIBC_ENTRYPOINT(ceil)(double x) { return fputil::ceil(x); }
} // namespace __llvm_libc

18
libc/src/math/ceil.h Normal file
View File

@ -0,0 +1,18 @@
//===-- Implementation header for ceil --------------------------*- 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_CEIL_H
#define LLVM_LIBC_SRC_MATH_CEIL_H
namespace __llvm_libc {
double ceil(double x);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_MATH_CEIL_H

16
libc/src/math/ceilf.cpp Normal file
View File

@ -0,0 +1,16 @@
//===-- Implementation of ceilf 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/FloatOperations.h"
namespace __llvm_libc {
float LLVM_LIBC_ENTRYPOINT(ceilf)(float x) { return fputil::ceil(x); }
} // namespace __llvm_libc

18
libc/src/math/ceilf.h Normal file
View File

@ -0,0 +1,18 @@
//===-- Implementation header for ceilf -------------------------*- 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_CEILF_H
#define LLVM_LIBC_SRC_MATH_CEILF_H
namespace __llvm_libc {
float ceilf(float x);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_MATH_CEILF_H

16
libc/src/math/floor.cpp Normal file
View File

@ -0,0 +1,16 @@
//===-- Implementation of floor 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/FloatOperations.h"
namespace __llvm_libc {
double LLVM_LIBC_ENTRYPOINT(floor)(double x) { return fputil::floor(x); }
} // namespace __llvm_libc

18
libc/src/math/floor.h Normal file
View File

@ -0,0 +1,18 @@
//===-- Implementation header for floor -------------------------*- 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_FLOOR_H
#define LLVM_LIBC_SRC_MATH_FLOOR_H
namespace __llvm_libc {
double floor(double x);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_MATH_FLOOR_H

16
libc/src/math/floorf.cpp Normal file
View File

@ -0,0 +1,16 @@
//===-- Implementation of floorf 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/FloatOperations.h"
namespace __llvm_libc {
float LLVM_LIBC_ENTRYPOINT(floorf)(float x) { return fputil::floor(x); }
} // namespace __llvm_libc

18
libc/src/math/floorf.h Normal file
View File

@ -0,0 +1,18 @@
//===-- Implementation header for floorf ------------------------*- 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_FLOORF_H
#define LLVM_LIBC_SRC_MATH_FLOORF_H
namespace __llvm_libc {
float floorf(float x);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_MATH_FLOORF_H

16
libc/src/math/trunc.cpp Normal file
View File

@ -0,0 +1,16 @@
//===-- Implementation of trunc 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/FloatOperations.h"
namespace __llvm_libc {
double LLVM_LIBC_ENTRYPOINT(trunc)(double x) { return fputil::trunc(x); }
} // namespace __llvm_libc

18
libc/src/math/trunc.h Normal file
View File

@ -0,0 +1,18 @@
//===-- Implementation header for trunc -------------------------*- 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_TRUNC_H
#define LLVM_LIBC_SRC_MATH_TRUNC_H
namespace __llvm_libc {
double trunc(double x);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_MATH_TRUNC_H

16
libc/src/math/truncf.cpp Normal file
View File

@ -0,0 +1,16 @@
//===-- Implementation of truncf 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/FloatOperations.h"
namespace __llvm_libc {
float LLVM_LIBC_ENTRYPOINT(truncf)(float x) { return fputil::trunc(x); }
} // namespace __llvm_libc

18
libc/src/math/truncf.h Normal file
View File

@ -0,0 +1,18 @@
//===-- Implementation header for truncf ------------------------*- 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_TRUNCF_H
#define LLVM_LIBC_SRC_MATH_TRUNCF_H
namespace __llvm_libc {
float truncf(float x);
} // namespace __llvm_libc
#endif // LLVM_LIBC_SRC_MATH_TRUNCF_H

View File

@ -97,6 +97,84 @@ add_math_unittest(
libc.utils.FPUtil.fputil
)
add_math_unittest(
trunc_test
NEED_MPFR
SUITE
libc_math_unittests
SRCS
trunc_test.cpp
DEPENDS
libc.include.math
libc.src.math.trunc
libc.utils.FPUtil.fputil
)
add_math_unittest(
truncf_test
NEED_MPFR
SUITE
libc_math_unittests
SRCS
truncf_test.cpp
DEPENDS
libc.include.math
libc.src.math.truncf
libc.utils.FPUtil.fputil
)
add_math_unittest(
ceil_test
NEED_MPFR
SUITE
libc_math_unittests
SRCS
ceil_test.cpp
DEPENDS
libc.include.math
libc.src.math.ceil
libc.utils.FPUtil.fputil
)
add_math_unittest(
ceilf_test
NEED_MPFR
SUITE
libc_math_unittests
SRCS
ceilf_test.cpp
DEPENDS
libc.include.math
libc.src.math.ceilf
libc.utils.FPUtil.fputil
)
add_math_unittest(
floor_test
NEED_MPFR
SUITE
libc_math_unittests
SRCS
floor_test.cpp
DEPENDS
libc.include.math
libc.src.math.floor
libc.utils.FPUtil.fputil
)
add_math_unittest(
floorf_test
NEED_MPFR
SUITE
libc_math_unittests
SRCS
floorf_test.cpp
DEPENDS
libc.include.math
libc.src.math.floorf
libc.utils.FPUtil.fputil
)
add_math_unittest(
expf_test
NEED_MPFR

View File

@ -0,0 +1,75 @@
//===-- Unittests for ceil ------------------------------------------------===//
//
// 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/ceil.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<double>;
using Properties = __llvm_libc::fputil::FloatProperties<double>;
namespace mpfr = __llvm_libc::testing::mpfr;
// Zero tolerance; As in, exact match with MPFR result.
static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::doublePrecision, 0,
0};
TEST(ceilTest, SpecialNumbers) {
EXPECT_EQ(
BitPatterns::aQuietNaN,
valueAsBits(__llvm_libc::ceil(valueFromBits(BitPatterns::aQuietNaN))));
EXPECT_EQ(BitPatterns::aNegativeQuietNaN,
valueAsBits(__llvm_libc::ceil(
valueFromBits(BitPatterns::aNegativeQuietNaN))));
EXPECT_EQ(BitPatterns::aSignallingNaN,
valueAsBits(
__llvm_libc::ceil(valueFromBits(BitPatterns::aSignallingNaN))));
EXPECT_EQ(BitPatterns::aNegativeSignallingNaN,
valueAsBits(__llvm_libc::ceil(
valueFromBits(BitPatterns::aNegativeSignallingNaN))));
EXPECT_EQ(BitPatterns::inf,
valueAsBits(__llvm_libc::ceil(valueFromBits(BitPatterns::inf))));
EXPECT_EQ(BitPatterns::negInf,
valueAsBits(__llvm_libc::ceil(valueFromBits(BitPatterns::negInf))));
EXPECT_EQ(BitPatterns::zero,
valueAsBits(__llvm_libc::ceil(valueFromBits(BitPatterns::zero))));
EXPECT_EQ(BitPatterns::negZero, valueAsBits(__llvm_libc::ceil(
valueFromBits(BitPatterns::negZero))));
}
TEST(ceilTest, RoundedNumbers) {
EXPECT_EQ(valueAsBits(1.0), valueAsBits(__llvm_libc::ceil(1.0)));
EXPECT_EQ(valueAsBits(-1.0), valueAsBits(__llvm_libc::ceil(-1.0)));
EXPECT_EQ(valueAsBits(10.0), valueAsBits(__llvm_libc::ceil(10.0)));
EXPECT_EQ(valueAsBits(-10.0), valueAsBits(__llvm_libc::ceil(-10.0)));
EXPECT_EQ(valueAsBits(12345.0), valueAsBits(__llvm_libc::ceil(12345.0)));
EXPECT_EQ(valueAsBits(-12345.0), valueAsBits(__llvm_libc::ceil(-12345.0)));
}
TEST(ceilTest, 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))
continue;
ASSERT_MPFR_MATCH(mpfr::Operation::Ceil, x, __llvm_libc::ceil(x),
tolerance);
}
}

View File

@ -0,0 +1,75 @@
//===-- Unittests for ceilf -----------------------------------------------===//
//
// 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/ceilf.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<float>;
using Properties = __llvm_libc::fputil::FloatProperties<float>;
namespace mpfr = __llvm_libc::testing::mpfr;
// Zero tolerance; As in, exact match with MPFR result.
static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::doublePrecision, 0,
0};
TEST(CeilfTest, SpecialNumbers) {
EXPECT_EQ(
BitPatterns::aQuietNaN,
valueAsBits(__llvm_libc::ceilf(valueFromBits(BitPatterns::aQuietNaN))));
EXPECT_EQ(BitPatterns::aNegativeQuietNaN,
valueAsBits(__llvm_libc::ceilf(
valueFromBits(BitPatterns::aNegativeQuietNaN))));
EXPECT_EQ(BitPatterns::aSignallingNaN,
valueAsBits(__llvm_libc::ceilf(
valueFromBits(BitPatterns::aSignallingNaN))));
EXPECT_EQ(BitPatterns::aNegativeSignallingNaN,
valueAsBits(__llvm_libc::ceilf(
valueFromBits(BitPatterns::aNegativeSignallingNaN))));
EXPECT_EQ(BitPatterns::inf,
valueAsBits(__llvm_libc::ceilf(valueFromBits(BitPatterns::inf))));
EXPECT_EQ(BitPatterns::negInf, valueAsBits(__llvm_libc::ceilf(
valueFromBits(BitPatterns::negInf))));
EXPECT_EQ(BitPatterns::zero,
valueAsBits(__llvm_libc::ceilf(valueFromBits(BitPatterns::zero))));
EXPECT_EQ(BitPatterns::negZero, valueAsBits(__llvm_libc::ceilf(
valueFromBits(BitPatterns::negZero))));
}
TEST(ceilfTest, RoundedNumbers) {
EXPECT_EQ(valueAsBits(1.0f), valueAsBits(__llvm_libc::ceilf(1.0f)));
EXPECT_EQ(valueAsBits(-1.0f), valueAsBits(__llvm_libc::ceilf(-1.0f)));
EXPECT_EQ(valueAsBits(10.0f), valueAsBits(__llvm_libc::ceilf(10.0f)));
EXPECT_EQ(valueAsBits(-10.0f), valueAsBits(__llvm_libc::ceilf(-10.0f)));
EXPECT_EQ(valueAsBits(12345.0f), valueAsBits(__llvm_libc::ceilf(12345.0f)));
EXPECT_EQ(valueAsBits(-12345.0f), valueAsBits(__llvm_libc::ceilf(-12345.0f)));
}
TEST(ceilfTest, 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) {
double x = valueFromBits(v);
if (isnan(x) || isinf(x))
continue;
ASSERT_MPFR_MATCH(mpfr::Operation::Ceil, x, __llvm_libc::ceilf(x),
tolerance);
}
}

View File

@ -0,0 +1,75 @@
//===-- Unittests for floor -----------------------------------------------===//
//
// 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/floor.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<double>;
using Properties = __llvm_libc::fputil::FloatProperties<double>;
namespace mpfr = __llvm_libc::testing::mpfr;
// Zero tolerance; As in, exact match with MPFR result.
static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::doublePrecision, 0,
0};
TEST(FloorTest, SpecialNumbers) {
EXPECT_EQ(
BitPatterns::aQuietNaN,
valueAsBits(__llvm_libc::floor(valueFromBits(BitPatterns::aQuietNaN))));
EXPECT_EQ(BitPatterns::aNegativeQuietNaN,
valueAsBits(__llvm_libc::floor(
valueFromBits(BitPatterns::aNegativeQuietNaN))));
EXPECT_EQ(BitPatterns::aSignallingNaN,
valueAsBits(__llvm_libc::floor(
valueFromBits(BitPatterns::aSignallingNaN))));
EXPECT_EQ(BitPatterns::aNegativeSignallingNaN,
valueAsBits(__llvm_libc::floor(
valueFromBits(BitPatterns::aNegativeSignallingNaN))));
EXPECT_EQ(BitPatterns::inf,
valueAsBits(__llvm_libc::floor(valueFromBits(BitPatterns::inf))));
EXPECT_EQ(BitPatterns::negInf, valueAsBits(__llvm_libc::floor(
valueFromBits(BitPatterns::negInf))));
EXPECT_EQ(BitPatterns::zero,
valueAsBits(__llvm_libc::floor(valueFromBits(BitPatterns::zero))));
EXPECT_EQ(BitPatterns::negZero, valueAsBits(__llvm_libc::floor(
valueFromBits(BitPatterns::negZero))));
}
TEST(floorTest, RoundedNumbers) {
EXPECT_EQ(valueAsBits(1.0), valueAsBits(__llvm_libc::floor(1.0)));
EXPECT_EQ(valueAsBits(-1.0), valueAsBits(__llvm_libc::floor(-1.0)));
EXPECT_EQ(valueAsBits(10.0), valueAsBits(__llvm_libc::floor(10.0)));
EXPECT_EQ(valueAsBits(-10.0), valueAsBits(__llvm_libc::floor(-10.0)));
EXPECT_EQ(valueAsBits(12345.0), valueAsBits(__llvm_libc::floor(12345.0)));
EXPECT_EQ(valueAsBits(-12345.0), valueAsBits(__llvm_libc::floor(-12345.0)));
}
TEST(floorTest, 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))
continue;
ASSERT_MPFR_MATCH(mpfr::Operation::Floor, x, __llvm_libc::floor(x),
tolerance);
}
}

View File

@ -0,0 +1,76 @@
//===-- Unittests for floorf ----------------------------------------------===//
//
// 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/floorf.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<float>;
using Properties = __llvm_libc::fputil::FloatProperties<float>;
namespace mpfr = __llvm_libc::testing::mpfr;
// Zero tolerance; As in, exact match with MPFR result.
static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::doublePrecision, 0,
0};
TEST(FloorfTest, SpecialNumbers) {
EXPECT_EQ(
BitPatterns::aQuietNaN,
valueAsBits(__llvm_libc::floorf(valueFromBits(BitPatterns::aQuietNaN))));
EXPECT_EQ(BitPatterns::aNegativeQuietNaN,
valueAsBits(__llvm_libc::floorf(
valueFromBits(BitPatterns::aNegativeQuietNaN))));
EXPECT_EQ(BitPatterns::aSignallingNaN,
valueAsBits(__llvm_libc::floorf(
valueFromBits(BitPatterns::aSignallingNaN))));
EXPECT_EQ(BitPatterns::aNegativeSignallingNaN,
valueAsBits(__llvm_libc::floorf(
valueFromBits(BitPatterns::aNegativeSignallingNaN))));
EXPECT_EQ(BitPatterns::inf,
valueAsBits(__llvm_libc::floorf(valueFromBits(BitPatterns::inf))));
EXPECT_EQ(BitPatterns::negInf, valueAsBits(__llvm_libc::floorf(
valueFromBits(BitPatterns::negInf))));
EXPECT_EQ(BitPatterns::zero,
valueAsBits(__llvm_libc::floorf(valueFromBits(BitPatterns::zero))));
EXPECT_EQ(BitPatterns::negZero, valueAsBits(__llvm_libc::floorf(
valueFromBits(BitPatterns::negZero))));
}
TEST(floorfTest, RoundedNumbers) {
EXPECT_EQ(valueAsBits(1.0f), valueAsBits(__llvm_libc::floorf(1.0f)));
EXPECT_EQ(valueAsBits(-1.0f), valueAsBits(__llvm_libc::floorf(-1.0f)));
EXPECT_EQ(valueAsBits(10.0f), valueAsBits(__llvm_libc::floorf(10.0f)));
EXPECT_EQ(valueAsBits(-10.0f), valueAsBits(__llvm_libc::floorf(-10.0f)));
EXPECT_EQ(valueAsBits(12345.0f), valueAsBits(__llvm_libc::floorf(12345.0f)));
EXPECT_EQ(valueAsBits(-12345.0f),
valueAsBits(__llvm_libc::floorf(-12345.0f)));
}
TEST(floorfTest, 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) {
double x = valueFromBits(v);
if (isnan(x) || isinf(x))
continue;
ASSERT_MPFR_MATCH(mpfr::Operation::Floor, x, __llvm_libc::floorf(x),
tolerance);
}
}

View File

@ -0,0 +1,75 @@
//===-- Unittests for trunc -----------------------------------------------===//
//
// 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/trunc.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<double>;
using Properties = __llvm_libc::fputil::FloatProperties<double>;
namespace mpfr = __llvm_libc::testing::mpfr;
// Zero tolerance; As in, exact match with MPFR result.
static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::doublePrecision, 0,
0};
TEST(TruncTest, SpecialNumbers) {
EXPECT_EQ(
BitPatterns::aQuietNaN,
valueAsBits(__llvm_libc::trunc(valueFromBits(BitPatterns::aQuietNaN))));
EXPECT_EQ(BitPatterns::aNegativeQuietNaN,
valueAsBits(__llvm_libc::trunc(
valueFromBits(BitPatterns::aNegativeQuietNaN))));
EXPECT_EQ(BitPatterns::aSignallingNaN,
valueAsBits(__llvm_libc::trunc(
valueFromBits(BitPatterns::aSignallingNaN))));
EXPECT_EQ(BitPatterns::aNegativeSignallingNaN,
valueAsBits(__llvm_libc::trunc(
valueFromBits(BitPatterns::aNegativeSignallingNaN))));
EXPECT_EQ(BitPatterns::inf,
valueAsBits(__llvm_libc::trunc(valueFromBits(BitPatterns::inf))));
EXPECT_EQ(BitPatterns::negInf, valueAsBits(__llvm_libc::trunc(
valueFromBits(BitPatterns::negInf))));
EXPECT_EQ(BitPatterns::zero,
valueAsBits(__llvm_libc::trunc(valueFromBits(BitPatterns::zero))));
EXPECT_EQ(BitPatterns::negZero, valueAsBits(__llvm_libc::trunc(
valueFromBits(BitPatterns::negZero))));
}
TEST(TruncTest, RoundedNumbers) {
EXPECT_EQ(valueAsBits(1.0), valueAsBits(__llvm_libc::trunc(1.0)));
EXPECT_EQ(valueAsBits(-1.0), valueAsBits(__llvm_libc::trunc(-1.0)));
EXPECT_EQ(valueAsBits(10.0), valueAsBits(__llvm_libc::trunc(10.0)));
EXPECT_EQ(valueAsBits(-10.0), valueAsBits(__llvm_libc::trunc(-10.0)));
EXPECT_EQ(valueAsBits(12345.0), valueAsBits(__llvm_libc::trunc(12345.0)));
EXPECT_EQ(valueAsBits(-12345.0), valueAsBits(__llvm_libc::trunc(-12345.0)));
}
TEST(truncTest, 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))
continue;
ASSERT_MPFR_MATCH(mpfr::Operation::Trunc, x, __llvm_libc::trunc(x),
tolerance);
}
}

View File

@ -0,0 +1,77 @@
//===-- Unittests for truncf ----------------------------------------------===//
//
// 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/truncf.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<float>;
using Properties = __llvm_libc::fputil::FloatProperties<float>;
namespace mpfr = __llvm_libc::testing::mpfr;
// Zero tolerance; As in, exact match with MPFR result.
static constexpr mpfr::Tolerance tolerance{mpfr::Tolerance::floatPrecision, 0,
0};
namespace mpfr = __llvm_libc::testing::mpfr;
TEST(TruncfTest, SpecialNumbers) {
EXPECT_EQ(
BitPatterns::aQuietNaN,
valueAsBits(__llvm_libc::truncf(valueFromBits(BitPatterns::aQuietNaN))));
EXPECT_EQ(BitPatterns::aNegativeQuietNaN,
valueAsBits(__llvm_libc::truncf(
valueFromBits(BitPatterns::aNegativeQuietNaN))));
EXPECT_EQ(BitPatterns::aSignallingNaN,
valueAsBits(__llvm_libc::truncf(
valueFromBits(BitPatterns::aSignallingNaN))));
EXPECT_EQ(BitPatterns::aNegativeSignallingNaN,
valueAsBits(__llvm_libc::truncf(
valueFromBits(BitPatterns::aNegativeSignallingNaN))));
EXPECT_EQ(BitPatterns::inf,
valueAsBits(__llvm_libc::truncf(valueFromBits(BitPatterns::inf))));
EXPECT_EQ(BitPatterns::negInf, valueAsBits(__llvm_libc::truncf(
valueFromBits(BitPatterns::negInf))));
EXPECT_EQ(BitPatterns::zero,
valueAsBits(__llvm_libc::truncf(valueFromBits(BitPatterns::zero))));
EXPECT_EQ(BitPatterns::negZero, valueAsBits(__llvm_libc::truncf(
valueFromBits(BitPatterns::negZero))));
}
TEST(TruncTest, RoundedNumbers) {
EXPECT_EQ(valueAsBits(1.0f), valueAsBits(__llvm_libc::truncf(1.0f)));
EXPECT_EQ(valueAsBits(-1.0f), valueAsBits(__llvm_libc::truncf(-1.0f)));
EXPECT_EQ(valueAsBits(10.0f), valueAsBits(__llvm_libc::truncf(10.0f)));
EXPECT_EQ(valueAsBits(-10.0f), valueAsBits(__llvm_libc::truncf(-10.0f)));
EXPECT_EQ(valueAsBits(12345.0f), valueAsBits(__llvm_libc::truncf(12345.0f)));
EXPECT_EQ(valueAsBits(-12345.0f),
valueAsBits(__llvm_libc::truncf(-12345.0f)));
}
TEST(truncfTest, 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) {
double x = valueFromBits(v);
if (isnan(x) || isinf(x))
continue;
ASSERT_MPFR_MATCH(mpfr::Operation::Trunc, x, __llvm_libc::truncf(x),
tolerance);
}
}

View File

@ -40,18 +40,23 @@ static inline typename FloatProperties<T>::BitsType absBits(T x) {
return valueAsBits(x) & (~FloatProperties<T>::signMask);
}
// Return the zero adjusted exponent value of x.
template <typename T,
cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
int getExponent(T x) {
using Properties = FloatProperties<T>;
using BitsType = typename Properties::BitsType;
BitsType bits = absBits(x);
template <typename BitsType>
static inline int getExponentFromBits(BitsType bits) {
using FPType = typename FloatType<BitsType>::Type;
using Properties = FloatProperties<FPType>;
bits &= Properties::exponentMask;
int e = (bits >> Properties::mantissaWidth); // Shift out the mantissa.
e -= Properties::exponentOffset; // Zero adjust.
return e;
}
// Return the zero adjusted exponent value of x.
template <typename T,
cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
static inline int getExponent(T x) {
return getExponentFromBits(valueAsBits(x));
}
// Return true if x is infinity (positive or negative.)
template <typename T,
cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
@ -74,6 +79,24 @@ static inline bool isNaN(T x) {
((bits & Properties::mantissaMask) != 0);
}
template <typename BitsType> static inline bool bitsAreInfOrNaN(BitsType bits) {
using FPType = typename FloatType<BitsType>::Type;
return (bits & BitPatterns<FPType>::inf) == BitPatterns<FPType>::inf;
}
template <typename BitsType> static inline bool bitsAreZero(BitsType bits) {
using FPType = typename FloatType<BitsType>::Type;
return (bits == BitPatterns<FPType>::zero) ||
(bits == BitPatterns<FPType>::negZero);
}
// Return true if x is any kind of NaN or infinity.
template <typename T,
cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
static inline bool isInfOrNaN(T x) {
return bitsAreInfOrNaN(valueAsBits(x));
}
// Return true if x is a quiet NAN.
template <typename T,
cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
@ -103,6 +126,94 @@ static inline T abs(T x) {
return valueFromBits(absBits(x));
}
// Return the trucated value of x. If x is non-negative, then the return value
// is greatest integer less than or equal to x. Otherwise, return the smallest
// integer greater than or equal to x. That is, return the integer value rounded
// toward zero.
template <typename T,
cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
static inline T trunc(T x) {
using Properties = FloatProperties<T>;
using BitsType = typename FloatProperties<T>::BitsType;
BitsType bits = valueAsBits(x);
// If x is infinity, NaN or zero, return it.
if (bitsAreInfOrNaN(bits) || bitsAreZero(bits))
return x;
int exponent = getExponentFromBits(bits);
// If the exponent is greater than the most negative mantissa
// exponent, then x is already an integer.
if (exponent >= static_cast<int>(Properties::mantissaWidth))
return x;
// If the exponent is such that abs(x) is less than 1, then return 0.
if (exponent <= -1) {
if (Properties::signMask & bits)
return T(-0.0);
else
return T(0.0);
}
uint32_t trimSize = Properties::mantissaWidth - exponent;
return valueFromBits((bits >> trimSize) << trimSize);
}
template <typename T,
cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
static inline T ceil(T x) {
using Properties = FloatProperties<T>;
using BitsType = typename FloatProperties<T>::BitsType;
BitsType bits = valueAsBits(x);
// If x is infinity NaN or zero, return it.
if (bitsAreInfOrNaN(bits) || bitsAreZero(bits))
return x;
bool isNeg = bits & Properties::signMask;
int exponent = getExponentFromBits(bits);
// If the exponent is greater than the most negative mantissa
// exponent, then x is already an integer.
if (exponent >= static_cast<int>(Properties::mantissaWidth))
return x;
if (exponent <= -1) {
if (isNeg)
return T(-0.0);
else
return T(1.0);
}
uint32_t trimSize = Properties::mantissaWidth - exponent;
// If x is already an integer, return it.
if ((bits << (Properties::bitWidth - trimSize)) == 0)
return x;
BitsType truncBits = (bits >> trimSize) << trimSize;
T truncValue = valueFromBits(truncBits);
// If x is negative, the ceil operation is equivalent to the trunc operation.
if (isNeg)
return truncValue;
return truncValue + T(1.0);
}
template <typename T,
cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
static inline T floor(T x) {
auto bits = valueAsBits(x);
if (FloatProperties<T>::signMask & bits) {
return -ceil(-x);
} else {
return trunc(x);
}
}
} // namespace fputil
} // namespace __llvm_libc

View File

@ -21,9 +21,12 @@ template <> struct FloatProperties<float> {
static_assert(sizeof(BitsType) == sizeof(float),
"Unexpected size of 'float' type.");
static constexpr uint32_t bitWidth = sizeof(BitsType) << 3;
static constexpr uint32_t mantissaWidth = 23;
static constexpr BitsType mantissaMask = 0x007fffffU;
static constexpr BitsType signMask = 0x80000000U;
static constexpr BitsType exponentMask = ~(signMask | mantissaMask);
static constexpr uint32_t exponentOffset = 127;
// If a number x is a NAN, then it is a quiet NAN if:
@ -37,9 +40,12 @@ template <> struct FloatProperties<double> {
static_assert(sizeof(BitsType) == sizeof(double),
"Unexpected size of 'double' type.");
static constexpr uint32_t bitWidth = sizeof(BitsType) << 3;
static constexpr uint32_t mantissaWidth = 52;
static constexpr BitsType mantissaMask = 0x000fffffffffffffU;
static constexpr BitsType signMask = 0x8000000000000000ULL;
static constexpr BitsType exponentMask = ~(signMask | mantissaMask);
static constexpr uint32_t exponentOffset = 1023;
// If a number x is a NAN, then it is a quiet NAN if:

View File

@ -89,6 +89,9 @@ public:
case Operation::Abs:
mpfr_abs(value, mpfrInput.value, MPFR_RNDN);
break;
case Operation::Ceil:
mpfr_ceil(value, mpfrInput.value);
break;
case Operation::Cos:
mpfr_cos(value, mpfrInput.value, MPFR_RNDN);
break;
@ -98,9 +101,18 @@ public:
case Operation::Exp2:
mpfr_exp2(value, mpfrInput.value, MPFR_RNDN);
break;
case Operation::Floor:
mpfr_floor(value, mpfrInput.value);
break;
case Operation::Round:
mpfr_round(value, mpfrInput.value);
break;
case Operation::Sin:
mpfr_sin(value, mpfrInput.value, MPFR_RNDN);
break;
case Operation::Trunc:
mpfr_trunc(value, mpfrInput.value);
break;
}
}

View File

@ -39,7 +39,17 @@ struct Tolerance {
uint32_t bits;
};
enum class Operation : int { Abs, Cos, Exp, Exp2, Sin };
enum class Operation : int {
Abs,
Ceil,
Cos,
Exp,
Exp2,
Floor,
Round,
Sin,
Trunc
};
namespace internal {