Skip to content

Commit 0d16ffe

Browse files
committed
Fix integral constant issues with ldexp
Signed-off-by: Ian <[email protected]>
1 parent ce3e691 commit 0d16ffe

File tree

12 files changed

+57
-42
lines changed

12 files changed

+57
-42
lines changed

CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU"
6666
-Wextra
6767
-Wconversion
6868
-Wpedantic
69+
#-Wwrite-strings
70+
-fpermissive # TODO: Figure out how to best remove this
71+
-g3
6972
# Define NOMINMAX only on Windows to avoid conflicts with min/max macros
7073
$<$<BOOL:${WIN32}>:-DNOMINMAX>
7174
)

include/ccmath/internal/config/type_support.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
// actually support __int128.
3131
#ifdef CCM_TYPES_HAS_INT128
3232
#error CCM_TYPES_HAS_INT128 cannot be directly set
33-
#elif defined(__SIZEOF_INT128__)
33+
#elif defined(__SIZEOF_INT128__) && !defined(_WIN32)
3434
#if (defined(__clang__) && !defined(_WIN32)) || (defined(__CUDACC__) && __CUDACC_VER_MAJOR__ >= 9) || \
3535
(defined(__GNUC__) && !defined(__clang__) && !defined(__CUDACC__))
3636
#define CCM_TYPES_HAS_INT128 1

include/ccmath/internal/math/generic/func/power/pow_impl/powf_impl.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -470,7 +470,7 @@ namespace ccm::gen::impl
470470
}
471471

472472
// Scale lower part of 2^(hi + mid)
473-
DoubleDouble exp2_hi_mid_dd;
473+
DoubleDouble exp2_hi_mid_dd{};
474474
exp2_hi_mid_dd.lo =
475475
(idx_y != 0) ? support::bit_cast<double>(exp_hi_i + support::bit_cast<int64_t>(support::constants::EXP2_MID1.at(idx_y).mid)) : 0.0;
476476
exp2_hi_mid_dd.hi = exp2_hi_mid;

include/ccmath/internal/support/bits.hpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,11 @@
2828

2929
namespace ccm::support
3030
{
31+
3132
template <typename To, typename From>
32-
[[nodiscard]] constexpr std::enable_if_t<
33+
inline constexpr std::enable_if_t<
3334
sizeof(To) == sizeof(From) && std::is_trivially_constructible_v<To> && std::is_trivially_copyable_v<To> && std::is_trivially_copyable_v<From>, To>
34-
// ReSharper disable once CppDFAUnreachableFunctionCall
35-
bit_cast(const From & from) noexcept
35+
bit_cast(const From & from)
3636
{
3737
return __builtin_bit_cast(To, from);
3838
}
@@ -45,6 +45,7 @@ namespace ccm::support
4545
}
4646

4747
// TODO: Have the below function replace all other top_bits func.
48+
// TODO: Remove all usages of bit grabbing functions
4849

4950
template <typename T, std::size_t TopBitsToTake, std::enable_if_t<std::is_floating_point_v<T> && !std::is_same_v<T, long double>, bool> = true>
5051
constexpr std::uint32_t top_bits(T x) noexcept

include/ccmath/internal/support/fp/fp_bits.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -848,7 +848,7 @@ namespace ccm::support::fp
848848
constexpr FPBits() = default;
849849

850850
template <typename XType>
851-
constexpr explicit FPBits(XType x)
851+
inline constexpr explicit FPBits(XType x)
852852
{
853853
using UnQual = std::remove_cv_t<XType>;
854854
if constexpr (std::is_same_v<UnQual, T>) { BASE::bits = support::bit_cast<storage_type>(x); }

include/ccmath/internal/support/helpers/internal_ldexp.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ namespace ccm::support::helpers
3131
fp::FPBits<T> bits(x);
3232
if (CCM_UNLIKELY((exp == 0) || bits.is_zero() || bits.is_inf_or_nan())) { return x; }
3333

34-
constexpr int exponent_limit = fp::FPBits<T>::max_biased_exponent + support::fp::FPBits<T>::fraction_length + 1;
34+
constexpr int exponent_limit = fp::FPBits<T>::max_biased_exponent + fp::FPBits<T>::fraction_length + 1;
3535
static_assert(exponent_limit <= INT_MAX && -exponent_limit >= INT_MIN);
3636

3737
// Make sure that we can safely cast exp to int when not returning early.
@@ -70,6 +70,6 @@ namespace ccm::support::helpers
7070
// For all other values, NormalFloat to T conversion handles it the right way.
7171
types::DyadicFloat<fp::FPBits<T>::storage_length> normal(bits.get_val());
7272
normal.exponent += static_cast<int>(exp);
73-
return normal.template as<T, /*ShouldRaiseExceptions=*/true>();
73+
return normal.template as<T, false>();
7474
}
7575
} // namespace ccm::support::helpers

