Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
Artur Bać committed Jul 22, 2024
1 parent 80440ce commit b8698c2
Show file tree
Hide file tree
Showing 6 changed files with 109 additions and 27 deletions.
44 changes: 20 additions & 24 deletions fixed_lib/include/fixedmath/detail/common.h
Original file line number Diff line number Diff line change
@@ -1,25 +1,29 @@
#pragma once

#include "../types.h"
#include <type_traits>

#define FIXEDMATH_PUBLIC gnu::visibility("default")
#include <fixedmath/detail/type_traits.h>

namespace fixedmath::inline v2::detail
{

template<int digits>
[[gnu::const, gnu::always_inline]]
constexpr auto unsigned_shift_left_signed(fixed_internal value) noexcept -> fixed_internal
constexpr auto unsigned_shift_left_signed(std::signed_integral auto value) noexcept -> fixed_internal
{
using unsigned_internal = std::make_unsigned_t<fixed_internal>;
return static_cast<fixed_internal>(
(static_cast<unsigned_internal>(value) << digits)
| (static_cast<unsigned_internal>(value) & (unsigned_internal(1) << 63u))
(static_cast<fixed_internal_unsigned>(value) << digits)
| (static_cast<fixed_internal_unsigned>(value) & (fixed_internal_unsigned(1) << 63u))
);
}

template<typename value_type>
template<int digits>
[[nodiscard, gnu::const, gnu::always_inline]]
constexpr auto unsigned_shift_left_unsigned(std::unsigned_integral auto value) noexcept -> fixed_internal
{
return static_cast<fixed_internal>(static_cast<fixed_internal_unsigned>(value) << digits);
}

template<std::integral value_type>
[[nodiscard, gnu::const, gnu::always_inline]]
constexpr auto promote_type_to_signed(value_type value) noexcept
{
Expand All @@ -32,17 +36,9 @@ constexpr auto promote_type_to_signed(value_type value) noexcept
}
}

template<int digits>
[[nodiscard, gnu::const, gnu::always_inline]]
constexpr auto unsigned_shift_left_unsigned(fixed_internal value) noexcept -> fixed_internal
{
using unsigned_internal = std::make_unsigned_t<fixed_internal>;
return static_cast<fixed_internal>(static_cast<unsigned_internal>(value) << digits);
}

[[nodiscard, gnu::const, gnu::always_inline]]
///\returns the highest power of 4 that is less than or equal to \ref value
constexpr auto highest_pwr4_clz(fixed_internal_unsigned value) noexcept -> fixed_internal
constexpr auto highest_pwr4_clz(concepts::internal_unsigned auto value) noexcept -> fixed_internal
{
if(value != 0) [[likely]]
{
Expand All @@ -58,7 +54,7 @@ constexpr auto highest_pwr4_clz(fixed_internal_unsigned value) noexcept -> fixed
}

[[nodiscard, gnu::const, gnu::always_inline]]
constexpr auto highest_pwr4(fixed_internal_unsigned value) noexcept -> fixed_internal
constexpr auto highest_pwr4(std::unsigned_integral auto value) noexcept -> fixed_internal
{
// one starts at the highest power of four <= than the argument.
fixed_internal_unsigned pwr4{1ll << 62}; // second-to-top bit set
Expand All @@ -70,27 +66,27 @@ constexpr auto highest_pwr4(fixed_internal_unsigned value) noexcept -> fixed_int

template<int precision>
[[nodiscard, gnu::const, gnu::always_inline]]
constexpr auto mul_(fixed_internal x, fixed_internal y) noexcept -> fixed_internal
constexpr auto mul_(concepts::internal auto x, concepts::internal auto y) noexcept -> fixed_internal
{
return (x * y) >> precision;
}

template<int precision>
[[nodiscard, gnu::const, gnu::always_inline]]
constexpr auto div_(fixed_internal x, fixed_internal y) noexcept -> fixed_internal
constexpr auto div_(concepts::internal auto x, concepts::internal auto y) noexcept -> fixed_internal
{
return (x << precision) / y;
}

template<int precision>
[[nodiscard, gnu::const, gnu::always_inline]]
constexpr auto fix_(fixed_internal x) noexcept -> fixed_internal
constexpr auto fix_(std::integral auto x) noexcept -> fixed_internal
{
return (x << precision);
return fixed_internal(x) << precision;
}

[[nodiscard, gnu::const, gnu::always_inline]]
constexpr auto set_sign(bool sign_, fixed_internal result) -> fixed_t
constexpr auto set_sign(bool sign_, concepts::internal auto result) -> fixed_t
{
if(!sign_)
return as_fixed(result);
Expand All @@ -104,5 +100,5 @@ constexpr void swap(T & a, T & b) noexcept
a = b;
b = temp;
}
} // namespace fixedmath::detail
} // namespace fixedmath::inline v2::detail

