Skip to content

Commit

Permalink
Make core implementation routines independent from the actual float t…
Browse files Browse the repository at this point in the history
…ypes and traits types

Now they are parameterized by the float format type and the carrier type
  • Loading branch information
jk-jeon committed Mar 18, 2024
1 parent a8dbed3 commit 8c48ec3
Show file tree
Hide file tree
Showing 9 changed files with 65 additions and 49 deletions.
41 changes: 22 additions & 19 deletions include/dragonbox/dragonbox.h
Original file line number Diff line number Diff line change
Expand Up @@ -1791,7 +1791,7 @@ namespace jkj {

namespace detail {
// Forward declare the implementation class.
template <class Float, class FloatTraits = default_float_traits<Float>>
template <class FloatFormat, class CarrierUInt>
struct impl;

namespace policy_impl {
Expand Down Expand Up @@ -2457,12 +2457,12 @@ namespace jkj {
// The main algorithm.
////////////////////////////////////////////////////////////////////////////////////////

template <class Float, class FloatTraits>
struct impl : private FloatTraits, private FloatTraits::format {
using format = typename FloatTraits::format;
using carrier_uint = typename FloatTraits::carrier_uint;
template <class FloatFormat, class CarrierUInt>
struct impl : private FloatFormat {
using format = FloatFormat;
using carrier_uint = CarrierUInt;
static constexpr int carrier_bits = int(physical_bits<carrier_uint>::value);

using FloatTraits::carrier_bits;
using format::significand_bits;
using format::min_exponent;
using format::max_exponent;
Expand Down Expand Up @@ -3330,31 +3330,33 @@ namespace jkj {
to_decimal_policy_holder<Policies...>::return_has_sign,
to_decimal_policy_holder<Policies...>::report_trailing_zeros>;

template <class Float, class FloatTraits, class PolicyHolder, class IntervalTypeProvider>
template <class FloatTraits, class PolicyHolder, class IntervalTypeProvider>
struct invoke_shorter_dispatcher {
using unsigned_return_type = decimal_fp<typename FloatTraits::carrier_uint, false,
PolicyHolder::report_trailing_zeros>;

template <class... Args>
JKJ_FORCEINLINE JKJ_SAFEBUFFERS JKJ_CONSTEXPR20 unsigned_return_type
operator()(Args... args) noexcept {
return impl<Float, FloatTraits>::template compute_nearest_shorter<
unsigned_return_type, typename IntervalTypeProvider::shorter_interval_type,
typename PolicyHolder::trailing_zero_policy,
typename PolicyHolder::binary_to_decimal_rounding_policy,
typename PolicyHolder::cache_policy>(args...);
return impl<typename FloatTraits::format, typename FloatTraits::carrier_uint>::
template compute_nearest_shorter<
unsigned_return_type, typename IntervalTypeProvider::shorter_interval_type,
typename PolicyHolder::trailing_zero_policy,
typename PolicyHolder::binary_to_decimal_rounding_policy,
typename PolicyHolder::cache_policy>(args...);
}
};

template <class Float, class FloatTraits, class PolicyHolder, class IntervalTypeProvider>
template <class FloatTraits, class PolicyHolder, class IntervalTypeProvider>
struct invoke_normal_dispatcher {
using unsigned_return_type = decimal_fp<typename FloatTraits::carrier_uint, false,
PolicyHolder::report_trailing_zeros>;

template <class... Args>
JKJ_FORCEINLINE JKJ_SAFEBUFFERS JKJ_CONSTEXPR20 unsigned_return_type
operator()(Args... args) noexcept {
return impl<Float, FloatTraits>::template compute_nearest_normal<
return impl<typename FloatTraits::format, typename FloatTraits::carrier_uint>::
template compute_nearest_normal<
unsigned_return_type, typename IntervalTypeProvider::normal_interval_type,
typename PolicyHolder::trailing_zero_policy,
typename PolicyHolder::binary_to_decimal_rounding_policy,
Expand Down Expand Up @@ -3418,7 +3420,7 @@ namespace jkj {
signed_significand_bits,
IntervalTypeProvider::invoke_shorter_interval_case(
signed_significand_bits,
invoke_shorter_dispatcher<Float, FloatTraits, PolicyHolder,
invoke_shorter_dispatcher<FloatTraits, PolicyHolder,
IntervalTypeProvider>{},
exponent));
}
Expand All @@ -3434,8 +3436,7 @@ namespace jkj {
signed_significand_bits,
IntervalTypeProvider::invoke_normal_interval_case(
signed_significand_bits,
invoke_normal_dispatcher<Float, FloatTraits, PolicyHolder,
IntervalTypeProvider>{},
invoke_normal_dispatcher<FloatTraits, PolicyHolder, IntervalTypeProvider>{},
two_fc, exponent));
}
else JKJ_IF_CONSTEXPR(tag == decimal_to_binary_rounding::tag_t::left_closed_directed) {
Expand All @@ -3451,7 +3452,8 @@ namespace jkj {

return PolicyHolder::handle_sign(
signed_significand_bits,
detail::impl<Float, FloatTraits>::template compute_left_closed_directed<
detail::impl<typename FloatTraits::format, typename FloatTraits::carrier_uint>::
template compute_left_closed_directed<
unsigned_return_type, typename PolicyHolder::trailing_zero_policy,
typename PolicyHolder::cache_policy>(two_fc, exponent));
}
Expand All @@ -3477,7 +3479,8 @@ namespace jkj {

return PolicyHolder::handle_sign(
signed_significand_bits,
detail::impl<Float, FloatTraits>::template compute_right_closed_directed<
detail::impl<typename FloatTraits::format, typename FloatTraits::carrier_uint>::
template compute_right_closed_directed<
unsigned_return_type, typename PolicyHolder::trailing_zero_policy,
typename PolicyHolder::cache_policy>(two_fc, exponent, shorter_interval));
}
Expand Down
10 changes: 5 additions & 5 deletions include/dragonbox/dragonbox_to_chars.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,8 @@
namespace jkj {
namespace dragonbox {
namespace detail {
template <class Float, class FloatTraits>
extern char* to_chars(typename FloatTraits::carrier_uint significand, int exponent,
char* buffer) noexcept;
template <class FloatFormat, class CarrierUInt>
extern char* to_chars(CarrierUInt significand, int exponent, char* buffer) noexcept;

// Avoid needless ABI overhead incurred by tag dispatch.
template <class PolicyHolder, class Float, class FloatTraits>
Expand All @@ -61,8 +60,9 @@ namespace jkj {
typename PolicyHolder::decimal_to_binary_rounding_policy{},
typename PolicyHolder::binary_to_decimal_rounding_policy{},
typename PolicyHolder::cache_policy{});
return to_chars<Float, FloatTraits>(result.significand, result.exponent,
buffer);
return to_chars<typename FloatTraits::format,
typename FloatTraits::carrier_uint>(result.significand,
result.exponent, buffer);
}
else {
stdr::memcpy(buffer, "0E0", 3);
Expand Down
14 changes: 7 additions & 7 deletions source/dragonbox_to_chars.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,7 @@ namespace jkj {
};

static void print_1_digit(int n, char* buffer) noexcept {
JKJ_IF_CONSTEXPR(('0' & 0xf) == 0) {
*buffer = char('0' | n);
}
JKJ_IF_CONSTEXPR(('0' & 0xf) == 0) { *buffer = char('0' | n); }
else {
*buffer = char('0' + n);
}
Expand Down Expand Up @@ -308,8 +306,9 @@ namespace jkj {
}

template <>
char* to_chars<float, default_float_traits<float>>(stdr::uint_least32_t s32, int exponent,
char* buffer) noexcept {
char* to_chars<ieee754_binary32, stdr::uint_least32_t>(stdr::uint_least32_t s32,
int exponent,
char* buffer) noexcept {
// Print significand.
print_9_digits(s32, exponent, buffer);

Expand Down Expand Up @@ -337,8 +336,9 @@ namespace jkj {
}

template <>
char* to_chars<double, default_float_traits<double>>(stdr::uint_least64_t const significand,
int exponent, char* buffer) noexcept {
char*
to_chars<ieee754_binary64, stdr::uint_least64_t>(stdr::uint_least64_t const significand,
int exponent, char* buffer) noexcept {
// Print significand by decomposing it into a 9-digit block and a 8-digit block.
stdr::uint_least32_t first_block, second_block;
bool no_second_block;
Expand Down
17 changes: 10 additions & 7 deletions subproject/meta/source/generate_cache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,10 @@

template <class FloatTraits>
auto generate_cache() {
using impl = jkj::dragonbox::detail::impl<typename FloatTraits::type, FloatTraits>;
using traits_type = FloatTraits;
using format = typename traits_type::format;
using carrier_uint = typename traits_type::carrier_uint;
using impl = jkj::dragonbox::detail::impl<format, carrier_uint>;

std::vector<jkj::big_uint> results;
jkj::unsigned_rational<jkj::big_uint> target_number;
Expand Down Expand Up @@ -76,17 +79,17 @@ auto generate_cache() {
int main() {
std::cout << "[Generating cache...]\n";

using jkj::dragonbox::detail::impl;

auto write_file = [](std::ofstream& out, auto type_tag, auto const& cache_array,
auto&& ieee_754_type_name_string, auto&& element_printer) {
using float_type = typename decltype(type_tag)::type;
using impl_type = jkj::dragonbox::detail::impl<typename decltype(type_tag)::format,
typename decltype(type_tag)::carrier_uint>;

out << "static constexpr int min_k = " << std::dec << impl<float_type>::min_k << ";\n";
out << "static constexpr int max_k = " << std::dec << impl<float_type>::max_k << ";\n";
out << "static constexpr int min_k = " << std::dec << impl_type::min_k << ";\n";
out << "static constexpr int max_k = " << std::dec << impl_type::max_k << ";\n";
out << "static constexpr cache_entry_type cache[max_k - min_k + 1] JKJ_STATIC_DATA_SECTION = {";
for (int k = impl<float_type>::min_k; k < impl<float_type>::max_k; ++k) {
auto idx = std::size_t(k - impl<float_type>::min_k);
for (int k = impl_type::min_k; k < impl_type::max_k; ++k) {
auto idx = std::size_t(k - impl_type::min_k);
out << "\n\t";
element_printer(out, cache_array[idx]);
out << ",";
Expand Down
2 changes: 1 addition & 1 deletion subproject/meta/source/live_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ static void live_test(std::streamsize hex_width) {
}

int main() {
constexpr enum { test_float, test_double } test = test_double;
constexpr enum { test_float, test_double } test = test_float;

if (test == test_float) {
std::cout << "[Start live test for float's]\n";
Expand Down
4 changes: 3 additions & 1 deletion subproject/test/source/verify_cache_precision.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,9 @@ template <class FloatTraits>
bool analyze(std::ostream& out) {
out << "e,bits_for_multiplication,bits_for_integer_check\n";

using impl = jkj::dragonbox::detail::impl<typename FloatTraits::type, FloatTraits>;
using format = typename FloatTraits::format;
using carrier_uint = typename FloatTraits::carrier_uint;
using impl = jkj::dragonbox::detail::impl<format, carrier_uint>;
using namespace jkj::dragonbox::detail::log;

auto n_max = jkj::big_uint::power_of_2(impl::significand_bits + 2);
Expand Down
3 changes: 1 addition & 2 deletions subproject/test/source/verify_compressed_cache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,12 @@ int main() {
using namespace jkj::dragonbox::detail::log;
using namespace jkj::dragonbox::detail::wuint;
using info = jkj::dragonbox::detail::compressed_cache_detail<jkj::dragonbox::ieee754_binary64>;
using impl = jkj::dragonbox::detail::impl<double>;
using impl = jkj::dragonbox::detail::impl<jkj::dragonbox::ieee754_binary64, std::uint_least64_t>;

std::cout << "[Verifying cache recovery for compressed cache...]\n";

jkj::unsigned_rational<jkj::big_uint> unit;
auto n_max = jkj::big_uint::power_of_2(impl::significand_bits + 2);
int prev_k = impl::max_k + 1;
for (int e = impl::min_exponent - impl::significand_bits;
e <= impl::max_exponent - impl::significand_bits; ++e) {
int const k = impl::kappa - floor_log10_pow2(e);
Expand Down
13 changes: 8 additions & 5 deletions subproject/test/source/verify_fast_multiplication.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,10 @@

template <class Float, class CachePolicy>
static bool verify_fast_multiplication_xz(CachePolicy&& cache_policy) {
using impl = jkj::dragonbox::detail::impl<Float>;
using format = typename impl::format;
using carrier_uint = typename impl::carrier_uint;
using traits_type = jkj::dragonbox::default_float_traits<Float>;
using format = typename traits_type::format;
using carrier_uint = typename traits_type::carrier_uint;
using impl = jkj::dragonbox::detail::impl<format, carrier_uint>;

constexpr auto four_fl = (carrier_uint(1) << (impl::significand_bits + 2)) - 1;
constexpr auto two_fr = (carrier_uint(1) << (impl::significand_bits + 1)) + 1;
Expand Down Expand Up @@ -95,8 +96,10 @@ static bool verify_fast_multiplication_xz(CachePolicy&& cache_policy) {

template <class Float, class CachePolicy>
static bool verify_fast_multiplication_yru(CachePolicy&& cache_policy) {
using impl = jkj::dragonbox::detail::impl<Float>;
using format = typename impl::format;
using traits_type = jkj::dragonbox::default_float_traits<Float>;
using format = typename traits_type::format;
using carrier_uint = typename traits_type::carrier_uint;
using impl = jkj::dragonbox::detail::impl<format, carrier_uint>;
bool success = true;

for (int k = impl::min_k; k <= impl::max_k; ++k) {
Expand Down
10 changes: 8 additions & 2 deletions subproject/test/source/verify_magic_division.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,11 @@
template <class Float>
static bool verify_check_divisibility_and_divide_by_pow10() {
using namespace jkj::dragonbox::detail;
using traits_type = jkj::dragonbox::default_float_traits<Float>;
using format = typename traits_type::format;
using carrier_uint = typename traits_type::carrier_uint;

constexpr int kappa = impl<Float>::kappa;
constexpr int kappa = impl<format, carrier_uint>::kappa;
constexpr auto max_n = compute_power<kappa + 1>(std::uint32_t(10));
constexpr auto divisor = compute_power<kappa>(std::uint32_t(10));

Expand Down Expand Up @@ -61,8 +64,11 @@ static bool verify_check_divisibility_and_divide_by_pow10() {
template <class Float>
static bool verify_divide_by_pow10() {
using namespace jkj::dragonbox::detail;
using traits_type = jkj::dragonbox::default_float_traits<Float>;
using format = typename traits_type::format;
using carrier_uint = typename traits_type::carrier_uint;

constexpr int kappa = impl<Float>::kappa;
constexpr int kappa = impl<format, carrier_uint>::kappa;
constexpr auto max_n = compute_power<kappa + 1>(std::uint32_t(10));
constexpr auto divisor = compute_power<kappa>(std::uint32_t(10));

Expand Down

0 comments on commit 8c48ec3

Please sign in to comment.