include/ccmath/internal/support/math_support.hpp

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@
1717

1818
#include <climits>
1919

20+
#include "ccmath/internal/predef/compiler_suppression/gcc_compiler_suppression.hpp"
21+
22+
// clang-format off
23+
CCM_DISABLE_GCC_WARNING(-Wpedantic)
24+
// clang-format on
25+
2026
namespace ccm::support
2127
{
2228

@@ -96,15 +102,15 @@ namespace ccm::support
96102
}
97103

98104
#define RETURN_IF(TYPE, BUILTIN) \
99-
if constexpr (std::is_same_v<T, TYPE>) return BUILTIN(a, b, carry_in, carry_out);
105+
if constexpr (std::is_same_v<T, TYPE>) { return BUILTIN(a, b, carry_in, &carry_out); }
100106

101107
// Returns the result of 'a + b' taking into account 'carry_in'.
102108
// The carry out is stored in 'carry_out' it not 'nullptr', dropped otherwise.
103109
// We keep the pass by pointer interface for consistency with the intrinsic.
104110
template <typename T>
105111
[[nodiscard]] constexpr std::enable_if_t<traits::ccm_is_unsigned_v<T>, T> add_with_carry(T a, T b, T carry_in, T & carry_out)
106112
{
107-
if (!is_constant_evaluated())
113+
if constexpr (!is_constant_evaluated())
108114
{
109115
#if CCM_HAS_BUILTIN(__builtin_addcb)
110116
RETURN_IF(unsigned char, __builtin_addcb)
@@ -126,10 +132,10 @@ namespace ccm::support
126132
}
127133

128134
// Returns the result of 'a - b' taking into account 'carry_in'.
129-
// The carry out is stored in 'carry_out' it not 'nullptr', dropped otherwise.
135+
// The carry out is stored in 'carry_out' if not 'nullptr', dropped otherwise.
130136
// We keep the pass by pointer interface for consistency with the intrinsic.
131137
template <typename T>
132-
[[nodiscard]] constexpr std::enable_if_t<traits::ccm_is_unsigned_v<T>, T> sub_with_borrow(T a, T b, T carry_in, T & carry_out)
138+
[[nodiscard]] inline constexpr std::enable_if_t<traits::ccm_is_unsigned_v<T>, T> sub_with_borrow(T a, T b, T carry_in, T & carry_out)
133139
{
134140
if (!is_constant_evaluated())
135141
{
@@ -217,7 +223,7 @@ namespace ccm::support
217223
* @param b
218224
*/
219225

220-
template <typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
226+
template <typename T, std::enable_if_t<traits::ccm_is_floating_point_v<T>, bool> = true>
221227
static constexpr void fast_two_sum(T & hi, T & lo, T a, T b)
222228
{
223229
hi = a + b;
@@ -226,7 +232,7 @@ namespace ccm::support
226232
}
227233

228234
/* Algorithm 2 from https://hal.science/hal-01351529 */
229-
template <typename T, std::enable_if_t<std::is_floating_point_v<T>, bool> = true>
235+
template <typename T, std::enable_if_t<traits::ccm_is_floating_point_v<T>, bool> = true>
230236
static constexpr void two_sum(T & s, T & t, T a, T b)
231237
{
232238
s = a + b;
@@ -251,3 +257,5 @@ namespace ccm::support
251257
}
252258

253259
} // namespace ccm::support
260+
261+
CCM_RESTORE_GCC_WARNING()

include/ccmath/internal/support/type_traits.hpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,8 +127,17 @@ namespace ccm::support::traits
127127

128128
/// is_unsigned
129129

130-
template <typename T> struct ccm_is_unsigned : and_<ccm_is_arithmetic<T>, not_<ccm_is_signed<T>>>::type {};
131-
template <typename T> constexpr bool ccm_is_unsigned_v = ccm_is_unsigned<T>::value;
130+
//template <typename T> struct ccm_is_unsigned : and_<ccm_is_arithmetic<T>, not_<ccm_is_signed<T>>>::type {};
131+
//template <typename T> constexpr bool ccm_is_unsigned_v = ccm_is_unsigned<T>::value;
132+
133+
template <typename T>
134+
struct ccm_is_unsigned : std::bool_constant<(ccm_is_arithmetic_v<T> && (T(-1) > T(0)))> {
135+
constexpr operator bool() const { return ccm_is_unsigned::value; }
136+
constexpr bool operator()() const { return ccm_is_unsigned::value; }
137+
};
138+
template <typename T>
139+
constexpr bool ccm_is_unsigned_v = ccm_is_unsigned<T>::value;
140+
132141

133142

134143
/// is_unsigned_integer custom trait

include/ccmath/internal/types/big_int.hpp

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
#include "ccmath/internal/support/math_support.hpp"
2626
#include "ccmath/internal/support/type_traits.hpp"
2727

28-
#include <algorithm>
2928
#include <array>
3029
#include <cstddef>
3130
#include <cstdint>
@@ -794,10 +793,13 @@ namespace ccm::types
794793
*
795794
* @return True if all parts of the BigInt are zero, false otherwise.
796795
*/
797-
[[nodiscard]] constexpr bool is_zero() const
796+
constexpr bool is_zero() const
798797
{
799-
// If at any point this operation see's a value that is not zero, it will return false.
800-
return std::none_of(val.begin(), val.end(), [](auto part) { return part != 0; });
798+
for (auto part : val)
799+
{
800+
if (part != 0) { return false; }
801+
}
802+
return true;
801803
}
802804

803805
/**
@@ -1483,14 +1485,15 @@ namespace ccm::types
14831485
/// Specialization of the bits.hpp header for BigInt types.
14841486
namespace ccm::support
14851487
{
1488+
14861489
template <typename To, typename From>
14871490
constexpr std::enable_if_t<
1488-
(sizeof(To) == sizeof(From)) && std::is_trivially_copyable_v<To> && std::is_trivially_copyable_v<From> && ccm::types::is_big_int<To>::value, To>
1491+
(sizeof(To) == sizeof(From)) && std::is_trivially_copyable_v<To> && std::is_trivially_copyable_v<From> && types::is_big_int<To>::value, To>
14891492
bit_cast(const From & from)
14901493
{
14911494
To out;
14921495
using Storage = decltype(out.val);
1493-
out.val = ccm::support::bit_cast<Storage>(from);
1496+
out.val = support::bit_cast<Storage>(from);
14941497
return out;
14951498
}
14961499

include/ccmath/internal/types/dyadic_float.hpp

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -82,8 +82,8 @@ namespace ccm::types
8282

8383
constexpr DyadicFloat() = default;
8484

85-
template <typename T, std::enable_if_t<ccm::support::traits::ccm_is_floating_point_v<T>, bool> = true>
86-
constexpr explicit DyadicFloat(T x)
85+
template <typename T, std::enable_if_t<std::is_floating_point_v<T>, int> = 0>
86+
constexpr DyadicFloat(T x)
8787
{
8888
static_assert(support::fp::FPBits<T>::fraction_length < Bits);
8989
support::fp::FPBits<T> x_bits(x);
@@ -107,7 +107,7 @@ namespace ccm::types
107107
{
108108
if (!mantissa.is_zero())
109109
{
110-
int shift_length = support::countl_zero(mantissa);
110+
const int shift_length = support::countl_zero(mantissa);
111111
exponent -= shift_length;
112112
mantissa <<= static_cast<std::size_t>(shift_length);
113113
}
@@ -194,7 +194,7 @@ namespace ccm::types
194194
*/
195195

196196
template <typename T, bool ShouldSignalExceptions,
197-
typename = std::enable_if_t<ccm::support::traits::ccm_is_floating_point_v<T> && (support::fp::FPBits<T>::fraction_length < Bits), void>>
197+
typename = std::enable_if_t<std::is_floating_point_v<T> && (support::fp::FPBits<T>::fraction_length < Bits), void>>
198198
constexpr T fast_as() const
199199
{
200200
if (CCM_UNLIKELY(mantissa.is_zero())) { return support::fp::FPBits<T>::zero(sign).get_val(); }
@@ -251,7 +251,7 @@ namespace ccm::types
251251
const bool sticky_bit = !(mantissa & sticky_mask).is_zero();
252252
int round_and_sticky = (static_cast<int>(round_bit) * 2) + static_cast<int>(sticky_bit);
253253

254-
T d_lo;
254+
T d_lo{}; // GCC will lose its mind if {} is not used here.
255255

256256
if (CCM_UNLIKELY(exp_lo <= 0))
257257
{
@@ -346,18 +346,7 @@ namespace ccm::types
346346
return as<T, /*ShouldSignalExceptions=*/false>();
347347
}
348348

349-
/**
350-
* @brief Converts this DyadicFloat to its underlying mantissa type with exponent adjustments.
351-
*
352-
* Interprets the DyadicFloat as an integer-like value by applying the exponent shift
353-
* and sign bit. In other words, it shifts the mantissa left (or right) by \c exponent,
354-
* and if the sign is negative, it converts the result to its two's complement form.
355-
* This can be used to retrieve the raw integer representation implied by the DyadicFloat.
356-
*
357-
* @return The \c mantissa_type value derived from the floating-point-like representation.
358-
* Returns 0 if the internal mantissa is zero.
359-
*/
360-
explicit constexpr operator mantissa_type() const
349+
constexpr mantissa_type as_mantissa_type() const
361350
{
362351
if (mantissa.is_zero()) { return 0; }
363352

include/ccmath/math/fmanip/ldexp.hpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ namespace ccm
9595
* @see https://en.cppreference.com/w/cpp/numeric/math/ldexp
9696
*/
9797
template <typename T, std::enable_if_t<!std::is_integral_v<T>, bool> = true>
98-
constexpr T ldexp(T num, int exp) noexcept
98+
constexpr T ldexp(T num, int exp)
9999
{
100100
if constexpr (ccm::builtin::has_constexpr_ldexp<T>) { return builtin::ldexp(num, exp); }
101101
else { return support::helpers::internal_ldexp(num, exp); }
@@ -129,7 +129,7 @@ namespace ccm
129129
* @see https://en.cppreference.com/w/cpp/numeric/math/ldexp
130130
*/
131131
template <typename Integer, std::enable_if_t<std::is_integral_v<Integer>, bool> = true>
132-
constexpr double ldexp(Integer num, int exp) noexcept
132+
constexpr double ldexp(Integer num, int exp)
133133
{
134134
return ccm::ldexp<double>(static_cast<double>(num), exp);
135135
}

test/fmanip/ldexp_test.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
// NOLINTBEGIN
1818

19+
static_assert(ccm::support::helpers::internal_ldexp(static_cast<float>(1.0), 2) == ccm::support::helpers::internal_ldexp(static_cast<float>(1.0), 2),
20+
"ldexp failed static_assert test");
21+
1922
template <typename T>
2023
class CcmathFmanipTests : public ::testing::Test
2124
{
@@ -28,7 +31,6 @@ TYPED_TEST(CcmathFmanipTests, LdexpStaticAssert)
2831
{
2932
// TODO: IanP: Figure out why this static_assert fails
3033
// EXPECT_EQ(ccm::ldexp(static_cast<TypeParam>(1.0), 0), 3.0);
31-
// static_assert(ccm::ldexp(static_cast<TypeParam>(1.0), 0) == ccm::ldexp(static_cast<TypeParam>(1.0), 0), "ldexp failed static_assert test");
3234
}
3335

3436
TYPED_TEST(CcmathFmanipTests, LdexpBasic)

0 commit comments

Comments
 (0)