7 changes: 6 additions & 1 deletion fixed_lib/include/fixedmath/detail/type_traits.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ using promote_to_signed_t = signed_type_by_size_t<(sizeof(T) << 1)>;
template<typename T>
inline constexpr bool is_integral_v = std::is_integral_v<T>;


template<typename T>
inline constexpr bool is_fixed_point_v = std::is_same_v<T, fixed_t>;

Expand Down Expand Up @@ -70,6 +69,11 @@ inline constexpr bool one_of_is_double_v = std::is_same_v<T, double> || std::is_
namespace fixedmath::inline v2::concepts
{
using std::integral;
template<typename T>
concept internal_unsigned = std::same_as<T, fixed_internal_unsigned>;

template<typename T>
concept internal = std::same_as<T, fixed_internal>;

template<typename T>
concept fixed_point = typetraits::is_fixed_point_v<T>;
Expand All @@ -91,6 +95,7 @@ concept arithmetic_and_one_is_fixed = typetraits::is_arithmetic_and_one_is_fixed

template<typename T, typename U>
concept one_of_is_double = typetraits::one_of_is_double_v<T, U>;

} // namespace fixedmath::inline v2::concepts

namespace fixedmath::inline v2::detail
Expand Down
2 changes: 1 addition & 1 deletion fixed_lib/include/fixedmath/math.h
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ struct subtract_t
template<concepts::arithmetic supported_type1, concepts::arithmetic supported_type2>
requires concepts::arithmetic_and_one_is_fixed<supported_type1, supported_type2>
[[nodiscard, gnu::const, gnu::always_inline]]
constexpr auto operator()(supported_type1 lh, supported_type2 rh) noexcept
static constexpr auto operator()(supported_type1 lh, supported_type2 rh) noexcept
{
if constexpr(typetraits::one_of_is_double_v<supported_type1, supported_type2>)
return detail::promote_to_double(lh) - detail::promote_to_double(rh);
Expand Down
2 changes: 1 addition & 1 deletion unit_tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ endfunction()
add_fixedmath_ut( fixed_construction_ut )
add_fixedmath_ut( type_convertions_ut )
add_fixedmath_ut( addition_ut )

add_fixedmath_ut( subtraction_ut )

# add_compile_test( addition )
# add_compile_test( substraction )
Expand Down
20 changes: 20 additions & 0 deletions unit_tests/addition_ut.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,26 @@ int main()
expect_neq(limits_::lowest() + 1, limits_::quiet_NaN());

expect_neq(as_fixed(limits_::max().v - 65536) + 1_fix, limits_::quiet_NaN());

expect( test_resulting_type<fixed_t>( int64_t(1) + 1_fix ) );
expect( test_resulting_type<fixed_t>( 1_fix + int64_t(1) ) );
expect( test_resulting_type<fixed_t>( uint64_t(1) + 1_fix ) );
expect( test_resulting_type<fixed_t>( 1_fix + uint64_t(1) ) );
expect( test_resulting_type<fixed_t>( 1_fix + 1_fix ) );
expect( test_resulting_type<fixed_t>( 1 + 1_fix ) );
expect( test_resulting_type<fixed_t>( 1_fix + 1 ) );
expect( test_resulting_type<fixed_t>( int16_t(1) + 1_fix ) );
expect( test_resulting_type<fixed_t>( 1_fix + int16_t(1) ) );
expect( test_resulting_type<fixed_t>( uint16_t(1) + 1_fix ) );
expect( test_resulting_type<fixed_t>( 1_fix + uint16_t(1) ) );
expect( test_resulting_type<fixed_t>( int8_t(1) + 1_fix ) );
expect( test_resulting_type<fixed_t>( 1_fix + int8_t(1) ) );
expect( test_resulting_type<fixed_t>( uint8_t(1) + 1_fix ) );
expect( test_resulting_type<fixed_t>( 1_fix + uint8_t(1) ) );
expect( test_resulting_type<fixed_t>( 1.f + 1_fix ) );
expect( test_resulting_type<fixed_t>( 1_fix + 1.f ) );
expect( test_resulting_type<double>( 1. + 1_fix ) );
expect( test_resulting_type<double>( 1_fix + 1. ) );
return {};
};
result |= run_constexpr_test(fn_tmpl);
Expand Down
61 changes: 61 additions & 0 deletions unit_tests/subtraction_ut.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#include <unit_test_core.h>
#include <unit_test_common.h>

