41 changes: 41 additions & 0 deletions libc/test/src/math/ilogb_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//===-- Unittests for ilogb -----------------------------------------------===//
//
// 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 "ILogbTest.h"

#include "include/math.h"
#include "src/math/ilogb.h"
#include "utils/CPP/Functional.h"
#include "utils/FPUtil/FPBits.h"
#include "utils/FPUtil/ManipulationFunctions.h"
#include "utils/FPUtil/TestHelpers.h"
#include "utils/UnitTest/Test.h"

#include <limits.h>

using RunContext = __llvm_libc::testing::RunContext;

TEST_F(ILogbTest, SpecialNumbers_ilogb) {
testSpecialNumbers<double>(&__llvm_libc::ilogb);
}

TEST_F(ILogbTest, PowersOfTwo_ilogb) {
testPowersOfTwo<double>(&__llvm_libc::ilogb);
}

TEST_F(ILogbTest, SomeIntegers_ilogb) {
testSomeIntegers<double>(&__llvm_libc::ilogb);
}

TEST_F(ILogbTest, SubnormalRange_ilogb) {
testSubnormalRange<double>(&__llvm_libc::ilogb);
}

TEST_F(ILogbTest, NormalRange_ilogb) {
testNormalRange<double>(&__llvm_libc::ilogb);
}
41 changes: 41 additions & 0 deletions libc/test/src/math/ilogbf_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//===-- Unittests for ilogbf ----------------------------------------------===//
//
// 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 "ILogbTest.h"

#include "include/math.h"
#include "src/math/ilogbf.h"
#include "utils/CPP/Functional.h"
#include "utils/FPUtil/FPBits.h"
#include "utils/FPUtil/ManipulationFunctions.h"
#include "utils/FPUtil/TestHelpers.h"
#include "utils/UnitTest/Test.h"

#include <limits.h>

using RunContext = __llvm_libc::testing::RunContext;

TEST_F(ILogbTest, SpecialNumbers_ilogbf) {
testSpecialNumbers<float>(&__llvm_libc::ilogbf);
}

TEST_F(ILogbTest, PowersOfTwo_ilogbf) {
testPowersOfTwo<float>(&__llvm_libc::ilogbf);
}

TEST_F(ILogbTest, SomeIntegers_ilogbf) {
testSomeIntegers<float>(&__llvm_libc::ilogbf);
}

TEST_F(ILogbTest, SubnormalRange_ilogbf) {
testSubnormalRange<float>(&__llvm_libc::ilogbf);
}

TEST_F(ILogbTest, NormalRange_ilogbf) {
testNormalRange<float>(&__llvm_libc::ilogbf);
}
41 changes: 41 additions & 0 deletions libc/test/src/math/ilogbl_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//===-- Unittests for ilogbl ----------------------------------------------===//
//
// 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 "ILogbTest.h"

#include "include/math.h"
#include "src/math/ilogbl.h"
#include "utils/CPP/Functional.h"
#include "utils/FPUtil/FPBits.h"
#include "utils/FPUtil/ManipulationFunctions.h"
#include "utils/FPUtil/TestHelpers.h"
#include "utils/UnitTest/Test.h"

#include <limits.h>

using RunContext = __llvm_libc::testing::RunContext;

TEST_F(ILogbTest, SpecialNumbers_ilogbl) {
testSpecialNumbers<long double>(&__llvm_libc::ilogbl);
}

TEST_F(ILogbTest, PowersOfTwo_ilogbl) {
testPowersOfTwo<long double>(&__llvm_libc::ilogbl);
}

TEST_F(ILogbTest, SomeIntegers_ilogbl) {
testSomeIntegers<long double>(&__llvm_libc::ilogbl);
}

TEST_F(ILogbTest, SubnormalRange_ilogbl) {
testSubnormalRange<long double>(&__llvm_libc::ilogbl);
}

TEST_F(ILogbTest, NormalRange_ilogbl) {
testNormalRange<long double>(&__llvm_libc::ilogbl);
}
1 change: 1 addition & 0 deletions libc/utils/FPUtil/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ add_header_library(
NearestIntegerOperations.h
NormalFloat.h
DEPENDS
libc.include.math
libc.utils.CPP.standalone_cpp
)

Expand Down
32 changes: 32 additions & 0 deletions libc/utils/FPUtil/ManipulationFunctions.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,11 @@
#include "NearestIntegerOperations.h"
#include "NormalFloat.h"

#include "include/math.h"
#include "utils/CPP/TypeTraits.h"

#include <limits.h>

namespace __llvm_libc {
namespace fputil {

Expand Down Expand Up @@ -65,6 +68,35 @@ static inline T copysign(T x, T y) {
return xbits;
}

template <typename T,
cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
static inline int ilogb(T x) {
// TODO: Raise appropriate floating point exceptions and set errno to the
// an appropriate error value wherever relevant.
FPBits<T> bits(x);
if (bits.isZero()) {
return FP_ILOGB0;
} else if (bits.isNaN()) {
return FP_ILOGBNAN;
} else if (bits.isInf()) {
return INT_MAX;
}

NormalFloat<T> normal(bits);
// The C standard does not specify the return value when an exponent is
// out of int range. However, XSI conformance required that INT_MAX or
// INT_MIN are returned.
// NOTE: It is highly unlikely that exponent will be out of int range as
// the exponent is only 15 bits wide even for the 128-bit floating point
// format.
if (normal.exponent > INT_MAX)
return INT_MAX;
else if (normal.exponent < INT_MIN)
return INT_MIN;
else
return normal.exponent;
}

template <typename T,
cpp::EnableIfType<cpp::IsFloatingPointType<T>::Value, int> = 0>
static inline T logb(T x) {
Expand Down