using boost::ut::operator""_test;
using namespace metatests;
using namespace fixedmath;

int main()
{
test_result result;
using F = fixedmath::fixed_internal;
"addition"_test = [&result]
{
auto fn_tmpl = [] -> metatests::test_result
{
expect_eq(0.2_fix - 1.2_fix, -1_fix);
expect_eq(3.2_fix - 1.2_fix, 2_fix);
expect_eq(-4.2_fix - 1.2_fix, -5.4_fix);
expect_eq(-4.2_fix + 1.2_fix, -3_fix);

static constexpr auto approx{std::numeric_limits<double>::epsilon()};
expect_approx(1_fix - 1., 1. - 1., approx);
expect_approx(2_fix - 1., 2. - 1., approx);
expect_approx(-2_fix - 1., -2. - 1., approx);
expect_approx(-2_fix + 1., -2. + 1., approx);

expect_eq(-10.5_fix - uint8_t(10), -20.5_fix);
expect_eq(-10.5_fix - uint16_t(10), -20.5_fix);
expect_eq(-10.5_fix - uint32_t(10), -20.5_fix);
expect_eq(-10.5_fix - uint64_t(10), -20.5_fix);
expect_eq(uint8_t(10) - 10.5_fix, -.5_fix);
expect_eq(uint16_t(10) - 10.5_fix, -.5_fix);
expect_eq(uint32_t(10) - 10.5_fix, -.5_fix);
expect_eq(uint64_t(10) - 10.5_fix, -.5_fix);
expect_neq(limits_::max() - 1, limits_::quiet_NaN());

expect(test_resulting_type<fixed_t>(int64_t(1) - 1_fix));
expect(test_resulting_type<fixed_t>(1_fix - int64_t(1)));
expect(test_resulting_type<fixed_t>(uint64_t(1) - 1_fix));
expect(test_resulting_type<fixed_t>(1_fix - uint64_t(1)));
expect(test_resulting_type<fixed_t>(1_fix - 1_fix));
expect(test_resulting_type<fixed_t>(1 - 1_fix));
expect(test_resulting_type<fixed_t>(1_fix - 1));
expect(test_resulting_type<fixed_t>(int16_t(1) - 1_fix));
expect(test_resulting_type<fixed_t>(1_fix - int16_t(1)));
expect(test_resulting_type<fixed_t>(uint16_t(1) - 1_fix));
expect(test_resulting_type<fixed_t>(1_fix - uint16_t(1)));
expect(test_resulting_type<fixed_t>(int8_t(1) - 1_fix));
expect(test_resulting_type<fixed_t>(1_fix - int8_t(1)));
expect(test_resulting_type<fixed_t>(uint8_t(1) - 1_fix));
expect(test_resulting_type<fixed_t>(1_fix - uint8_t(1)));
expect(test_resulting_type<fixed_t>(1.f - 1_fix));
expect(test_resulting_type<fixed_t>(1_fix - 1.f));
expect(test_resulting_type<double>(1. - 1_fix));
expect(test_resulting_type<double>(1_fix - 1.));
return {};
};
result |= run_constexpr_test(fn_tmpl);
result |= run_consteval_test(fn_tmpl);
};
}

0 comments on commit b8698c2

Please sign in to comment.