├── .gitattributes ├── .gitignore ├── CMakeLists.txt ├── README.md ├── cmake └── jkj_fpConfig.cmake ├── include └── jkj │ └── fp │ ├── decimal_fp.h │ ├── detail │ ├── bits.h │ ├── div.h │ ├── dragonbox_cache.h │ ├── log.h │ ├── macros.h │ ├── policy.h │ ├── ryu_printf_fast_cache.h │ ├── undef_macros.h │ ├── util.h │ └── wuint.h │ ├── dooly.h │ ├── dragonbox.h │ ├── from_chars │ └── from_chars.h │ ├── ieee754_format.h │ ├── policy.h │ ├── ryu_printf.h │ └── to_chars │ ├── fixed_precision.h │ ├── shortest_precise.h │ ├── shortest_roundtrip.h │ └── to_chars_common.h ├── source └── to_chars │ ├── LICENSE-Apache2 │ ├── LICENSE-Boost │ └── to_chars.cpp └── subproject ├── 3rdparty ├── fmt │ ├── CMakeLists.txt │ └── fmt │ │ ├── compile.h │ │ ├── core.h │ │ ├── format-inl.h │ │ └── format.h ├── grisu_exact │ ├── CMakeLists.txt │ ├── fp_to_chars.cpp │ ├── fp_to_chars.h │ └── grisu_exact.h ├── ryu │ ├── CMakeLists.txt │ └── ryu │ │ ├── LICENSE-Apache2 │ │ ├── LICENSE-Boost │ │ ├── common.h │ │ ├── d2fixed.c │ │ ├── d2fixed_full_table.h │ │ ├── d2s.c │ │ ├── d2s_full_table.h │ │ ├── d2s_intrinsics.h │ │ ├── digit_table.h │ │ ├── f2s.c │ │ ├── f2s_full_table.h │ │ ├── f2s_intrinsics.h │ │ ├── ryu.h │ │ ├── ryu_parse.h │ │ ├── s2d.c │ │ └── s2f.c ├── schubfach │ ├── CMakeLists.txt │ ├── schubfach_32.cc │ ├── schubfach_32.h │ ├── schubfach_64.cc │ └── schubfach_64.h └── shaded_plots │ ├── example_shaded_plots.m │ ├── license.txt │ ├── plot_distribution.m │ ├── plot_distribution_prctile.m │ ├── plot_histogram_shaded.m │ └── plot_shaded.m ├── benchmark ├── CMakeLists.txt ├── include │ ├── from_chars_limited_precision_benchmark.h │ ├── from_chars_unlimited_precision_benchmark.h │ ├── to_chars_fixed_precision_benchmark.h │ └── to_chars_shortest_roundtrip_benchmark.h ├── matlab │ ├── plot_digit_benchmark.m │ ├── plot_fixed_precision_benchmark.m │ ├── plot_to_chars_shortest_roundtrip_benchmarks.m │ └── plot_to_chars_shortest_roundtrip_uniform_benchmark.m ├── results │ ├── from_chars_limited_precision_benchmark_binary32_clang.png │ ├── from_chars_limited_precision_benchmark_binary64_clang.png │ ├── from_chars_unlimited_precision_benchmark_binary32_clang.png │ ├── from_chars_unlimited_precision_benchmark_binary64_clang.png │ ├── to_chars_fixed_precision_benchmark_binary32_clang.png │ ├── to_chars_fixed_precision_benchmark_binary64_clang.png │ ├── to_chars_shortest_roundtrip_digits_benchmark_binary32_clang.png │ ├── to_chars_shortest_roundtrip_digits_benchmark_binary64_clang.png │ ├── to_chars_shortest_roundtrip_digits_benchmark_ntzr_binary32_clang.png │ ├── to_chars_shortest_roundtrip_digits_benchmark_ntzr_binary64_clang.png │ ├── to_chars_shortest_roundtrip_uniform_benchmark_binary32_clang.png │ ├── to_chars_shortest_roundtrip_uniform_benchmark_binary64_clang.png │ ├── to_chars_shortest_roundtrip_uniform_benchmark_ntzr_binary32_clang.png │ └── to_chars_shortest_roundtrip_uniform_benchmark_ntzr_binary64_clang.png └── source │ ├── fmt_fixed_precision.cpp │ ├── fp_from_chars_limited_precision.cpp │ ├── fp_from_chars_unlimited_precision.cpp │ ├── fp_to_chars_fixed_precision.cpp │ ├── fp_to_chars_shortest_roundtrip.cpp │ ├── from_chars_limited_precision_benchmark.cpp │ ├── from_chars_unlimited_precision_benchmark.cpp │ ├── grisu_exact_shortest_roundtrip.cpp │ ├── ryu_fixed_precision.cpp │ ├── ryu_shortest_roundtrip.cpp │ ├── ryu_stof.cpp │ ├── schubfach_shortest_roundtrip.cpp │ ├── std_from_chars.cpp │ ├── stod.cpp │ ├── to_chars_fixed_precision_benchmark.cpp │ └── to_chars_shortest_roundtrip_benchmark.cpp ├── common ├── CMakeLists.txt └── include │ ├── bigint.h │ ├── cache_write_helper.h │ ├── minmax_euclid.h │ └── random_float.h ├── meta ├── CMakeLists.txt ├── results │ ├── dragonbox_binary32_fast_cache.txt │ ├── dragonbox_binary64_compressed_cache_error_table.txt │ ├── dragonbox_binary64_fast_cache.txt │ ├── ryu_printf_binary32_fast_cache.txt │ └── ryu_printf_binary64_fast_cache.txt └── source │ ├── dragonbox_generate_cache.cpp │ ├── dragonbox_generate_compact_cache_error_table.cpp │ ├── from_chars_limited_precision_live_test.cpp │ ├── from_chars_unlimited_precision_live_test.cpp │ ├── ryu_printf_generate_fast_cache.cpp │ ├── sandbox.cpp │ ├── to_chars_fixed_precision_live_test.cpp │ └── to_chars_shortest_roundtrip_live_test.cpp └── test ├── CMakeLists.txt └── source ├── dragonbox_dooly_binary32_exhaustive_joint_test.cpp ├── dragonbox_dooly_binary64_uniform_random_joint_test.cpp ├── dragonbox_test_all_shorter_interval_cases.cpp ├── dragonbox_uniform_random_test.cpp ├── dragonbox_verify_fast_multiplication.cpp ├── dragonbox_verify_magic_division.cpp ├── ryu_printf_dooly_uniform_random_joint_test.cpp ├── ryu_printf_uniform_random_test.cpp ├── test_bigint.cpp ├── test_minmax_euclid.cpp ├── test_policy_holder.cpp └── verify_log_computation.cpp /.gitattributes: -------------------------------------------------------------------------------- 1 | * text=auto 2 | 3 | CMakeLists.txt eol=lf 4 | *.h eol=lf 5 | *.hpp eol=lf 6 | *.cc eol=lf 7 | *.cpp eol=lf 8 | *.cmake eol=lf 9 | *.m eol=lf 10 | 11 | *.png binary 12 | *.pdf binary 13 | *.csv binary 14 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14 FATAL_ERROR) 2 | 3 | project(jkj_fp 4 | VERSION 0.0.1 5 | LANGUAGES CXX) 6 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 7 | 8 | # ---- Includes ---- 9 | 10 | include(CMakePackageConfigHelpers) 11 | include(GNUInstallDirs) 12 | 13 | # ---- Warning guard ---- 14 | 15 | # Protect dependents from this project's warnings if the guard isn't disabled 16 | set(jkj_fp_warning_guard "SYSTEM") 17 | if(jkj_fp_INCLUDE_WITHOUT_SYSTEM) 18 | set(jkj_fp_warning_guard "") 19 | endif() 20 | 21 | # ---- Declare library (fp) ---- 22 | 23 | add_library(jkj_fp INTERFACE) 24 | add_library(jkj_fp::fp ALIAS jkj_fp) 25 | 26 | set(jkj_fp_headers 27 | include/jkj/fp/detail/bits.h 28 | include/jkj/fp/detail/div.h 29 | include/jkj/fp/detail/dragonbox_cache.h 30 | include/jkj/fp/detail/log.h 31 | include/jkj/fp/detail/macros.h 32 | include/jkj/fp/detail/ryu_printf_fast_cache.h 33 | include/jkj/fp/detail/undef_macros.h 34 | include/jkj/fp/detail/util.h 35 | include/jkj/fp/detail/wuint.h 36 | include/jkj/fp/decimal_fp.h 37 | include/jkj/fp/dooly.h 38 | include/jkj/fp/dragonbox.h 39 | include/jkj/fp/ieee754_format.h 40 | include/jkj/fp/policy.h 41 | include/jkj/fp/ryu_printf.h) 42 | 43 | target_include_directories(jkj_fp 44 | ${jkj_fp_warning_guard} 45 | INTERFACE 46 | "$") 47 | 48 | target_compile_features(jkj_fp INTERFACE cxx_std_17) 49 | 50 | # ---- Declare library (charconv) ---- 51 | 52 | set(jkj_fp_charconv_headers 53 | ${jkj_fp_headers} 54 | include/jkj/fp/to_chars/fixed_precision.h 55 | include/jkj/fp/to_chars/shortest_roundtrip.h 56 | include/jkj/fp/to_chars/shortest_precise.h 57 | include/jkj/fp/to_chars/to_chars_common.h 58 | include/jkj/fp/from_chars/from_chars.h) 59 | 60 | set(jkj_fp_charconv_sources source/to_chars/to_chars.cpp) 61 | 62 | add_library(jkj_fp_charconv STATIC 63 | ${jkj_fp_charconv_headers} 64 | ${jkj_fp_charconv_sources}) 65 | add_library(jkj_fp::charconv ALIAS jkj_fp_charconv) 66 | 67 | target_include_directories(jkj_fp_charconv 68 | ${jkj_fp_warning_guard} 69 | PUBLIC 70 | "$") 71 | 72 | target_compile_features(jkj_fp_charconv PUBLIC cxx_std_17) 73 | set_target_properties(jkj_fp_charconv PROPERTIES FOLDER fp) 74 | 75 | # ---- Install ---- 76 | 77 | option(JKJ_FP_INSTALL_CHARCONV 78 | "When invoked with --install, to_chars/from_chars families are installed together with the core library" 79 | On) 80 | 81 | set(jkj_fp_directory "fp-${PROJECT_VERSION}") 82 | set(jkj_fp_include_directory "${CMAKE_INSTALL_INCLUDEDIR}/${jkj_fp_directory}") 83 | set(jkj_fp_install_targets jkj_fp) 84 | 85 | if (JKJ_FP_INSTALL_CHARCONV) 86 | set(jkj_fp_install_targets ${jkj_fp_targets} jkj_fp_charconv) 87 | endif() 88 | 89 | install(TARGETS ${jkj_fp_install_targets} 90 | EXPORT jkj_fpTargets 91 | ARCHIVE # 92 | DESTINATION "${CMAKE_INSTALL_LIBDIR}" 93 | COMPONENT jkj_fp_Development 94 | INCLUDES # 95 | DESTINATION "${jkj_fp_include_directory}") 96 | 97 | set(jkj_fp_install_cmakedir "${CMAKE_INSTALL_LIBDIR}/cmake/${jkj_fp_directory}") 98 | 99 | write_basic_package_version_file( 100 | jkj_fpConfigVersion.cmake 101 | VERSION ${PROJECT_VERSION} 102 | COMPATIBILITY SameMajorVersion 103 | ARCH_INDEPENDENT) 104 | 105 | install(EXPORT jkj_fpTargets 106 | NAMESPACE jkj_fp:: 107 | DESTINATION "${jkj_fp_install_cmakedir}") 108 | 109 | install(FILES 110 | "${PROJECT_SOURCE_DIR}/cmake/jkj_fpConfig.cmake" 111 | "${PROJECT_BINARY_DIR}/jkj_fpConfigVersion.cmake" 112 | DESTINATION "${jkj_fp_install_cmakedir}") 113 | 114 | install(DIRECTORY include/jkj/fp/detail 115 | DESTINATION "${jkj_fp_include_directory}/jkj/fp") 116 | install(FILES include/jkj/fp/decimal_fp.h 117 | include/jkj/fp/dooly.h 118 | include/jkj/fp/dragonbox.h 119 | include/jkj/fp/ieee754_format.h 120 | include/jkj/fp/policy.h 121 | include/jkj/fp/ryu_printf.h 122 | DESTINATION "${jkj_fp_include_directory}/jkj/fp") 123 | 124 | if (JKJ_FP_INSTALL_CHARCONV) 125 | install(DIRECTORY include/jkj/fp/from_chars 126 | DESTINATION "${jkj_fp_include_directory}/jkj/fp") 127 | install(DIRECTORY include/jkj/fp/to_chars 128 | DESTINATION "${jkj_fp_include_directory}/jkj/fp") 129 | endif() 130 | 131 | # ---- Subproject ---- 132 | 133 | option(JKJ_FP_ENABLE_SUBPROJECT "Build subproject as well" OFF) 134 | 135 | if (JKJ_FP_ENABLE_SUBPROJECT) 136 | add_subdirectory("subproject/benchmark") 137 | add_subdirectory("subproject/meta") 138 | add_subdirectory("subproject/test") 139 | endif() 140 | 141 | # ---- MSVC Specifics ---- 142 | if (MSVC) 143 | # No need to not generate PDB 144 | # /permissive- should be the default 145 | # The compilation will fail without /experimental:newLambdaProcessor 146 | target_compile_options(jkj_fp INTERFACE 147 | /Zi /permissive- 148 | $<$>:/experimental:newLambdaProcessor>) 149 | target_compile_options(jkj_fp_charconv PUBLIC 150 | /Zi /permissive- 151 | $<$>:/experimental:newLambdaProcessor> 152 | $<$:/GL>) 153 | endif() -------------------------------------------------------------------------------- /cmake/jkj_fpConfig.cmake: -------------------------------------------------------------------------------- 1 | include("${CMAKE_CURRENT_LIST_DIR}/jkj_fpTargets.cmake") 2 | -------------------------------------------------------------------------------- /include/jkj/fp/decimal_fp.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | 19 | #ifndef JKJ_HEADER_FP_DECIMAL_FP 20 | #define JKJ_HEADER_FP_DECIMAL_FP 21 | 22 | #include "ieee754_format.h" 23 | 24 | namespace jkj::fp { 25 | template 26 | struct decimal_fp; 27 | 28 | template 29 | struct decimal_fp { 30 | using float_type = Float; 31 | using carrier_uint = typename ieee754_traits::carrier_uint; 32 | static constexpr bool is_signed = false; 33 | 34 | carrier_uint significand; 35 | int exponent; 36 | }; 37 | 38 | template 39 | struct decimal_fp { 40 | using float_type = Float; 41 | using carrier_uint = typename ieee754_traits::carrier_uint; 42 | static constexpr bool is_signed = true; 43 | 44 | carrier_uint significand; 45 | int exponent; 46 | bool is_negative; 47 | }; 48 | 49 | template 50 | struct decimal_fp { 51 | using float_type = Float; 52 | using carrier_uint = typename ieee754_traits::carrier_uint; 53 | static constexpr bool is_signed = false; 54 | 55 | carrier_uint significand; 56 | int exponent; 57 | bool may_have_trailing_zeros; 58 | }; 59 | 60 | template 61 | struct decimal_fp { 62 | using float_type = Float; 63 | using carrier_uint = typename ieee754_traits::carrier_uint; 64 | static constexpr bool is_signed = true; 65 | 66 | carrier_uint significand; 67 | int exponent; 68 | bool is_negative; 69 | bool may_have_trailing_zeros; 70 | }; 71 | 72 | template 73 | using unsigned_decimal_fp = decimal_fp; 74 | 75 | template 76 | using signed_decimal_fp = decimal_fp; 77 | } 78 | 79 | #endif -------------------------------------------------------------------------------- /include/jkj/fp/detail/bits.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | //////////////////////////////////////////////////////////// 19 | //////////// !!!! This header leaks macros !!!! //////////// 20 | //////////////////////////////////////////////////////////// 21 | 22 | #ifndef JKJ_HEADER_FP_BITS 23 | #define JKJ_HEADER_FP_BITS 24 | 25 | #include "util.h" 26 | #include 27 | #include 28 | 29 | #if (defined(__GNUC__) || defined(__clang__)) && defined(__x86_64__) 30 | #include 31 | #elif defined(_MSC_VER) && defined(_M_X64) 32 | #include // this includes immintrin.h as well 33 | #endif 34 | 35 | namespace jkj::fp { 36 | namespace detail { 37 | namespace bits { 38 | template 39 | int countl_zero(UInt n) noexcept { 40 | static_assert(std::is_unsigned_v && sizeof(UInt) <= 8); 41 | assert(n != 0); 42 | #if (defined(__GNUC__) || defined(__clang__)) && defined(__x86_64__) 43 | if constexpr (std::is_same_v) { 44 | return __builtin_clzl(n); 45 | } 46 | else if constexpr (std::is_same_v) { 47 | return __builtin_clzll(n); 48 | } 49 | else { 50 | static_assert(sizeof(UInt) <= sizeof(unsigned int)); 51 | return __builtin_clz((unsigned int)n) 52 | - (value_bits - value_bits); 53 | } 54 | #elif defined(_MSC_VER) && defined(_M_X64) 55 | if constexpr (std::is_same_v) { 56 | return int(__lzcnt16(n)); 57 | } 58 | else if constexpr (std::is_same_v) { 59 | return int(__lzcnt64(n)); 60 | } 61 | else { 62 | static_assert(sizeof(UInt) <= sizeof(unsigned int)); 63 | return int(__lzcnt((unsigned int)n) 64 | - (value_bits - value_bits)); 65 | } 66 | #else 67 | int count = int(value_bits); 68 | 69 | std::uint32_t n32; 70 | if constexpr (value_bits > 32) { 71 | if ((n >> 32) != 0) { 72 | count -= 33; 73 | n32 = std::uint32_t(n >> 32); 74 | } 75 | else { 76 | n32 = std::uint32_t(n); 77 | if (n32 != 0) { 78 | count -= 1; 79 | } 80 | } 81 | } 82 | else { 83 | n32 = std::uint32_t(n); 84 | } 85 | if constexpr (value_bits > 16) { 86 | if ((n32 & 0xffff0000) != 0) count -= 16; 87 | } 88 | if constexpr (value_bits > 8) { 89 | if ((n32 & 0xff00ff00) != 0) count -= 8; 90 | } 91 | if ((n32 & 0xf0f0f0f0) != 0) count -= 4; 92 | if ((n32 & 0xcccccccc) != 0) count -= 2; 93 | if ((n32 & 0xaaaaaaaa) != 0) count -= 1; 94 | 95 | return count; 96 | #endif 97 | } 98 | 99 | template 100 | inline int countr_zero(UInt n) noexcept { 101 | static_assert(std::is_unsigned_v && value_bits <= 64); 102 | #if (defined(__GNUC__) || defined(__clang__)) && defined(__x86_64__) 103 | #define JKJ_HAS_COUNTR_ZERO_INTRINSIC 1 104 | if constexpr (std::is_same_v) { 105 | return __builtin_ctzl(n); 106 | } 107 | else if constexpr (std::is_same_v) { 108 | return __builtin_ctzll(n); 109 | } 110 | else { 111 | static_assert(sizeof(UInt) <= sizeof(unsigned int)); 112 | return __builtin_ctz((unsigned int)n); 113 | } 114 | #elif defined(_MSC_VER) && defined(_M_X64) 115 | #define JKJ_HAS_COUNTR_ZERO_INTRINSIC 1 116 | if constexpr (std::is_same_v) { 117 | return int(_tzcnt_u64(n)); 118 | } 119 | else { 120 | static_assert(sizeof(UInt) <= sizeof(unsigned int)); 121 | return int(_tzcnt_u32((unsigned int)n)); 122 | } 123 | #else 124 | #define JKJ_HAS_COUNTR_ZERO_INTRINSIC 0 125 | int count = int(value_bits); 126 | 127 | auto n32 = std::uint32_t(n); 128 | if constexpr (value_bits > 32) { 129 | if (n32 != 0) { 130 | count = 31; 131 | } 132 | else { 133 | n32 = std::uint32_t(n >> 32); 134 | if (n32 != 0) { 135 | count -= 1; 136 | } 137 | } 138 | } 139 | if constexpr (value_bits > 16) { 140 | if ((n32 & 0x0000ffff) != 0) count -= 16; 141 | } 142 | if constexpr (value_bits > 8) { 143 | if ((n32 & 0x00ff00ff) != 0) count -= 8; 144 | } 145 | if ((n32 & 0x0f0f0f0f) != 0) count -= 4; 146 | if ((n32 & 0x33333333) != 0) count -= 2; 147 | if ((n32 & 0x55555555) != 0) count -= 1; 148 | 149 | return count; 150 | #endif 151 | } 152 | } 153 | } 154 | } 155 | 156 | #endif -------------------------------------------------------------------------------- /include/jkj/fp/detail/div.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #ifndef JKJ_HEADER_FP_DIV 19 | #define JKJ_HEADER_FP_DIV 20 | 21 | #include "bits.h" 22 | #include "util.h" 23 | #include 24 | #include 25 | 26 | namespace jkj::fp { 27 | namespace detail { 28 | namespace div { 29 | template 30 | constexpr UInt modular_inverse(int bit_width = int(value_bits)) noexcept { 31 | // By Euler's theorem, a^phi(2^n) == 1 (mod 2^n), 32 | // where phi(2^n) = 2^(n-1), so the modular inverse of a is 33 | // a^(2^(n-1) - 1) = a^(1 + 2 + 2^2 + ... + 2^(n-2)). 34 | std::common_type_t mod_inverse = 1; 35 | for (int i = 1; i < bit_width; ++i) { 36 | mod_inverse = mod_inverse * mod_inverse * a; 37 | } 38 | if (bit_width < value_bits) { 39 | auto mask = UInt((UInt(1) << bit_width) - 1); 40 | return UInt(mod_inverse & mask); 41 | } 42 | else { 43 | return UInt(mod_inverse); 44 | } 45 | } 46 | 47 | template 48 | struct table_t { 49 | static_assert(std::is_unsigned_v); 50 | static_assert(a % 2 != 0); 51 | static_assert(N > 0); 52 | 53 | static constexpr int size = N; 54 | struct entry_t { 55 | UInt mod_inv; 56 | UInt max_quotient; 57 | } entries[N]; 58 | 59 | constexpr entry_t const& operator[](std::size_t idx) const noexcept { 60 | assert(idx < N); 61 | return entries[idx]; 62 | } 63 | constexpr entry_t& operator[](std::size_t idx) noexcept { 64 | assert(idx < N); 65 | return entries[idx]; 66 | } 67 | }; 68 | 69 | template 70 | struct table_holder { 71 | static constexpr table_t table = [] { 72 | constexpr auto mod_inverse = modular_inverse(); 73 | table_t table{}; 74 | std::common_type_t pow_of_mod_inverse = 1; 75 | UInt pow_of_a = 1; 76 | for (int i = 0; i < N; ++i) { 77 | table[i].mod_inv = UInt(pow_of_mod_inverse); 78 | table[i].max_quotient = UInt(std::numeric_limits::max() / pow_of_a); 79 | 80 | pow_of_mod_inverse *= mod_inverse; 81 | pow_of_a *= a; 82 | } 83 | 84 | return table; 85 | }(); 86 | }; 87 | 88 | // Prevent needless duplication of tables 89 | template 90 | struct default_table_size { 91 | static constexpr int value = 0; 92 | }; 93 | template <> 94 | struct default_table_size { 95 | static constexpr int value = 13; 96 | }; 97 | template <> 98 | struct default_table_size { 99 | static constexpr int value = 24; 100 | }; 101 | 102 | template 103 | constexpr bool divisible_by_power_of_5(UInt x, unsigned int exp) noexcept { 104 | auto const& table = table_holder::value ? 106 | default_table_size::value : table_size>::table; 107 | 108 | assert(exp < (unsigned int)(table.size)); 109 | return x * table[exp].mod_inv <= table[exp].max_quotient; 110 | } 111 | 112 | template 113 | constexpr bool divisible_by_power_of_2(UInt x, unsigned int exp) noexcept { 114 | assert(exp >= 1); 115 | assert(x != 0); 116 | #if JKJ_HAS_COUNTR_ZERO_INTRINSIC 117 | return bits::countr_zero(x) >= int(exp); 118 | #else 119 | if (exp >= int(value_bits)) { 120 | return false; 121 | } 122 | return x == ((x >> exp) << exp); 123 | #endif 124 | } 125 | } 126 | } 127 | } 128 | 129 | #include "undef_macros.h" 130 | #endif -------------------------------------------------------------------------------- /include/jkj/fp/detail/log.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #ifndef JKJ_HEADER_FP_LOG 19 | #define JKJ_HEADER_FP_LOG 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | namespace jkj::fp { 26 | namespace detail { 27 | namespace log { 28 | constexpr std::int32_t floor_shift( 29 | std::uint32_t integer_part, 30 | std::uint64_t fractional_digits, 31 | std::size_t shift_amount) noexcept 32 | { 33 | assert(shift_amount < 32); 34 | // Ensure no overflow 35 | assert(shift_amount == 0 || integer_part < (std::uint32_t(1) << (32 - shift_amount))); 36 | 37 | return shift_amount == 0 ? std::int32_t(integer_part) : 38 | std::int32_t( 39 | (integer_part << shift_amount) | 40 | (fractional_digits >> (64 - shift_amount))); 41 | } 42 | 43 | // Computes floor(e * c - s) 44 | template < 45 | std::uint32_t c_integer_part, 46 | std::uint64_t c_fractional_digits, 47 | std::size_t shift_amount, 48 | std::int32_t max_exponent, 49 | std::uint32_t s_integer_part = 0, 50 | std::uint64_t s_fractional_digits = 0 51 | > 52 | constexpr int compute(int e) noexcept { 53 | assert(e <= max_exponent && e >= -max_exponent); 54 | constexpr auto c = floor_shift(c_integer_part, c_fractional_digits, shift_amount); 55 | constexpr auto s = floor_shift(s_integer_part, s_fractional_digits, shift_amount); 56 | return int((std::int32_t(e) * c - s) >> shift_amount); 57 | } 58 | 59 | static constexpr std::uint64_t log10_2_fractional_digits{ 0x4d10'4d42'7de7'fbcc }; 60 | static constexpr std::uint64_t log10_4_over_3_fractional_digits{ 0x1ffb'fc2b'bc78'0375 }; 61 | constexpr std::size_t floor_log10_pow2_shift_amount = 22; 62 | static constexpr int floor_log10_pow2_input_limit = 1700; 63 | static constexpr int floor_log10_pow2_minus_log10_4_over_3_input_limit = 1700; 64 | 65 | static constexpr std::uint64_t log10_5_fractional_digits{ 0xb2ef'b2bd'8218'0433 }; 66 | constexpr std::size_t floor_log10_pow5_shift_amount = 20; 67 | static constexpr int floor_log10_pow5_input_limit = 2620; 68 | 69 | static constexpr std::uint64_t log2_10_fractional_digits{ 0x5269'e12f'346e'2bf9 }; 70 | constexpr std::size_t floor_log2_pow10_shift_amount = 19; 71 | static constexpr int floor_log2_pow5_input_limit = 1764; 72 | static constexpr int floor_log2_pow10_input_limit = 1233; 73 | 74 | static constexpr std::uint64_t log5_2_fractional_digits{ 0x6e40'd1a4'143d'cb94 }; 75 | static constexpr std::uint64_t log5_3_fractional_digits{ 0xaebf'4791'5d44'3b24 }; 76 | constexpr std::size_t floor_log5_pow2_shift_amount = 20; 77 | static constexpr int floor_log5_pow2_input_limit = 1492; 78 | static constexpr int floor_log5_pow2_minus_log5_3_input_limit = 2427; 79 | 80 | // For constexpr computation 81 | // Returns -1 when n = 0 82 | template 83 | constexpr int floor_log2(UInt n) noexcept { 84 | int count = -1; 85 | while (n != 0) { 86 | ++count; 87 | n >>= 1; 88 | } 89 | return count; 90 | } 91 | 92 | constexpr int floor_log10_pow2(int e) noexcept { 93 | using namespace log; 94 | return compute< 95 | 0, log10_2_fractional_digits, 96 | floor_log10_pow2_shift_amount, 97 | floor_log10_pow2_input_limit>(e); 98 | } 99 | 100 | constexpr int floor_log10_pow5(int e) noexcept { 101 | using namespace log; 102 | return compute< 103 | 0, log10_5_fractional_digits, 104 | floor_log10_pow5_shift_amount, 105 | floor_log10_pow5_input_limit>(e); 106 | } 107 | 108 | constexpr int floor_log2_pow5(int e) noexcept { 109 | using namespace log; 110 | return compute< 111 | 2, log2_10_fractional_digits, 112 | floor_log2_pow10_shift_amount, 113 | floor_log2_pow5_input_limit>(e); 114 | } 115 | 116 | constexpr int floor_log2_pow10(int e) noexcept { 117 | using namespace log; 118 | return compute< 119 | 3, log2_10_fractional_digits, 120 | floor_log2_pow10_shift_amount, 121 | floor_log2_pow10_input_limit>(e); 122 | } 123 | 124 | constexpr int floor_log5_pow2(int e) noexcept { 125 | using namespace log; 126 | return compute< 127 | 0, log5_2_fractional_digits, 128 | floor_log5_pow2_shift_amount, 129 | floor_log5_pow2_input_limit>(e); 130 | } 131 | 132 | constexpr int floor_log5_pow2_minus_log5_3(int e) noexcept { 133 | using namespace log; 134 | return compute< 135 | 0, log5_2_fractional_digits, 136 | floor_log5_pow2_shift_amount, 137 | floor_log5_pow2_minus_log5_3_input_limit, 138 | 0, log5_3_fractional_digits>(e); 139 | } 140 | 141 | constexpr int floor_log10_pow2_minus_log10_4_over_3(int e) noexcept { 142 | using namespace log; 143 | return compute< 144 | 0, log10_2_fractional_digits, 145 | floor_log10_pow2_shift_amount, 146 | floor_log10_pow2_minus_log10_4_over_3_input_limit, 147 | 0, log10_4_over_3_fractional_digits>(e); 148 | } 149 | } 150 | } 151 | } 152 | 153 | #endif -------------------------------------------------------------------------------- /include/jkj/fp/detail/macros.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | //////////////////////////////////////////////////////////// 19 | //////////// !!!! This header leaks macros !!!! //////////// 20 | //////////////////////////////////////////////////////////// 21 | 22 | // This header MUST be included AFTER all the other fp headers are included, 23 | // because some of the fp headers include undef_macros.h, which 24 | // undef's all the macros exported by this header. 25 | 26 | #ifndef JKJ_HEADER_FP_MACROS 27 | #define JKJ_HEADER_FP_MACROS 28 | 29 | #if defined(__GNUC__) || defined(__clang__) 30 | #define JKJ_SAFEBUFFERS 31 | #define JKJ_FORCEINLINE inline __attribute__((always_inline)) 32 | #define JKJ_EMPTY_BASE 33 | #elif defined(_MSC_VER) 34 | #define JKJ_SAFEBUFFERS __declspec(safebuffers) // Suppresses needless buffer overrun check. 35 | #define JKJ_FORCEINLINE __forceinline 36 | #define JKJ_EMPTY_BASE __declspec(empty_bases) 37 | #else 38 | #define JKJ_SAFEBUFFERS 39 | #define JKJ_FORCEINLINE inline 40 | #define JKJ_EMPTY_BASE 41 | #endif 42 | 43 | #endif -------------------------------------------------------------------------------- /include/jkj/fp/detail/undef_macros.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | // Undefines all leaked macros. 19 | #undef JKJ_SAFEBUFFERS 20 | #undef JKJ_FORCEINLINE 21 | #undef JKJ_HAS_COUNTR_ZERO_INTRINSIC 22 | #undef JKJ_HEADER_FP_MACROS -------------------------------------------------------------------------------- /include/jkj/fp/detail/util.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #ifndef JKJ_HEADER_FP_UTIL 19 | #define JKJ_HEADER_FP_UTIL 20 | 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | namespace jkj::fp { 27 | namespace detail { 28 | template 29 | constexpr std::size_t physical_bits = sizeof(T) * std::numeric_limits::digits; 30 | 31 | template 32 | constexpr std::size_t value_bits = 33 | std::numeric_limits, T>>::digits; 34 | 35 | template 36 | constexpr Int compute_power(Int a) noexcept { 37 | static_assert(k >= 0); 38 | Int p = 1; 39 | for (int i = 0; i < k; ++i) { 40 | p *= a; 41 | } 42 | return p; 43 | } 44 | 45 | template 46 | constexpr int count_factors(UInt n) noexcept { 47 | static_assert(a > 1); 48 | int c = 0; 49 | while (n % a == 0) { 50 | n /= a; 51 | ++c; 52 | } 53 | return c; 54 | } 55 | 56 | template 57 | struct pow_table_impl; 58 | 59 | template 60 | struct pow_table_impl> { 61 | static_assert(std::is_unsigned_v); 62 | static constexpr UInt table[] = { compute_power(a)... }; 63 | }; 64 | 65 | template 66 | using pow_table = pow_table_impl>; 67 | 68 | // C++20 std::remove_cvref_t 69 | template 70 | struct remove_cvref { 71 | using type = std::remove_cv_t>; 72 | }; 73 | template 74 | using remove_cvref_t = typename remove_cvref::type; 75 | 76 | // A simple utility class 77 | template 78 | struct typelist {}; 79 | } 80 | } 81 | 82 | #endif -------------------------------------------------------------------------------- /include/jkj/fp/to_chars/shortest_precise.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #ifndef JKJ_HEADER_FP_TO_CHARS_SHORTEST_PRECISE 19 | #define JKJ_HEADER_FP_TO_CHARS_SHORTEST_PRECISE 20 | 21 | #include "../ryu_printf.h" 22 | #include "../detail/bits.h" 23 | #include "to_chars_common.h" 24 | 25 | namespace jkj::fp { 26 | // Returns the next-to-end position. 27 | template 28 | char* to_chars_precise_scientific_n(Float x, char* buffer) 29 | { 30 | using ieee754_format_info = ieee754_format_info::format>; 31 | 32 | auto br = ieee754_bits(x); 33 | if (br.is_finite()) { 34 | if (br.is_negative()) { 35 | *buffer = '-'; 36 | ++buffer; 37 | } 38 | if (br.is_nonzero()) { 39 | // Print the exact value using Ryu-printf 40 | ryu_printf digit_gen{ x }; 41 | static_assert(ryu_printf::segment_size == 9); 42 | int exponent = 43 | -digit_gen.current_segment_index() * ryu_printf::segment_size; 44 | std::uint32_t current_segment; 45 | bool has_more_segments; 46 | 47 | auto case_handler = [&](auto holder) { 48 | constexpr auto length = decltype(holder)::value; 49 | constexpr auto divisor = detail::compute_power(std::uint32_t(10)); 50 | buffer[0] = char('0' + digit_gen.current_segment() / divisor); 51 | buffer[1] = '.'; 52 | buffer += 2; 53 | 54 | current_segment = digit_gen.current_segment() % divisor; 55 | has_more_segments = digit_gen.compute_next_segment(); 56 | 57 | if (has_more_segments) { 58 | buffer = detail::print_number(buffer, current_segment, length - 1); 59 | current_segment = digit_gen.current_segment(); 60 | has_more_segments = digit_gen.compute_next_segment(); 61 | } 62 | else { 63 | // Normalize. 64 | constexpr auto normalizer = detail::compute_power< 65 | ryu_printf::segment_size - length + 1>(std::uint32_t(10)); 66 | current_segment *= normalizer; 67 | assert(current_segment <= 9'9999'9999); 68 | } 69 | exponent += length - 1; 70 | }; 71 | if (digit_gen.current_segment() >= 1'0000'0000) { 72 | case_handler(std::integral_constant{}); 73 | } 74 | else if (digit_gen.current_segment() >= 1000'0000) { 75 | case_handler(std::integral_constant{}); 76 | } 77 | else if (digit_gen.current_segment() >= 100'0000) { 78 | case_handler(std::integral_constant{}); 79 | } 80 | else if (digit_gen.current_segment() >= 10'0000) { 81 | case_handler(std::integral_constant{}); 82 | } 83 | else if (digit_gen.current_segment() >= 1'0000) { 84 | case_handler(std::integral_constant{}); 85 | } 86 | else if (digit_gen.current_segment() >= 1000) { 87 | case_handler(std::integral_constant{}); 88 | } 89 | else if (digit_gen.current_segment() >= 100) { 90 | case_handler(std::integral_constant{}); 91 | } 92 | else if (digit_gen.current_segment() >= 10) { 93 | case_handler(std::integral_constant{}); 94 | } 95 | else { 96 | buffer[0] = char('0' + digit_gen.current_segment()); 97 | 98 | has_more_segments = digit_gen.compute_next_segment(); 99 | if (has_more_segments) { 100 | buffer[1] = '.'; 101 | buffer += 2; 102 | current_segment = digit_gen.current_segment(); 103 | has_more_segments = digit_gen.compute_next_segment(); 104 | } 105 | else { 106 | return buffer + 1; 107 | } 108 | } 109 | 110 | while (has_more_segments) { 111 | buffer = detail::print_nine_digits(buffer, current_segment); 112 | current_segment = digit_gen.current_segment(); 113 | has_more_segments = digit_gen.compute_next_segment(); 114 | } 115 | 116 | // Remove trailing zeros 117 | auto t = detail::bits::countr_zero(current_segment); 118 | if (t > ryu_printf::segment_size) { 119 | t = ryu_printf::segment_size; 120 | } 121 | 122 | constexpr auto const& divtable = 123 | detail::div::table_holder::segment_size>::table; 124 | 125 | int s = 0; 126 | for (; s < t - 1; s += 2) { 127 | if (current_segment * divtable[2].mod_inv > divtable[2].max_quotient) { 128 | break; 129 | } 130 | current_segment *= divtable[2].mod_inv; 131 | } 132 | if (s < t && current_segment * divtable[1].mod_inv <= divtable[1].max_quotient) 133 | { 134 | current_segment *= divtable[1].mod_inv; 135 | ++s; 136 | } 137 | current_segment >>= s; 138 | 139 | // Print the last segment 140 | buffer = detail::print_number(buffer, current_segment, ryu_printf::segment_size - s); 141 | 142 | // Print exponent 143 | if (exponent < 0) { 144 | std::memcpy(buffer, "e-", 2); 145 | exponent = -exponent; 146 | } 147 | else { 148 | std::memcpy(buffer, "e+", 2); 149 | } 150 | buffer += 2; 151 | buffer = detail::print_number(buffer, std::uint32_t(exponent), 152 | ieee754_traits::format == ieee754_format::binary32 ? 2 : 3); 153 | 154 | return buffer; 155 | } 156 | else { 157 | std::memcpy(buffer, "0e0", 3); 158 | return buffer + 3; 159 | } 160 | } 161 | else { 162 | if ((br.u << (ieee754_format_info::exponent_bits + 1)) != 0) 163 | { 164 | std::memcpy(buffer, "nan", 3); 165 | return buffer + 3; 166 | } 167 | else { 168 | if (br.is_negative()) { 169 | *buffer = '-'; 170 | ++buffer; 171 | } 172 | std::memcpy(buffer, "Infinity", 8); 173 | return buffer + 8; 174 | } 175 | } 176 | } 177 | 178 | // Null-terminates and bypass the return value of fp_to_chars_n. 179 | template 180 | char* to_chars_precise_scientific(Float x, char* buffer) 181 | { 182 | auto ptr = to_chars_precise_scientific_n(x, buffer); 183 | *ptr = '\0'; 184 | return ptr; 185 | } 186 | } 187 | 188 | #include "../detail/undef_macros.h" 189 | #endif 190 | 191 | -------------------------------------------------------------------------------- /include/jkj/fp/to_chars/shortest_roundtrip.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #ifndef JKJ_HEADER_FP_TO_CHARS_SHORTEST_ROUNDTRIP 19 | #define JKJ_HEADER_FP_TO_CHARS_SHORTEST_ROUNDTRIP 20 | 21 | #include "../dragonbox.h" 22 | 23 | namespace jkj::fp { 24 | namespace detail { 25 | char* to_chars_shortest_scientific_n_impl(unsigned_decimal_fp v, char* buffer); 26 | char* to_chars_shortest_scientific_n_impl(unsigned_decimal_fp v, char* buffer); 27 | } 28 | 29 | // Returns the next-to-end position. 30 | template 31 | char* to_chars_shortest_scientific_n(Float x, char* buffer, Policies&&... policies) 32 | { 33 | using namespace jkj::fp::detail::policy; 34 | using policy_holder_t = decltype(make_policy_holder( 35 | make_default_list( 36 | make_default(policy::trailing_zero::remove), 37 | make_default(policy::binary_rounding::nearest_to_even), 38 | make_default(policy::decimal_rounding::to_even), 39 | make_default(policy::cache::fast)), 40 | std::forward(policies)...)); 41 | 42 | static_assert(!policy_holder_t::report_trailing_zeros, 43 | "jkj::fp::policy::trailing_zero::report is not valid for to_chars & to_chars_n"); 44 | 45 | using ieee754_format_info = ieee754_format_info::format>; 46 | 47 | auto br = ieee754_bits(x); 48 | if (br.is_finite()) { 49 | if (br.is_negative()) { 50 | *buffer = '-'; 51 | ++buffer; 52 | } 53 | if (br.is_nonzero()) { 54 | return detail::to_chars_shortest_scientific_n_impl(to_shortest_decimal(x, 55 | policy::sign::ignore, 56 | std::forward(policies)...), 57 | buffer); 58 | } 59 | else { 60 | std::memcpy(buffer, "0E0", 3); 61 | return buffer + 3; 62 | } 63 | } 64 | else { 65 | if ((br.u << (ieee754_format_info::exponent_bits + 1)) != 0) 66 | { 67 | std::memcpy(buffer, "NaN", 3); 68 | return buffer + 3; 69 | } 70 | else { 71 | if (br.is_negative()) { 72 | *buffer = '-'; 73 | ++buffer; 74 | } 75 | std::memcpy(buffer, "Infinity", 8); 76 | return buffer + 8; 77 | } 78 | } 79 | } 80 | 81 | // Null-terminates and bypass the return value of fp_to_chars_n. 82 | template 83 | char* to_chars_shortest_scientific(Float x, char* buffer, Policies... policies) 84 | { 85 | auto ptr = to_chars_shortest_scientific_n(x, buffer, policies...); 86 | *ptr = '\0'; 87 | return ptr; 88 | } 89 | } 90 | 91 | #endif 92 | 93 | -------------------------------------------------------------------------------- /include/jkj/fp/to_chars/to_chars_common.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #ifndef JKJ_HEADER_FP_TO_CHARS_COMMON 19 | #define JKJ_HEADER_FP_TO_CHARS_COMMON 20 | 21 | #include "../detail/log.h" 22 | #include "../detail/util.h" 23 | #include "../detail/macros.h" 24 | 25 | namespace jkj::fp { 26 | namespace detail { 27 | extern char const radix_100_table[200]; 28 | 29 | template 30 | JKJ_FORCEINLINE constexpr std::uint32_t decimal_length(UInt const x) noexcept { 31 | static_assert(max_length > 0); 32 | static_assert(max_length <= log::floor_log10_pow2(value_bits)); 33 | constexpr auto threshold = compute_power(UInt(10)); 34 | assert(x < compute_power(UInt(10))); 35 | 36 | if constexpr (max_length == 1) { 37 | return 1; 38 | } 39 | else { 40 | if (x >= threshold) { 41 | return max_length; 42 | } 43 | else { 44 | return decimal_length(x); 45 | } 46 | } 47 | } 48 | 49 | char* print_number(char* buffer, std::uint32_t number, int length) noexcept; 50 | char* print_nine_digits(char* buffer, std::uint32_t number) noexcept; 51 | char* print_zeros(char* buffer, int length) noexcept; 52 | char* print_nines(char* buffer, int length) noexcept; 53 | } 54 | } 55 | 56 | #endif -------------------------------------------------------------------------------- /source/to_chars/LICENSE-Boost: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /subproject/3rdparty/fmt/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14 FATAL_ERROR) 2 | 3 | project(fmt_minimal LANGUAGES CXX) 4 | 5 | add_library(fmt INTERFACE) 6 | add_library(fmt::fmt ALIAS fmt) 7 | 8 | target_compile_features(fmt INTERFACE cxx_std_17) 9 | 10 | target_include_directories(fmt 11 | INTERFACE 12 | $) 13 | 14 | # ---- MSVC Specifics ---- 15 | if (MSVC) 16 | # No need to not generate PDB 17 | target_compile_options(fmt INTERFACE 18 | /Zi $<$:/GL>) 19 | endif() -------------------------------------------------------------------------------- /subproject/3rdparty/grisu_exact/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14 FATAL_ERROR) 2 | 3 | project(grisu_exact LANGUAGES CXX) 4 | 5 | add_library(grisu_exact STATIC fp_to_chars.h fp_to_chars.cpp grisu_exact.h) 6 | add_library(grisu_exact::grisu_exact ALIAS grisu_exact) 7 | 8 | target_compile_features(grisu_exact PUBLIC cxx_std_17) 9 | 10 | target_include_directories(grisu_exact 11 | PUBLIC 12 | $) 13 | 14 | # ---- MSVC Specifics ---- 15 | if (MSVC) 16 | # No need to not generate PDB 17 | # /permissive- should be the default 18 | # The compilation will fail without /experimental:newLambdaProcessor 19 | # See also https://gitlab.kitware.com/cmake/cmake/-/issues/16478 20 | target_compile_options(grisu_exact PUBLIC 21 | /Zi /permissive- 22 | $<$>:/experimental:newLambdaProcessor> 23 | $<$:/GL>) 24 | endif() 25 | set_target_properties(grisu_exact PROPERTIES FOLDER fp/extern) -------------------------------------------------------------------------------- /subproject/3rdparty/grisu_exact/fp_to_chars.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #ifndef JKJ_FP_TO_CHARS 19 | #define JKJ_FP_TO_CHARS 20 | 21 | #include "grisu_exact.h" 22 | 23 | namespace jkj { 24 | namespace fp_to_chars_detail { 25 | char* float_to_chars(unsigned_fp_t v, char* buffer); 26 | char* double_to_chars(unsigned_fp_t v, char* buffer); 27 | } 28 | 29 | // Returns the next-to-end position 30 | template 34 | char* fp_to_chars_n(Float x, char* buffer, 35 | RoundingMode&& rounding_mode = {}, 36 | CorrectRoundingSearch&& crs = {}) 37 | { 38 | auto br = get_bit_representation(x); 39 | if (br.is_finite()) { 40 | if (br.is_negative()) { 41 | *buffer = '-'; 42 | ++buffer; 43 | } 44 | if (br.is_nonzero()) { 45 | if constexpr (sizeof(Float) == 4) { 46 | return fp_to_chars_detail::float_to_chars(grisu_exact(x, 47 | std::forward(rounding_mode), 48 | std::forward(crs)), buffer); 49 | } 50 | else { 51 | return fp_to_chars_detail::double_to_chars(grisu_exact(x, 52 | std::forward(rounding_mode), 53 | std::forward(crs)), buffer); 54 | } 55 | } 56 | else { 57 | std::memcpy(buffer, "0E0", 3); 58 | return buffer + 3; 59 | } 60 | } 61 | else { 62 | if ((br.f << (grisu_exact_detail::common_info::exponent_bits + 1)) != 0) 63 | { 64 | std::memcpy(buffer, "NaN", 3); 65 | return buffer + 3; 66 | } 67 | else { 68 | if (br.is_negative()) { 69 | *buffer = '-'; 70 | ++buffer; 71 | } 72 | std::memcpy(buffer, "Infinity", 8); 73 | return buffer + 8; 74 | } 75 | } 76 | } 77 | 78 | // Null-terminate and bypass the return value of fp_to_chars_n 79 | template 83 | char* fp_to_chars(Float x, char* buffer, 84 | RoundingMode&& rounding_mode = {}, 85 | CorrectRoundingSearch&& crs = {}) 86 | { 87 | auto ptr = fp_to_chars_n(x, buffer, 88 | std::forward(rounding_mode), 89 | std::forward(crs)); 90 | *ptr = '\0'; 91 | return ptr; 92 | } 93 | } 94 | 95 | #endif 96 | -------------------------------------------------------------------------------- /subproject/3rdparty/ryu/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14 FATAL_ERROR) 2 | 3 | project(ryu_cmake LANGUAGES C) 4 | 5 | add_library(ryu STATIC 6 | ryu/ryu.h ryu/common.h ryu/f2s.c ryu/d2s.c 7 | ryu/f2s_intrinsics.h ryu/f2s_full_table.h 8 | ryu/d2s_intrinsics.h ryu/d2s_full_table.h 9 | ryu/d2fixed.c ryu/d2fixed_full_table.h 10 | ryu/ryu_parse.h ryu/s2d.c ryu/s2f.c 11 | ryu/digit_table.h) 12 | add_library(ryu::ryu ALIAS ryu) 13 | 14 | target_compile_features(ryu PUBLIC cxx_std_17) 15 | 16 | target_include_directories(ryu 17 | PUBLIC 18 | $) 19 | 20 | # ---- MSVC Specifics ---- 21 | if (MSVC) 22 | # No need to not generate PDB 23 | target_compile_options(ryu PUBLIC 24 | /Zi $<$:/GL>) 25 | endif() 26 | set_target_properties(ryu PROPERTIES FOLDER fp/extern) -------------------------------------------------------------------------------- /subproject/3rdparty/ryu/ryu/LICENSE-Boost: -------------------------------------------------------------------------------- 1 | Boost Software License - Version 1.0 - August 17th, 2003 2 | 3 | Permission is hereby granted, free of charge, to any person or organization 4 | obtaining a copy of the software and accompanying documentation covered by 5 | this license (the "Software") to use, reproduce, display, distribute, 6 | execute, and transmit the Software, and to prepare derivative works of the 7 | Software, and to permit third-parties to whom the Software is furnished to 8 | do so, all subject to the following: 9 | 10 | The copyright notices in the Software and this entire statement, including 11 | the above license grant, this restriction and the following disclaimer, 12 | must be included in all copies of the Software, in whole or in part, and 13 | all derivative works of the Software, unless such copies or derivative 14 | works are solely in the form of machine-executable object code generated by 15 | a source language processor. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 20 | SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 21 | FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 22 | ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /subproject/3rdparty/ryu/ryu/common.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Ulf Adams 2 | // 3 | // The contents of this file may be used under the terms of the Apache License, 4 | // Version 2.0. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // http://www.apache.org/licenses/LICENSE-2.0) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | #ifndef RYU_COMMON_H 18 | #define RYU_COMMON_H 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #if defined(_M_IX86) || defined(_M_ARM) 25 | #define RYU_32_BIT_PLATFORM 26 | #endif 27 | 28 | // Returns the number of decimal digits in v, which must not contain more than 9 digits. 29 | static inline uint32_t decimalLength9(const uint32_t v) { 30 | // Function precondition: v is not a 10-digit number. 31 | // (f2s: 9 digits are sufficient for round-tripping.) 32 | // (d2fixed: We print 9-digit blocks.) 33 | assert(v < 1000000000); 34 | if (v >= 100000000) { return 9; } 35 | if (v >= 10000000) { return 8; } 36 | if (v >= 1000000) { return 7; } 37 | if (v >= 100000) { return 6; } 38 | if (v >= 10000) { return 5; } 39 | if (v >= 1000) { return 4; } 40 | if (v >= 100) { return 3; } 41 | if (v >= 10) { return 2; } 42 | return 1; 43 | } 44 | 45 | // Returns e == 0 ? 1 : [log_2(5^e)]; requires 0 <= e <= 3528. 46 | static inline int32_t log2pow5(const int32_t e) { 47 | // This approximation works up to the point that the multiplication overflows at e = 3529. 48 | // If the multiplication were done in 64 bits, it would fail at 5^4004 which is just greater 49 | // than 2^9297. 50 | assert(e >= 0); 51 | assert(e <= 3528); 52 | return (int32_t) ((((uint32_t) e) * 1217359) >> 19); 53 | } 54 | 55 | // Returns e == 0 ? 1 : ceil(log_2(5^e)); requires 0 <= e <= 3528. 56 | static inline int32_t pow5bits(const int32_t e) { 57 | // This approximation works up to the point that the multiplication overflows at e = 3529. 58 | // If the multiplication were done in 64 bits, it would fail at 5^4004 which is just greater 59 | // than 2^9297. 60 | assert(e >= 0); 61 | assert(e <= 3528); 62 | return (int32_t) (((((uint32_t) e) * 1217359) >> 19) + 1); 63 | } 64 | 65 | // Returns e == 0 ? 1 : ceil(log_2(5^e)); requires 0 <= e <= 3528. 66 | static inline int32_t ceil_log2pow5(const int32_t e) { 67 | return log2pow5(e) + 1; 68 | } 69 | 70 | // Returns floor(log_10(2^e)); requires 0 <= e <= 1650. 71 | static inline uint32_t log10Pow2(const int32_t e) { 72 | // The first value this approximation fails for is 2^1651 which is just greater than 10^297. 73 | assert(e >= 0); 74 | assert(e <= 1650); 75 | return (((uint32_t) e) * 78913) >> 18; 76 | } 77 | 78 | // Returns floor(log_10(5^e)); requires 0 <= e <= 2620. 79 | static inline uint32_t log10Pow5(const int32_t e) { 80 | // The first value this approximation fails for is 5^2621 which is just greater than 10^1832. 81 | assert(e >= 0); 82 | assert(e <= 2620); 83 | return (((uint32_t) e) * 732923) >> 20; 84 | } 85 | 86 | static inline int copy_special_str(char * const result, const bool sign, const bool exponent, const bool mantissa) { 87 | if (mantissa) { 88 | memcpy(result, "NaN", 3); 89 | return 3; 90 | } 91 | if (sign) { 92 | result[0] = '-'; 93 | } 94 | if (exponent) { 95 | memcpy(result + sign, "Infinity", 8); 96 | return sign + 8; 97 | } 98 | memcpy(result + sign, "0E0", 3); 99 | return sign + 3; 100 | } 101 | 102 | static inline uint32_t float_to_bits(const float f) { 103 | uint32_t bits = 0; 104 | memcpy(&bits, &f, sizeof(float)); 105 | return bits; 106 | } 107 | 108 | static inline uint64_t double_to_bits(const double d) { 109 | uint64_t bits = 0; 110 | memcpy(&bits, &d, sizeof(double)); 111 | return bits; 112 | } 113 | 114 | #endif // RYU_COMMON_H 115 | -------------------------------------------------------------------------------- /subproject/3rdparty/ryu/ryu/digit_table.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Ulf Adams 2 | // 3 | // The contents of this file may be used under the terms of the Apache License, 4 | // Version 2.0. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // http://www.apache.org/licenses/LICENSE-2.0) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | #ifndef RYU_DIGIT_TABLE_H 18 | #define RYU_DIGIT_TABLE_H 19 | 20 | // A table of all two-digit numbers. This is used to speed up decimal digit 21 | // generation by copying pairs of digits into the final output. 22 | static const char DIGIT_TABLE[200] = { 23 | '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9', 24 | '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9', 25 | '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9', 26 | '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9', 27 | '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9', 28 | '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9', 29 | '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9', 30 | '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9', 31 | '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9', 32 | '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9' 33 | }; 34 | 35 | #endif // RYU_DIGIT_TABLE_H 36 | -------------------------------------------------------------------------------- /subproject/3rdparty/ryu/ryu/f2s_full_table.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Ulf Adams 2 | // 3 | // The contents of this file may be used under the terms of the Apache License, 4 | // Version 2.0. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // http://www.apache.org/licenses/LICENSE-2.0) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | #ifndef RYU_F2S_FULL_TABLE_H 18 | #define RYU_F2S_FULL_TABLE_H 19 | 20 | // This table is generated by PrintFloatLookupTable. 21 | #define FLOAT_POW5_INV_BITCOUNT 59 22 | #define FLOAT_POW5_BITCOUNT 61 23 | 24 | static uint64_t FLOAT_POW5_INV_SPLIT[55] = { 25 | 576460752303423489u, 461168601842738791u, 368934881474191033u, 295147905179352826u, 26 | 472236648286964522u, 377789318629571618u, 302231454903657294u, 483570327845851670u, 27 | 386856262276681336u, 309485009821345069u, 495176015714152110u, 396140812571321688u, 28 | 316912650057057351u, 507060240091291761u, 405648192073033409u, 324518553658426727u, 29 | 519229685853482763u, 415383748682786211u, 332306998946228969u, 531691198313966350u, 30 | 425352958651173080u, 340282366920938464u, 544451787073501542u, 435561429658801234u, 31 | 348449143727040987u, 557518629963265579u, 446014903970612463u, 356811923176489971u, 32 | 570899077082383953u, 456719261665907162u, 365375409332725730u, 292300327466180584u, 33 | 467680523945888934u, 374144419156711148u, 299315535325368918u, 478904856520590269u, 34 | 383123885216472215u, 306499108173177772u, 490398573077084435u, 392318858461667548u, 35 | 313855086769334039u, 502168138830934462u, 401734511064747569u, 321387608851798056u, 36 | 514220174162876889u, 411376139330301511u, 329100911464241209u, 526561458342785934u, 37 | 421249166674228747u, 336999333339382998u, 539198933343012796u, 431359146674410237u, 38 | 345087317339528190u, 552139707743245103u, 441711766194596083u 39 | }; 40 | static const uint64_t FLOAT_POW5_SPLIT[47] = { 41 | 1152921504606846976u, 1441151880758558720u, 1801439850948198400u, 2251799813685248000u, 42 | 1407374883553280000u, 1759218604441600000u, 2199023255552000000u, 1374389534720000000u, 43 | 1717986918400000000u, 2147483648000000000u, 1342177280000000000u, 1677721600000000000u, 44 | 2097152000000000000u, 1310720000000000000u, 1638400000000000000u, 2048000000000000000u, 45 | 1280000000000000000u, 1600000000000000000u, 2000000000000000000u, 1250000000000000000u, 46 | 1562500000000000000u, 1953125000000000000u, 1220703125000000000u, 1525878906250000000u, 47 | 1907348632812500000u, 1192092895507812500u, 1490116119384765625u, 1862645149230957031u, 48 | 1164153218269348144u, 1455191522836685180u, 1818989403545856475u, 2273736754432320594u, 49 | 1421085471520200371u, 1776356839400250464u, 2220446049250313080u, 1387778780781445675u, 50 | 1734723475976807094u, 2168404344971008868u, 1355252715606880542u, 1694065894508600678u, 51 | 2117582368135750847u, 1323488980084844279u, 1654361225106055349u, 2067951531382569187u, 52 | 1292469707114105741u, 1615587133892632177u, 2019483917365790221u 53 | }; 54 | 55 | #endif // RYU_F2S_FULL_TABLE_H 56 | -------------------------------------------------------------------------------- /subproject/3rdparty/ryu/ryu/f2s_intrinsics.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Ulf Adams 2 | // 3 | // The contents of this file may be used under the terms of the Apache License, 4 | // Version 2.0. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // http://www.apache.org/licenses/LICENSE-2.0) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | #ifndef RYU_F2S_INTRINSICS_H 18 | #define RYU_F2S_INTRINSICS_H 19 | 20 | // Defines RYU_32_BIT_PLATFORM if applicable. 21 | #include "ryu/common.h" 22 | 23 | #if defined(RYU_FLOAT_FULL_TABLE) 24 | 25 | #include "ryu/f2s_full_table.h" 26 | 27 | #else 28 | 29 | #if defined(RYU_OPTIMIZE_SIZE) 30 | #include "ryu/d2s_small_table.h" 31 | #else 32 | #include "ryu/d2s_full_table.h" 33 | #endif 34 | #define FLOAT_POW5_INV_BITCOUNT (DOUBLE_POW5_INV_BITCOUNT - 64) 35 | #define FLOAT_POW5_BITCOUNT (DOUBLE_POW5_BITCOUNT - 64) 36 | 37 | #endif 38 | 39 | static inline uint32_t pow5factor_32(uint32_t value) { 40 | uint32_t count = 0; 41 | for (;;) { 42 | assert(value != 0); 43 | const uint32_t q = value / 5; 44 | const uint32_t r = value % 5; 45 | if (r != 0) { 46 | break; 47 | } 48 | value = q; 49 | ++count; 50 | } 51 | return count; 52 | } 53 | 54 | // Returns true if value is divisible by 5^p. 55 | static inline bool multipleOfPowerOf5_32(const uint32_t value, const uint32_t p) { 56 | return pow5factor_32(value) >= p; 57 | } 58 | 59 | // Returns true if value is divisible by 2^p. 60 | static inline bool multipleOfPowerOf2_32(const uint32_t value, const uint32_t p) { 61 | // __builtin_ctz doesn't appear to be faster here. 62 | return (value & ((1u << p) - 1)) == 0; 63 | } 64 | 65 | // It seems to be slightly faster to avoid uint128_t here, although the 66 | // generated code for uint128_t looks slightly nicer. 67 | static inline uint32_t mulShift32(const uint32_t m, const uint64_t factor, const int32_t shift) { 68 | assert(shift > 32); 69 | 70 | // The casts here help MSVC to avoid calls to the __allmul library 71 | // function. 72 | const uint32_t factorLo = (uint32_t)(factor); 73 | const uint32_t factorHi = (uint32_t)(factor >> 32); 74 | const uint64_t bits0 = (uint64_t)m * factorLo; 75 | const uint64_t bits1 = (uint64_t)m * factorHi; 76 | 77 | #if defined(RYU_32_BIT_PLATFORM) 78 | // On 32-bit platforms we can avoid a 64-bit shift-right since we only 79 | // need the upper 32 bits of the result and the shift value is > 32. 80 | const uint32_t bits0Hi = (uint32_t)(bits0 >> 32); 81 | uint32_t bits1Lo = (uint32_t)(bits1); 82 | uint32_t bits1Hi = (uint32_t)(bits1 >> 32); 83 | bits1Lo += bits0Hi; 84 | bits1Hi += (bits1Lo < bits0Hi); 85 | if (shift >= 64) { 86 | // s2f can call this with a shift value >= 64, which we have to handle. 87 | // This could now be slower than the !defined(RYU_32_BIT_PLATFORM) case. 88 | return (uint32_t)(bits1Hi >> (shift - 64)); 89 | } else { 90 | const int32_t s = shift - 32; 91 | return (bits1Hi << (32 - s)) | (bits1Lo >> s); 92 | } 93 | #else // RYU_32_BIT_PLATFORM 94 | const uint64_t sum = (bits0 >> 32) + bits1; 95 | const uint64_t shiftedSum = sum >> (shift - 32); 96 | assert(shiftedSum <= UINT32_MAX); 97 | return (uint32_t) shiftedSum; 98 | #endif // RYU_32_BIT_PLATFORM 99 | } 100 | 101 | static inline uint32_t mulPow5InvDivPow2(const uint32_t m, const uint32_t q, const int32_t j) { 102 | #if defined(RYU_FLOAT_FULL_TABLE) 103 | return mulShift32(m, FLOAT_POW5_INV_SPLIT[q], j); 104 | #elif defined(RYU_OPTIMIZE_SIZE) 105 | // The inverse multipliers are defined as [2^x / 5^y] + 1; the upper 64 bits from the double lookup 106 | // table are the correct bits for [2^x / 5^y], so we have to add 1 here. Note that we rely on the 107 | // fact that the added 1 that's already stored in the table never overflows into the upper 64 bits. 108 | uint64_t pow5[2]; 109 | double_computeInvPow5(q, pow5); 110 | return mulShift32(m, pow5[1] + 1, j); 111 | #else 112 | return mulShift32(m, DOUBLE_POW5_INV_SPLIT[q][1] + 1, j); 113 | #endif 114 | } 115 | 116 | static inline uint32_t mulPow5divPow2(const uint32_t m, const uint32_t i, const int32_t j) { 117 | #if defined(RYU_FLOAT_FULL_TABLE) 118 | return mulShift32(m, FLOAT_POW5_SPLIT[i], j); 119 | #elif defined(RYU_OPTIMIZE_SIZE) 120 | uint64_t pow5[2]; 121 | double_computePow5(i, pow5); 122 | return mulShift32(m, pow5[1], j); 123 | #else 124 | return mulShift32(m, DOUBLE_POW5_SPLIT[i][1], j); 125 | #endif 126 | } 127 | 128 | #endif // RYU_F2S_INTRINSICS_H 129 | -------------------------------------------------------------------------------- /subproject/3rdparty/ryu/ryu/ryu.h: -------------------------------------------------------------------------------- 1 | // Copyright 2018 Ulf Adams 2 | // 3 | // The contents of this file may be used under the terms of the Apache License, 4 | // Version 2.0. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // http://www.apache.org/licenses/LICENSE-2.0) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | #ifndef RYU_H 18 | #define RYU_H 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | #include 25 | 26 | int d2s_buffered_n(double f, char* result); 27 | void d2s_buffered(double f, char* result); 28 | char* d2s(double f); 29 | 30 | int f2s_buffered_n(float f, char* result); 31 | void f2s_buffered(float f, char* result); 32 | char* f2s(float f); 33 | 34 | int d2fixed_buffered_n(double d, uint32_t precision, char* result); 35 | void d2fixed_buffered(double d, uint32_t precision, char* result); 36 | char* d2fixed(double d, uint32_t precision); 37 | 38 | int d2exp_buffered_n(double d, uint32_t precision, char* result); 39 | void d2exp_buffered(double d, uint32_t precision, char* result); 40 | char* d2exp(double d, uint32_t precision); 41 | 42 | #ifdef __cplusplus 43 | } 44 | #endif 45 | 46 | #endif // RYU_H 47 | -------------------------------------------------------------------------------- /subproject/3rdparty/ryu/ryu/ryu_parse.h: -------------------------------------------------------------------------------- 1 | // Copyright 2019 Ulf Adams 2 | // 3 | // The contents of this file may be used under the terms of the Apache License, 4 | // Version 2.0. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // http://www.apache.org/licenses/LICENSE-2.0) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | #ifndef RYU_PARSE_H 18 | #define RYU_PARSE_H 19 | 20 | #ifdef __cplusplus 21 | extern "C" { 22 | #endif 23 | 24 | // This is an experimental implementation of parsing strings to 64-bit floats 25 | // using a Ryu-like algorithm. At this time, it only support up to 17 non-zero 26 | // digits in the input, and also does not support all formats. Use at your own 27 | // risk. 28 | // 29 | // This implementation does not currently support -DRYU_OPTIMIZE_SIZE and always 30 | // compiles against the large lookup tables. 31 | 32 | enum Status { 33 | SUCCESS, 34 | INPUT_TOO_SHORT, 35 | INPUT_TOO_LONG, 36 | MALFORMED_INPUT 37 | }; 38 | 39 | enum Status s2d_n(const char * buffer, const int len, double * result); 40 | enum Status s2d(const char * buffer, double * result); 41 | 42 | enum Status s2f_n(const char * buffer, const int len, float * result); 43 | enum Status s2f(const char * buffer, float * result); 44 | 45 | #ifdef __cplusplus 46 | } 47 | #endif 48 | 49 | #endif // RYU_PARSE_H -------------------------------------------------------------------------------- /subproject/3rdparty/schubfach/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14 FATAL_ERROR) 2 | 3 | project(schubfach LANGUAGES CXX) 4 | 5 | add_library(schubfach STATIC 6 | schubfach_32.cc schubfach_32.h schubfach_64.cc schubfach_64.h) 7 | add_library(schubfach::schubfach ALIAS schubfach) 8 | 9 | target_compile_features(schubfach PUBLIC cxx_std_17) 10 | 11 | target_include_directories(schubfach 12 | PUBLIC 13 | $) 14 | 15 | # ---- MSVC Specifics ---- 16 | if (MSVC) 17 | # No need to not generate PDB 18 | # /permissive- should be the default 19 | target_compile_options(schubfach PUBLIC 20 | /Zi /permissive- 21 | $<$:/GL>) 22 | endif() 23 | set_target_properties(schubfach PROPERTIES FOLDER fp/extern) -------------------------------------------------------------------------------- /subproject/3rdparty/schubfach/schubfach_32.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Alexander Bolz 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #pragma once 7 | 8 | namespace schubfach { 9 | 10 | // char* output_end = Ftoa(buffer, value); 11 | // 12 | // Converts the given single-precision number into decimal form and stores the result in the given 13 | // buffer. 14 | // 15 | // The buffer must be large enough, i.e. >= FtoaMinBufferLength. 16 | // The output format is similar to printf("%g"). 17 | // The output is _not_ null-terminted. 18 | // 19 | // The output is optimal, i.e. the output string 20 | // 1. rounds back to the input number when read in (using round-to-nearest-even) 21 | // 2. is as short as possible, 22 | // 3. is as close to the input number as possible. 23 | // 24 | // Note: 25 | // This function may temporarily write up to FtoaMinBufferLength characters into the buffer. 26 | 27 | constexpr int FtoaMinBufferLength = 32; 28 | 29 | char* Ftoa(char* buffer, float value); 30 | 31 | } // namespace schubfach 32 | 33 | -------------------------------------------------------------------------------- /subproject/3rdparty/schubfach/schubfach_64.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Alexander Bolz 2 | // 3 | // Distributed under the Boost Software License, Version 1.0. 4 | // (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt) 5 | 6 | #pragma once 7 | 8 | namespace schubfach { 9 | 10 | // char* output_end = Dtoa(buffer, value); 11 | // 12 | // Converts the given double-precision number into decimal form and stores the result in the given 13 | // buffer. 14 | // 15 | // The buffer must be large enough, i.e. >= DtoaMinBufferLength. 16 | // The output format is similar to printf("%g"). 17 | // The output is _not_ null-terminted. 18 | // 19 | // The output is optimal, i.e. the output string 20 | // 1. rounds back to the input number when read in (using round-to-nearest-even) 21 | // 2. is as short as possible, 22 | // 3. is as close to the input number as possible. 23 | // 24 | // Note: 25 | // This function may temporarily write up to DtoaMinBufferLength characters into the buffer. 26 | 27 | constexpr int DtoaMinBufferLength = 64; 28 | 29 | char* Dtoa(char* buffer, double value); 30 | 31 | } // namespace schubfach 32 | 33 | -------------------------------------------------------------------------------- /subproject/3rdparty/shaded_plots/example_shaded_plots.m: -------------------------------------------------------------------------------- 1 | %% Shaded line plot 2 | % Example showing the difference between the standard plot routine and the 3 | % shaded routine 4 | 5 | x = -2*pi:pi/100:2*pi; 6 | fx = sin(x); 7 | 8 | figure('Color','w'); 9 | subplot(1,2,1); 10 | hold on 11 | plot(x,fx); 12 | plot(2*x+pi/2,0.5*fx+0.1*x); 13 | hold off 14 | title('plot'); 15 | 16 | subplot(1,2,2); 17 | hold on 18 | plot_shaded(x,fx); 19 | plot_shaded(2*x+pi/2,0.5*fx+0.1*x); 20 | hold off 21 | title('plot\_shaded'); 22 | 23 | %% Histogram plot 24 | % Plots two histograms for two different distributions 25 | 26 | X1 = 3 + 2.0*randn([100000,1]); 27 | X2 = 12 + 4.0*randn([100000,1]); 28 | 29 | figure('Color','w'); 30 | hold on 31 | plot_histogram_shaded(X1,'Alpha',0.3); 32 | plot_histogram_shaded(X2); 33 | hold off 34 | title('plot\_histogram\_shaded'); 35 | 36 | 37 | %% Distribution plots 38 | % Show different plot routines to visualize measurement errors/noise 39 | 40 | X = 1:0.25:10; 41 | Y = sin(X)+0.25*X; 42 | Y_error = randn(1000,numel(Y)); 43 | Y_noisy = Y+Y_error.*repmat(0.1*X,[size(Y_error,1) 1]); 44 | 45 | 46 | figure('Color','w'); 47 | subplot(3,1,1); 48 | plot(X,Y,'LineWidth',1.5); 49 | title('plot (True value y=f(x))'); 50 | ylim([-1 5]); 51 | 52 | subplot(3,1,2); 53 | hold on 54 | plot(X,Y,'LineWidth',1.5); 55 | plot_distribution(X,Y_noisy); 56 | hold off 57 | title('plot\_distribution'); 58 | ylim([-1 5]); 59 | 60 | subplot(3,1,3); 61 | hold on 62 | plot(X,Y,'LineWidth',1.5); 63 | plot_distribution_prctile(X,Y_noisy,'Prctile',[25 50 75 90]); 64 | hold off 65 | title('plot\_distribution\_prctile'); 66 | ylim([-1 5]); 67 | 68 | 69 | -------------------------------------------------------------------------------- /subproject/3rdparty/shaded_plots/license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2018, John A. Onofrey 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution 13 | * Neither the name of Yale University nor the names of its 14 | contributors may be used to endorse or promote products derived from this 15 | software without specific prior written permission. 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /subproject/3rdparty/shaded_plots/plot_distribution.m: -------------------------------------------------------------------------------- 1 | function plot_distribution(varargin) 2 | % PLOT_DISTRIBUTION(X,Y) - Plots the mean with standard deviation errors as a shaded region in the open 3 | % figure window. 4 | % Inputs: 5 | % X: vector of n domain values (the x-axis). 6 | % Y: mxn matrix of distribution of range values (the y-axis), where m 7 | % corresponds to the number of data samples for each value n. 8 | % 9 | % PLOT_DISTRIBUTION(X,Y,...) 10 | % Parameter options include: 11 | % 'Alpha': the alpha value of the shaded region, default 0.15. 12 | % 'Color': the shaded region color. 13 | % 'LineWidth': the contour line width, default = 2.0. 14 | 15 | 16 | [X,Y,color_value,alpha_value,line_width] = parseinputs(varargin{:}); 17 | 18 | 19 | MU = mean(Y); 20 | SIGMA = std(Y); 21 | 22 | hold on 23 | % Create the polygons for the shaded region 24 | 25 | Ptop = MU+SIGMA; 26 | Pbot = MU-SIGMA; 27 | 28 | for i=1:numel(X)-1 29 | Px = [X(i) X(i+1) X(i+1) X(i)]; 30 | Py = [Ptop(i) Ptop(i+1) Pbot(i+1) Pbot(i)]; 31 | fill(Px,Py,color_value,'FaceAlpha',alpha_value,'EdgeColor','none'); 32 | end 33 | 34 | plot(X,MU,'LineWidth',line_width,'Color',color_value); 35 | hold off 36 | 37 | end 38 | 39 | 40 | 41 | 42 | function [X,Y,color_value,alpha_value,line_width] = parseinputs(varargin) 43 | 44 | % Check the number of input args 45 | minargs = 2; 46 | numopts = 3; 47 | maxargs = minargs + 2*numopts; 48 | narginchk(minargs,maxargs); 49 | 50 | ax = gca; 51 | 52 | % Set the defaults 53 | alpha_value = 0.15; 54 | color_value = ax.ColorOrder(ax.ColorOrderIndex,:); 55 | line_width = 2.0; 56 | 57 | 58 | % Get the inputs and check them 59 | X = varargin{1}; 60 | validateattributes(X,{'numeric'},{'vector','nonnan','finite'},mfilename,'X',2); 61 | Y = varargin{2}; 62 | validateattributes(Y,{'numeric'},{'2d','nonnan','finite','ncols',numel(X)},mfilename,'Y',2); 63 | 64 | 65 | if nargin > minargs 66 | for i=(minargs+1):2:nargin 67 | PNAME = varargin{i}; 68 | PVALUE = varargin{i+1}; 69 | 70 | PNAME = validatestring(PNAME,{'Alpha','Color','LineWidth','Prctile'},... 71 | mfilename,'ParameterName',i); 72 | 73 | switch PNAME 74 | case 'Alpha' 75 | validateattributes(PVALUE,{'numeric'},{'scalar','nonnan','finite','nonnegative','<=',1.0},mfilename,PNAME,i+1); 76 | alpha_value = PVALUE; 77 | case 'Color' 78 | validateattributes(PVALUE,{'numeric'},{'real','nonnegative','nonempty','vector','numel',3,'<=',1.0},mfilename,PNAME,i+1); 79 | color_value = PVALUE; 80 | case 'LineWidth' 81 | validateattributes(PVALUE,{'numeric'},{'scalar','finite','nonnegative'},... 82 | mfilename,PNAME,i+1); 83 | line_width = PVALUE; 84 | end 85 | end 86 | end 87 | 88 | end 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /subproject/3rdparty/shaded_plots/plot_distribution_prctile.m: -------------------------------------------------------------------------------- 1 | function plot_distribution_prctile(varargin) 2 | % PLOT_DISTRIBUTION_PRCTILE(X,Y) - Plots the median with percentile errors as a shaded region in the open 3 | % figure window. 4 | % Inputs: 5 | % X: vector of n domain values (the x-axis). 6 | % Y: mxn matrix of distribution of range values (the y-axis), where m 7 | % corresponds to the number of data samples for each value n. 8 | % 9 | % PLOT_DISTRIBUTION_PRCTILE(X,Y,...) 10 | % Parameter options include: 11 | % 'Alpha': the alpha value of the shaded region, default 0.15. 12 | % 'Color': the shaded region color. 13 | % 'LineWidth': the contour line width, default = 2.0. 14 | % 'Prctile': the percentile values to plot, default [50] (the middle 15 | % 50 percentile, or inter-quartile range). 16 | % 17 | 18 | 19 | [X,Y,prctile_value,color_value,alpha_value,line_width] = parseinputs(varargin{:}); 20 | 21 | p_value = 0.5*(100-sort(prctile_value)); 22 | 23 | hold on 24 | % Create the polygons for the shaded region 25 | for j=1:numel(p_value) 26 | Ptop = prctile(Y,100-p_value(j)); 27 | Pbot = prctile(Y,p_value(j)); 28 | for i=1:numel(X)-1 29 | Px = [X(i) X(i+1) X(i+1) X(i)]; 30 | Py = [Ptop(i) Ptop(i+1) Pbot(i+1) Pbot(i)]; 31 | fill(Px,Py,color_value,'FaceAlpha',alpha_value,'EdgeColor','none'); 32 | end 33 | end 34 | %plot(X,median(Y),'LineWidth',line_width,'Color',color_value); 35 | %%%% This part is modified by Junekey Jeon %%%% 36 | plot(X,median(Y),'--','LineWidth',line_width,'Color',color_value); 37 | hold off 38 | 39 | 40 | end 41 | 42 | 43 | 44 | 45 | 46 | function [X,Y,prctile_value,color_value,alpha_value,line_width] = parseinputs(varargin) 47 | 48 | % Check the number of input args 49 | minargs = 2; 50 | numopts = 4; 51 | maxargs = minargs + 2*numopts; 52 | narginchk(minargs,maxargs); 53 | 54 | ax = gca; 55 | 56 | % Set the defaults 57 | prctile_value = 50; 58 | alpha_value = 0.15; 59 | color_value = ax.ColorOrder(ax.ColorOrderIndex,:); 60 | line_width = 2.0; 61 | 62 | 63 | % Get the inputs and check them 64 | X = varargin{1}; 65 | validateattributes(X,{'numeric'},{'vector','nonnan','finite'},mfilename,'X',2); 66 | Y = varargin{2}; 67 | validateattributes(Y,{'numeric'},{'2d','nonnan','finite','ncols',numel(X)},mfilename,'Y',2); 68 | 69 | 70 | if nargin > minargs 71 | for i=3:2:nargin 72 | PNAME = varargin{i}; 73 | PVALUE = varargin{i+1}; 74 | 75 | PNAME = validatestring(PNAME,{'Alpha','Color','LineWidth','Prctile'},... 76 | mfilename,'ParameterName',i); 77 | 78 | switch PNAME 79 | case 'Alpha' 80 | validateattributes(PVALUE,{'numeric'},{'scalar','nonnan','finite','nonnegative','<=',1.0},mfilename,PNAME,i+1); 81 | alpha_value = PVALUE; 82 | case 'Color' 83 | validateattributes(PVALUE,{'numeric'},{'real','nonnegative','nonempty','vector','numel',3,'<=',1.0},mfilename,PNAME,i+1); 84 | color_value = PVALUE; 85 | case 'LineWidth' 86 | validateattributes(PVALUE,{'numeric'},{'scalar','finite','nonnegative'},... 87 | mfilename,PNAME,i+1); 88 | line_width = PVALUE; 89 | case 'Prctile' 90 | validateattributes(PVALUE,{'numeric'},{'vector','finite','nonnan','nonnegative','<=',100},... 91 | mfilename,PNAME,i+1); 92 | prctile_value = PVALUE; 93 | end 94 | end 95 | end 96 | 97 | end 98 | 99 | -------------------------------------------------------------------------------- /subproject/3rdparty/shaded_plots/plot_histogram_shaded.m: -------------------------------------------------------------------------------- 1 | function [bin_centers,hist_values,bin_edges] = plot_histogram_shaded(varargin) 2 | % [C,V,E] = PLOT_HISTOGRAM_SHADED(X) - Plots the histogram as a shaded line plot instead of bar plot. 3 | % Outputs: 4 | % C: the histogram bin centers. 5 | % V: the histogram values at each bin. 6 | % E: the histogram bin edges values. 7 | % 8 | % [C,V,E] = PLOT_HISTOGRAM_SHADED(X,_) 9 | % Optional values: 10 | % 'alpha': alpha value of the shaded region, default 0.2. 11 | % 'bins': number of bins, default []. 12 | % 'color': color of the plot, default [0 0 1]. 13 | % 'edges': the bins edges to use, default []. 14 | % 'normalization': the normalization type to use (see histogram doc), 15 | % default 'probability' 16 | % 17 | 18 | [X,n_bins,bin_edges,color_value,alpha_value,norm_type] = parseinputs(varargin{:}); 19 | 20 | 21 | 22 | if isempty(n_bins) && isempty(bin_edges) 23 | [hist_values,bin_edges] = histcounts(X,'Normalization',norm_type); 24 | else 25 | bin_param = n_bins; 26 | if ~isempty(bin_edges) 27 | bin_param = bin_edges; 28 | end 29 | [hist_values,bin_edges] = histcounts(X,bin_param,'Normalization',norm_type); 30 | end 31 | 32 | 33 | x_cat = cat(1,bin_edges,circshift(bin_edges,-1)); 34 | x_mean = mean(x_cat,1); 35 | bin_centers = x_mean(1:end-1); 36 | fprintf(1,'Plotting histogram with %d bins\n',numel(bin_centers)); 37 | 38 | % Use a shaded plot 39 | plot_shaded(bin_centers,hist_values,'Alpha',alpha_value,'Color',color_value,'LineWidth',1.5); 40 | 41 | 42 | end 43 | 44 | 45 | function [X,n_bins,bin_edges,color_value,alpha_value,norm_type] = parseinputs(varargin) 46 | 47 | % Get the number of input args 48 | minargs = 1; 49 | maxargs = minargs+5*2; 50 | narginchk(minargs,maxargs); 51 | 52 | ax = gca; 53 | 54 | % Set the defaults 55 | n_bins = []; 56 | bin_edges = []; 57 | color_value = ax.ColorOrder(ax.ColorOrderIndex,:); 58 | alpha_value = 0.2; 59 | norm_type = 'probability'; 60 | 61 | % Get the inputs and check them 62 | X = varargin{1}; 63 | validateattributes(X,{'numeric'},{'nonnan','finite'},mfilename,'X',1); 64 | 65 | if nargin > 1 66 | for i=2:2:nargin 67 | PNAME = varargin{i}; 68 | PVALUE = varargin{i+1}; 69 | 70 | PNAME = validatestring(PNAME,... 71 | {'alpha','bins','color','edges','normalization'},... 72 | mfilename,'ParameterName',i); 73 | 74 | switch PNAME 75 | case 'alpha' 76 | validateattributes(PVALUE,{'numeric'},{'real','nonnegative','finite','scalar'},... 77 | mfilename,PNAME,i+1); 78 | alpha_value = PVALUE; 79 | case 'bins' 80 | if ~isempty(PVALUE) 81 | validateattributes(PVALUE,{'numeric'},{'integer','positive','finite','scalar'},... 82 | mfilename,PNAME,i+1); 83 | n_bins = PVALUE; 84 | end 85 | case 'color' 86 | validateattributes(PVALUE,{'numeric'},{'real','nonnegative','nonempty','vector','numel',3,'<=',1.0},mfilename,PNAME,i+1); 87 | color_value = PVALUE; 88 | case 'edges' 89 | validateattributes(PVALUE,{'numeric'},{'real','nonempty','vector','nonnan'},mfilename,PNAME,i+1); 90 | bin_edges = PVALUE; 91 | case 'normalization' 92 | validateattributes(PVALUE,{'char'},{'nonempty'},mfilename,PNAME,i+1); 93 | norm_type = PVALUE; 94 | end 95 | end 96 | end 97 | 98 | end 99 | 100 | -------------------------------------------------------------------------------- /subproject/3rdparty/shaded_plots/plot_shaded.m: -------------------------------------------------------------------------------- 1 | function plot_shaded(varargin) 2 | % PLOT_SHADED(X,Y) - Plots the line with pretty shaded region under the line in the open 3 | % figure window. 4 | % Inputs: 5 | % X: vector of domain values. 6 | % Y: vector or range values. 7 | % 8 | % PLOT_SHADED(X,Y,...) 9 | % Parameter options include: 10 | % 'Alpha': the alpha value of the shaded region, default 0.15. 11 | % 'Color': the shaded region color. 12 | % 'LineWidth': the contour line width, default = 2.0. 13 | 14 | 15 | [X,Y,color_value,alpha_value,line_width] = parseinputs(varargin{:}); 16 | 17 | 18 | y_min = min(Y); 19 | y_max = max(Y); 20 | V_alpha = alpha_value*((Y-y_min)/y_max); 21 | F = [1 2 3 4]; 22 | 23 | hold on 24 | % Create patches for the shaded region 25 | for i=1:numel(X)-1 26 | V = [ X(i) y_min ; X(i) Y(i); X(i+1) Y(i+1); X(i+1) y_min ]; 27 | A = [0,V_alpha(i),V_alpha(i+1),0]'; 28 | patch('Faces',F,'Vertices',V,'FaceColor',color_value,... 29 | 'EdgeColor','none',... 30 | 'FaceVertexAlphaData',A,'FaceAlpha','interp','AlphaDataMapping','none'); 31 | end 32 | 33 | plot(X,Y,'LineWidth',line_width,'Color',color_value); 34 | hold off 35 | 36 | end 37 | 38 | 39 | 40 | 41 | function [X,Y,color_value,alpha_value,line_width] = parseinputs(varargin) 42 | 43 | % Check the number of input args 44 | minargs = 2; 45 | numopts = 3; 46 | maxargs = minargs + 2*numopts; 47 | narginchk(minargs,maxargs); 48 | 49 | ax = gca; 50 | 51 | % Set the defaults 52 | alpha_value = 0.15; 53 | color_value = ax.ColorOrder(ax.ColorOrderIndex,:); 54 | line_width = 2.0; 55 | 56 | 57 | % Get the inputs and check them 58 | X = varargin{1}; 59 | validateattributes(X,{'numeric'},{'vector','nonnan','finite'},mfilename,'X',2); 60 | Y = varargin{2}; 61 | validateattributes(Y,{'numeric'},{'vector','nonnan','finite','numel',numel(X)},mfilename,'Y',2); 62 | % Ensure that X and Y are column vectors 63 | X = X(:); 64 | Y = Y(:); 65 | 66 | if nargin > minargs 67 | for i=(minargs+1):2:nargin 68 | PNAME = varargin{i}; 69 | PVALUE = varargin{i+1}; 70 | 71 | PNAME = validatestring(PNAME,{'Alpha','Color','LineWidth','Prctile'},... 72 | mfilename,'ParameterName',i); 73 | 74 | switch PNAME 75 | case 'Alpha' 76 | validateattributes(PVALUE,{'numeric'},{'scalar','nonnan','finite','nonnegative','<=',1.0},mfilename,PNAME,i+1); 77 | alpha_value = PVALUE; 78 | case 'Color' 79 | validateattributes(PVALUE,{'numeric'},{'real','nonnegative','nonempty','vector','numel',3,'<=',1.0},mfilename,PNAME,i+1); 80 | color_value = PVALUE; 81 | case 'LineWidth' 82 | validateattributes(PVALUE,{'numeric'},{'scalar','finite','nonnegative'},... 83 | mfilename,PNAME,i+1); 84 | line_width = PVALUE; 85 | end 86 | end 87 | end 88 | 89 | end 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /subproject/benchmark/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14 FATAL_ERROR) 2 | 3 | project(jkj_fp_benchmark LANGUAGES CXX) 4 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 5 | 6 | # ---- Add dependencies ---- 7 | 8 | include(FetchContent) 9 | if (NOT TARGET jkj_fp) 10 | FetchContent_Declare(jkj_fp SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../..") 11 | FetchContent_MakeAvailable(jkj_fp) 12 | endif() 13 | if (NOT TARGET common) 14 | FetchContent_Declare(common SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../common") 15 | FetchContent_MakeAvailable(common) 16 | endif() 17 | if (NOT TARGET ryu) 18 | FetchContent_Declare(ryu SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../3rdparty/ryu") 19 | FetchContent_MakeAvailable(ryu) 20 | endif() 21 | if (NOT TARGET grisu_exact) 22 | FetchContent_Declare(grisu_exact SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../3rdparty/grisu_exact") 23 | FetchContent_MakeAvailable(grisu_exact) 24 | endif() 25 | if (NOT TARGET schubfach) 26 | FetchContent_Declare(schubfach SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../3rdparty/schubfach") 27 | FetchContent_MakeAvailable(schubfach) 28 | endif() 29 | if (NOT TARGET fmt) 30 | FetchContent_Declare(fmt SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../3rdparty/fmt") 31 | FetchContent_MakeAvailable(fmt) 32 | endif() 33 | 34 | 35 | function(fp_add_benchmark NAME) 36 | cmake_parse_arguments(FPBM "" "" "SOURCES;INCLUDES;LIBRARIES" ${ARGN}) 37 | add_executable(${NAME}) 38 | target_include_directories(${NAME} PRIVATE $ ${FPBM_INCLUDES}) 39 | target_sources(${NAME} PRIVATE ${FPBM_SOURCES}) 40 | target_link_libraries(${NAME} PRIVATE ${FPBM_LIBRARIES}) 41 | target_compile_features(${NAME} PRIVATE cxx_std_17) 42 | # ---- MSVC Specifics ---- 43 | if (MSVC) 44 | # No need to not generate PDB 45 | # /permissive- should be the default 46 | # The compilation will fail without /experimental:newLambdaProcessor 47 | # See also https://gitlab.kitware.com/cmake/cmake/-/issues/16478 48 | target_compile_options(${NAME} PUBLIC 49 | /Zi /permissive- 50 | $<$>:/experimental:newLambdaProcessor> 51 | $<$:/GL>) 52 | target_link_options(${NAME} PUBLIC $<$:/LTCG> /DEBUG:FASTLINK) 53 | set_target_properties(${NAME} PROPERTIES 54 | VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}") 55 | endif() 56 | set_target_properties(${NAME} PROPERTIES FOLDER fp/benchmark) 57 | endfunction() 58 | 59 | 60 | # ---- Fixed-precision Benchmark ---- 61 | 62 | fp_add_benchmark(to_chars_fixed_precision_benchmark 63 | SOURCES 64 | include/to_chars_fixed_precision_benchmark.h 65 | source/to_chars_fixed_precision_benchmark.cpp 66 | source/fp_to_chars_fixed_precision.cpp 67 | source/ryu_fixed_precision.cpp 68 | source/fmt_fixed_precision.cpp 69 | LIBRARIES 70 | ryu::ryu 71 | fmt::fmt 72 | jkj_fp::common 73 | jkj_fp::charconv) 74 | 75 | 76 | # ---- Shortest-roundtrip Benchmark ---- 77 | 78 | fp_add_benchmark(to_chars_shortest_roundtrip_benchmark 79 | SOURCES 80 | include/to_chars_shortest_roundtrip_benchmark.h 81 | source/to_chars_shortest_roundtrip_benchmark.cpp 82 | source/fp_to_chars_shortest_roundtrip.cpp 83 | source/ryu_shortest_roundtrip.cpp 84 | source/grisu_exact_shortest_roundtrip.cpp 85 | source/schubfach_shortest_roundtrip.cpp 86 | LIBRARIES 87 | ryu::ryu 88 | grisu_exact::grisu_exact 89 | schubfach::schubfach 90 | jkj_fp::common 91 | jkj_fp::charconv) 92 | 93 | 94 | # ---- Limited-precision from_chars Benchmark ---- 95 | 96 | fp_add_benchmark(from_chars_limited_precision_benchmark 97 | SOURCES 98 | include/from_chars_limited_precision_benchmark.h 99 | source/from_chars_limited_precision_benchmark.cpp 100 | source/fp_from_chars_limited_precision.cpp 101 | source/ryu_stof.cpp 102 | LIBRARIES 103 | ryu::ryu 104 | jkj_fp::common 105 | jkj_fp::charconv) 106 | 107 | 108 | # ---- Unlimited-precision from_chars Benchmark ---- 109 | 110 | fp_add_benchmark(from_chars_unlimited_precision_benchmark 111 | SOURCES 112 | include/from_chars_unlimited_precision_benchmark.h 113 | source/from_chars_unlimited_precision_benchmark.cpp 114 | source/fp_from_chars_unlimited_precision.cpp 115 | source/std_from_chars.cpp 116 | source/stod.cpp 117 | LIBRARIES 118 | jkj_fp::common 119 | jkj_fp::charconv) 120 | -------------------------------------------------------------------------------- /subproject/benchmark/include/from_chars_limited_precision_benchmark.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #ifndef JKJ_HEADER_FP_FROM_CHARS_LIMITED_PRECISION_BENCHMARK 19 | #define JKJ_HEADER_FP_FROM_CHARS_LIMITED_PRECISION_BENCHMARK 20 | 21 | #include 22 | #include 23 | 24 | struct register_function_for_from_chars_limited_precision_benchmark { 25 | register_function_for_from_chars_limited_precision_benchmark() = default; 26 | 27 | register_function_for_from_chars_limited_precision_benchmark( 28 | std::string_view name, 29 | float(*func)(std::string const&)); 30 | 31 | register_function_for_from_chars_limited_precision_benchmark( 32 | std::string_view name, 33 | double(*func)(std::string const&)); 34 | 35 | register_function_for_from_chars_limited_precision_benchmark( 36 | std::string_view name, 37 | float(*func_float)(std::string const&), 38 | double(*func_double)(std::string const&)); 39 | }; 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /subproject/benchmark/include/from_chars_unlimited_precision_benchmark.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #ifndef JKJ_HEADER_FP_FROM_CHARS_UNLIMITED_PRECISION_BENCHMARK 19 | #define JKJ_HEADER_FP_FROM_CHARS_UNLIMITED_PRECISION_BENCHMARK 20 | 21 | #include 22 | #include 23 | 24 | struct register_function_for_from_chars_unlimited_precision_benchmark { 25 | register_function_for_from_chars_unlimited_precision_benchmark() = default; 26 | 27 | register_function_for_from_chars_unlimited_precision_benchmark( 28 | std::string_view name, 29 | float(*func)(std::string const&)); 30 | 31 | register_function_for_from_chars_unlimited_precision_benchmark( 32 | std::string_view name, 33 | double(*func)(std::string const&)); 34 | 35 | register_function_for_from_chars_unlimited_precision_benchmark( 36 | std::string_view name, 37 | float(*func_float)(std::string const&), 38 | double(*func_double)(std::string const&)); 39 | }; 40 | 41 | #endif 42 | -------------------------------------------------------------------------------- /subproject/benchmark/include/to_chars_fixed_precision_benchmark.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #ifndef JKJ_HEADER_FP_FIXED_PRECISION_BENCHMARK 19 | #define JKJ_HEADER_FP_FIXED_PRECISION_BENCHMARK 20 | 21 | #include 22 | 23 | struct register_function_for_to_chars_fixed_precision_benchmark { 24 | register_function_for_to_chars_fixed_precision_benchmark() = default; 25 | 26 | register_function_for_to_chars_fixed_precision_benchmark( 27 | std::string_view name, 28 | void(*func)(float, char*, int)); 29 | 30 | register_function_for_to_chars_fixed_precision_benchmark( 31 | std::string_view name, 32 | void(*func)(double, char*, int)); 33 | 34 | register_function_for_to_chars_fixed_precision_benchmark( 35 | std::string_view name, 36 | void(*func_float)(float, char*, int), 37 | void(*func_double)(double, char*, int)); 38 | }; 39 | 40 | #endif 41 | -------------------------------------------------------------------------------- /subproject/benchmark/include/to_chars_shortest_roundtrip_benchmark.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #ifndef JKJ_HEADER_FP_SHORTEST_ROUNDTRIP_BENCHMARK 19 | #define JKJ_HEADER_FP_SHORTEST_ROUNDTRIP_BENCHMARK 20 | 21 | #include 22 | 23 | static constexpr enum { 24 | benchmark_no_trailing_zero, 25 | benchmark_allow_trailing_zero 26 | } benchmark_kind = benchmark_no_trailing_zero; 27 | 28 | struct register_function_for_to_chars_shortest_roundtrip_benchmark { 29 | register_function_for_to_chars_shortest_roundtrip_benchmark() = default; 30 | 31 | register_function_for_to_chars_shortest_roundtrip_benchmark( 32 | std::string_view name, 33 | void(*func)(float, char*)); 34 | 35 | register_function_for_to_chars_shortest_roundtrip_benchmark( 36 | std::string_view name, 37 | void(*func)(double, char*)); 38 | 39 | register_function_for_to_chars_shortest_roundtrip_benchmark( 40 | std::string_view name, 41 | void(*func_float)(float, char*), 42 | void(*func_double)(double, char*)); 43 | }; 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /subproject/benchmark/matlab/plot_digit_benchmark.m: -------------------------------------------------------------------------------- 1 | % Copyright 2020 Junekey Jeon 2 | % 3 | % The contents of this file may be used under the terms of 4 | % the Apache License v2.0 with LLVM Exceptions. 5 | % 6 | % (See accompanying file LICENSE-Apache or copy at 7 | % https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | % 9 | % Alternatively, the contents of this file may be used under the terms of 10 | % the Boost Software License, Version 1.0. 11 | % (See accompanying file LICENSE-Boost or copy at 12 | % https://www.boost.org/LICENSE_1_0.txt) 13 | % 14 | % Unless required by applicable law or agreed to in writing, this software 15 | % is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | % KIND, either express or implied. 17 | 18 | function [avg] = plot_digit_benchmark( filename ) 19 | 20 | output_filename = replace(filename, '.csv', '.pdf'); 21 | 22 | samples_per_digits = csvread(filename,0,1,[0 1 0 1]); 23 | table = readtable(filename); 24 | max_digits = table{size(table,1),2}; 25 | number_of_algorithms = size(table,1) / samples_per_digits / max_digits; 26 | names = string(zeros(number_of_algorithms, 1)); 27 | for i=1:number_of_algorithms 28 | names(i) = string(table{samples_per_digits * i * max_digits,1}); 29 | end 30 | 31 | % algorithm index, digits, measured_time 32 | data = zeros(number_of_algorithms, max_digits, samples_per_digits); 33 | for algorithm_idx=1:number_of_algorithms 34 | for digits_idx=1:max_digits 35 | offset = ((algorithm_idx-1) * max_digits + (digits_idx-1)) * samples_per_digits; 36 | data(algorithm_idx, digits_idx,:) = table{offset+1:offset+samples_per_digits, 4}; 37 | end 38 | end 39 | 40 | color_array = {[.8 .06 .1],[.1 .7 .06],[.06 .1 .8],[.6 .2 .8],[.8 .9 0],[.5 .6 .7],[.8 .2 .6]}; 41 | avg = zeros(number_of_algorithms, max_digits); 42 | for algorithm_idx=1:number_of_algorithms 43 | for digits_idx=1:max_digits 44 | avg(algorithm_idx,digits_idx) = mean(data(algorithm_idx,digits_idx,:)); 45 | end 46 | end 47 | 48 | % we will call this function stdshade 49 | addpath(genpath('shaded_plots')); 50 | 51 | % plot 52 | fig = figure('Color','w'); 53 | fig_handles = zeros(number_of_algorithms,1); 54 | hold on 55 | for algorithm_idx=1:number_of_algorithms 56 | fig_handles(algorithm_idx) = plot(1:max_digits,squeeze(avg(algorithm_idx,:)), ... 57 | 'Color', color_array{algorithm_idx}, 'LineWidth', 1.2); 58 | end 59 | for algorithm_idx=1:number_of_algorithms 60 | plot_distribution_prctile(1:max_digits,squeeze(data(algorithm_idx,:,:))', ... 61 | 'Color', color_array{algorithm_idx}, 'Alpha', 0.05, ... 62 | 'Prctile', [30 50 70], 'LineWidth', 0.2); 63 | end 64 | legend(fig_handles,names); 65 | axis([1 max_digits -Inf Inf]); 66 | xlabel('Number of digits'); 67 | ylabel('Time (ns)'); 68 | h = gca; 69 | h.XTick = 1:max_digits; 70 | h.XGrid = 'on'; 71 | h.YGrid = 'on'; 72 | set(gca,'TickLabelInterpreter', 'latex'); 73 | set(gcf, 'Position', [100 100 1200 500]); 74 | orient(fig,'landscape'); 75 | print(fig, output_filename,'-dpdf'); 76 | hold off 77 | 78 | end 79 | -------------------------------------------------------------------------------- /subproject/benchmark/matlab/plot_fixed_precision_benchmark.m: -------------------------------------------------------------------------------- 1 | % Copyright 2020 Junekey Jeon 2 | % 3 | % The contents of this file may be used under the terms of 4 | % the Apache License v2.0 with LLVM Exceptions. 5 | % 6 | % (See accompanying file LICENSE-Apache or copy at 7 | % https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | % 9 | % Alternatively, the contents of this file may be used under the terms of 10 | % the Boost Software License, Version 1.0. 11 | % (See accompanying file LICENSE-Boost or copy at 12 | % https://www.boost.org/LICENSE_1_0.txt) 13 | % 14 | % Unless required by applicable law or agreed to in writing, this software 15 | % is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | % KIND, either express or implied. 17 | 18 | function [avg] = plot_fixed_precision_benchmark( filename ) 19 | 20 | output_filename = replace(filename, '.csv', '.pdf'); 21 | 22 | table = readtable(filename); 23 | max_precision = table{size(table,1),2}; 24 | number_of_algorithms = size(table,1) / (max_precision + 1); 25 | names = string(zeros(number_of_algorithms, 1)); 26 | for i=1:number_of_algorithms 27 | names(i) = string(table{i * (max_precision + 1),1}); 28 | end 29 | 30 | % algorithm index, precision, measured_time 31 | data = zeros(number_of_algorithms, max_precision + 1); 32 | for algorithm_idx=1:number_of_algorithms 33 | for precision=0:max_precision 34 | data(algorithm_idx, precision + 1) = ... 35 | table{(algorithm_idx - 1) * (max_precision + 1) + precision + 1, 3}; 36 | end 37 | end 38 | 39 | color_array = {[.8 .06 .1],[.1 .7 .06],[.06 .1 .8],[.6 .2 .8],[.8 .9 0],[.5 .6 .7],[.8 .2 .6]}; 40 | 41 | % plot 42 | fig = figure('Color','w','DefaultLegendInterpreter','none'); 43 | fig_handles = zeros(number_of_algorithms,1); 44 | hold on 45 | for algorithm_idx=1:number_of_algorithms 46 | fig_handles(algorithm_idx) = plot(1:(max_precision+1),data(algorithm_idx,:), ... 47 | 'Color', color_array{algorithm_idx}, 'LineWidth', 1.2); 48 | end 49 | legend(fig_handles,names); 50 | axis([0 max_precision -Inf Inf]); 51 | xlabel('Precision + 1'); 52 | ylabel('Time (ns)'); 53 | h = gca; 54 | h.XTick = [1 2 3 4 5 6 7 8 9 10 20 30 40 50 60 70 80 90 100 200 300 400 500 600 700 800]; 55 | h.XGrid = 'on'; 56 | h.YGrid = 'on'; 57 | set(gca,'xscale','log'); 58 | set(gca,'yscale','log'); 59 | set(gca,'TickLabelInterpreter', 'latex'); 60 | set(gcf, 'Position', [100 100 1200 500]); 61 | orient(fig,'landscape'); 62 | print(fig, output_filename,'-dpdf'); 63 | hold off 64 | 65 | end 66 | -------------------------------------------------------------------------------- /subproject/benchmark/matlab/plot_to_chars_shortest_roundtrip_benchmarks.m: -------------------------------------------------------------------------------- 1 | % Copyright 2020 Junekey Jeon 2 | % 3 | % The contents of this file may be used under the terms of 4 | % the Apache License v2.0 with LLVM Exceptions. 5 | % 6 | % (See accompanying file LICENSE-Apache or copy at 7 | % https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | % 9 | % Alternatively, the contents of this file may be used under the terms of 10 | % the Boost Software License, Version 1.0. 11 | % (See accompanying file LICENSE-Boost or copy at 12 | % https://www.boost.org/LICENSE_1_0.txt) 13 | % 14 | % Unless required by applicable law or agreed to in writing, this software 15 | % is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | % KIND, either express or implied. 17 | 18 | addpath('../../3rdparty/shaded_plots'); 19 | plot_to_chars_shortest_roundtrip_uniform_benchmark('../results/to_chars_shortest_roundtrip_uniform_benchmark_binary32.csv', 32); 20 | plot_to_chars_shortest_roundtrip_uniform_benchmark('../results/to_chars_shortest_roundtrip_uniform_benchmark_binary64.csv', 64); 21 | avg32 = plot_digit_benchmark('../results/to_chars_shortest_roundtrip_digits_benchmark_binary32.csv'); 22 | avg64 = plot_digit_benchmark('../results/to_chars_shortest_roundtrip_digits_benchmark_binary64.csv'); -------------------------------------------------------------------------------- /subproject/benchmark/matlab/plot_to_chars_shortest_roundtrip_uniform_benchmark.m: -------------------------------------------------------------------------------- 1 | % Copyright 2020 Junekey Jeon 2 | % 3 | % The contents of this file may be used under the terms of 4 | % the Apache License v2.0 with LLVM Exceptions. 5 | % 6 | % (See accompanying file LICENSE-Apache or copy at 7 | % https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | % 9 | % Alternatively, the contents of this file may be used under the terms of 10 | % the Boost Software License, Version 1.0. 11 | % (See accompanying file LICENSE-Boost or copy at 12 | % https://www.boost.org/LICENSE_1_0.txt) 13 | % 14 | % Unless required by applicable law or agreed to in writing, this software 15 | % is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | % KIND, either express or implied. 17 | 18 | function [] = plot_uniform_benchmark( filename, bits ) 19 | 20 | output_filename = replace(filename, '.csv', '.pdf'); 21 | 22 | samples = csvread(filename,0,1,[0 1 0 1]); 23 | table = readtable(filename); 24 | number_of_algorithms = size(table,1) / samples; 25 | names = string(zeros(number_of_algorithms, 1)); 26 | for i=1:number_of_algorithms 27 | names(i) = string(table{samples * i,1}); 28 | end 29 | 30 | % algorithm index, measured_time 31 | measured_times = zeros(number_of_algorithms, samples); 32 | for algorithm_idx=1:number_of_algorithms 33 | offset = (algorithm_idx-1) * samples; 34 | measured_times(algorithm_idx,:) = table{offset+1:offset+samples, 4}; 35 | end 36 | bit_representations = sscanf(strjoin(string(table{1:samples, 3})', ' '), '%lx'); 37 | 38 | color_array = {[.8 .06 .1],[.1 .7 .06],[.06 .1 .8],[.6 .2 .8],[.8 .9 0],[.5 .6 .7],[.8 .2 .6]}; 39 | 40 | % compute statistics 41 | av = mean(measured_times'); 42 | st = std(measured_times'); 43 | me = median(measured_times'); 44 | 45 | decorated_names = names; 46 | for algorithm_idx=1:number_of_algorithms 47 | decorated_names(algorithm_idx) = sprintf('%s (avg: %.2f, std: %.2f, med: %.2f)', ... 48 | names(algorithm_idx), av(algorithm_idx), st(algorithm_idx), me(algorithm_idx)); 49 | end 50 | 51 | % sample data for plot 52 | maximum_plot_size = 10000; 53 | if samples > maximum_plot_size 54 | plot_size = maximum_plot_size; 55 | unit = floor(samples / maximum_plot_size); 56 | sampled_br = bit_representations(1:unit:unit*plot_size); 57 | sampled_mt = measured_times(:,1:unit:unit*plot_size); 58 | else 59 | plot_size = samples; 60 | sampled_br = bit_representations; 61 | sampled_mt = measured_times; 62 | end 63 | 64 | % plot 65 | fig = figure('Color','w'); 66 | fig_handles = zeros(number_of_algorithms,1); 67 | hold on 68 | sz = ones(plot_size, 1) * 0.4; 69 | for algorithm_idx=1:number_of_algorithms 70 | fig_handles(algorithm_idx) = scatter(sampled_br, ... 71 | sampled_mt(algorithm_idx,:), sz, '+', ... 72 | 'MarkerEdgeColor', color_array{algorithm_idx}, 'LineWidth', 0.1); 73 | end 74 | legend(fig_handles,decorated_names); 75 | xlabel('Bit representation'); 76 | ylabel('Time (ns)'); 77 | range = prctile(measured_times(:), 99.9); 78 | axis([0 uint64(2)^bits 0 range(1)]); 79 | if bits==32 80 | xticks([0 uint64(2)^30 uint64(2)^31 3*uint64(2)^30 uint64(2)^32]); 81 | xticklabels({'$0$','$2^{30}$','$2^{31}$','$3\times2^{30}$','$2^{32}$'}); 82 | elseif bits==64 83 | xticks([0 uint64(2)^62 uint64(2)^63 3*uint64(2)^62 uint64(2)^64]); 84 | xticklabels({'$0$','$2^{62}$','$2^{63}$','$3\times2^{62}$','$2^{64}$'}); 85 | end 86 | h = gca; 87 | h.XGrid = 'off'; 88 | h.YGrid = 'on'; 89 | set(gca,'TickLabelInterpreter', 'latex'); 90 | set(gcf, 'Position', [100 100 1200 500]); 91 | orient(fig,'landscape'); 92 | print(fig, output_filename,'-dpdf'); 93 | hold off 94 | 95 | end 96 | -------------------------------------------------------------------------------- /subproject/benchmark/results/from_chars_limited_precision_benchmark_binary32_clang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jk-jeon/fp/871ef67ee01302893ec91e730355ae8a65f4b678/subproject/benchmark/results/from_chars_limited_precision_benchmark_binary32_clang.png -------------------------------------------------------------------------------- /subproject/benchmark/results/from_chars_limited_precision_benchmark_binary64_clang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jk-jeon/fp/871ef67ee01302893ec91e730355ae8a65f4b678/subproject/benchmark/results/from_chars_limited_precision_benchmark_binary64_clang.png -------------------------------------------------------------------------------- /subproject/benchmark/results/from_chars_unlimited_precision_benchmark_binary32_clang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jk-jeon/fp/871ef67ee01302893ec91e730355ae8a65f4b678/subproject/benchmark/results/from_chars_unlimited_precision_benchmark_binary32_clang.png -------------------------------------------------------------------------------- /subproject/benchmark/results/from_chars_unlimited_precision_benchmark_binary64_clang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jk-jeon/fp/871ef67ee01302893ec91e730355ae8a65f4b678/subproject/benchmark/results/from_chars_unlimited_precision_benchmark_binary64_clang.png -------------------------------------------------------------------------------- /subproject/benchmark/results/to_chars_fixed_precision_benchmark_binary32_clang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jk-jeon/fp/871ef67ee01302893ec91e730355ae8a65f4b678/subproject/benchmark/results/to_chars_fixed_precision_benchmark_binary32_clang.png -------------------------------------------------------------------------------- /subproject/benchmark/results/to_chars_fixed_precision_benchmark_binary64_clang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jk-jeon/fp/871ef67ee01302893ec91e730355ae8a65f4b678/subproject/benchmark/results/to_chars_fixed_precision_benchmark_binary64_clang.png -------------------------------------------------------------------------------- /subproject/benchmark/results/to_chars_shortest_roundtrip_digits_benchmark_binary32_clang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jk-jeon/fp/871ef67ee01302893ec91e730355ae8a65f4b678/subproject/benchmark/results/to_chars_shortest_roundtrip_digits_benchmark_binary32_clang.png -------------------------------------------------------------------------------- /subproject/benchmark/results/to_chars_shortest_roundtrip_digits_benchmark_binary64_clang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jk-jeon/fp/871ef67ee01302893ec91e730355ae8a65f4b678/subproject/benchmark/results/to_chars_shortest_roundtrip_digits_benchmark_binary64_clang.png -------------------------------------------------------------------------------- /subproject/benchmark/results/to_chars_shortest_roundtrip_digits_benchmark_ntzr_binary32_clang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jk-jeon/fp/871ef67ee01302893ec91e730355ae8a65f4b678/subproject/benchmark/results/to_chars_shortest_roundtrip_digits_benchmark_ntzr_binary32_clang.png -------------------------------------------------------------------------------- /subproject/benchmark/results/to_chars_shortest_roundtrip_digits_benchmark_ntzr_binary64_clang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jk-jeon/fp/871ef67ee01302893ec91e730355ae8a65f4b678/subproject/benchmark/results/to_chars_shortest_roundtrip_digits_benchmark_ntzr_binary64_clang.png -------------------------------------------------------------------------------- /subproject/benchmark/results/to_chars_shortest_roundtrip_uniform_benchmark_binary32_clang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jk-jeon/fp/871ef67ee01302893ec91e730355ae8a65f4b678/subproject/benchmark/results/to_chars_shortest_roundtrip_uniform_benchmark_binary32_clang.png -------------------------------------------------------------------------------- /subproject/benchmark/results/to_chars_shortest_roundtrip_uniform_benchmark_binary64_clang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jk-jeon/fp/871ef67ee01302893ec91e730355ae8a65f4b678/subproject/benchmark/results/to_chars_shortest_roundtrip_uniform_benchmark_binary64_clang.png -------------------------------------------------------------------------------- /subproject/benchmark/results/to_chars_shortest_roundtrip_uniform_benchmark_ntzr_binary32_clang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jk-jeon/fp/871ef67ee01302893ec91e730355ae8a65f4b678/subproject/benchmark/results/to_chars_shortest_roundtrip_uniform_benchmark_ntzr_binary32_clang.png -------------------------------------------------------------------------------- /subproject/benchmark/results/to_chars_shortest_roundtrip_uniform_benchmark_ntzr_binary64_clang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jk-jeon/fp/871ef67ee01302893ec91e730355ae8a65f4b678/subproject/benchmark/results/to_chars_shortest_roundtrip_uniform_benchmark_ntzr_binary64_clang.png -------------------------------------------------------------------------------- /subproject/benchmark/source/fmt_fixed_precision.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "to_chars_fixed_precision_benchmark.h" 19 | #define FMT_HEADER_ONLY 1 20 | #include "fmt/compile.h" 21 | 22 | namespace { 23 | void float_to_chars(float x, char* buffer, int precision) 24 | { 25 | fmt::format_to(buffer, FMT_COMPILE("{:.{}e}"), x, precision); 26 | } 27 | void double_to_chars(double x, char* buffer, int precision) 28 | { 29 | fmt::format_to(buffer, FMT_COMPILE("{:.{}e}"), x, precision); 30 | } 31 | 32 | auto dummy = []() -> register_function_for_to_chars_fixed_precision_benchmark { 33 | return{ "fmt", 34 | float_to_chars, 35 | double_to_chars 36 | }; 37 | }(); 38 | } -------------------------------------------------------------------------------- /subproject/benchmark/source/fp_from_chars_limited_precision.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "from_chars_limited_precision_benchmark.h" 19 | #include "jkj/fp/from_chars/from_chars.h" 20 | 21 | namespace { 22 | float float_from_chars(std::string const& str) 23 | { 24 | return jkj::fp::from_chars_limited(str.data(), str.data() + str.length()).to_float(); 25 | } 26 | double double_from_chars(std::string const& str) 27 | { 28 | return jkj::fp::from_chars_limited(str.data(), str.data() + str.length()).to_float(); 29 | } 30 | 31 | auto dummy = []() -> register_function_for_from_chars_limited_precision_benchmark { 32 | return{ "fp", 33 | float_from_chars, 34 | double_from_chars 35 | }; 36 | }(); 37 | } -------------------------------------------------------------------------------- /subproject/benchmark/source/fp_from_chars_unlimited_precision.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "from_chars_unlimited_precision_benchmark.h" 19 | #include "jkj/fp/from_chars/from_chars.h" 20 | 21 | namespace { 22 | float float_from_chars(std::string const& str) 23 | { 24 | return jkj::fp::from_chars_unlimited(str.data(), str.data() + str.length()).to_float(); 25 | } 26 | double double_from_chars(std::string const& str) 27 | { 28 | return jkj::fp::from_chars_unlimited(str.data(), str.data() + str.length()).to_float(); 29 | } 30 | 31 | auto dummy = []() -> register_function_for_from_chars_unlimited_precision_benchmark { 32 | return{ "fp", 33 | float_from_chars, 34 | double_from_chars 35 | }; 36 | }(); 37 | } -------------------------------------------------------------------------------- /subproject/benchmark/source/fp_to_chars_fixed_precision.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "to_chars_fixed_precision_benchmark.h" 19 | #include "jkj/fp/to_chars/fixed_precision.h" 20 | 21 | namespace { 22 | void float_to_chars(float x, char* buffer, int precision) 23 | { 24 | jkj::fp::to_chars_fixed_precision_scientific_n(x, buffer, precision); 25 | } 26 | void double_to_chars(double x, char* buffer, int precision) 27 | { 28 | jkj::fp::to_chars_fixed_precision_scientific_n(x, buffer, precision); 29 | } 30 | 31 | auto dummy = []() -> register_function_for_to_chars_fixed_precision_benchmark { 32 | return{ "fp", 33 | float_to_chars, 34 | double_to_chars 35 | }; 36 | }(); 37 | } -------------------------------------------------------------------------------- /subproject/benchmark/source/fp_to_chars_shortest_roundtrip.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "to_chars_shortest_roundtrip_benchmark.h" 19 | #include "jkj/fp/to_chars/shortest_roundtrip.h" 20 | 21 | namespace { 22 | void float_to_chars(float x, char* buffer) 23 | { 24 | jkj::fp::to_chars_shortest_scientific(x, buffer, 25 | jkj::fp::policy::binary_rounding::nearest_to_even, 26 | jkj::fp::policy::decimal_rounding::to_even); 27 | } 28 | void double_to_chars(double x, char* buffer) 29 | { 30 | jkj::fp::to_chars_shortest_scientific(x, buffer, 31 | jkj::fp::policy::binary_rounding::nearest_to_even, 32 | jkj::fp::policy::decimal_rounding::to_even); 33 | } 34 | 35 | void float_to_chars_wo_tzremoval(float x, char* buffer) 36 | { 37 | jkj::fp::to_chars_shortest_scientific(x, buffer, 38 | jkj::fp::policy::trailing_zero::allow, 39 | jkj::fp::policy::binary_rounding::nearest_to_even, 40 | jkj::fp::policy::decimal_rounding::to_even); 41 | } 42 | void double_to_chars_wo_tzremoval(double x, char* buffer) 43 | { 44 | jkj::fp::to_chars_shortest_scientific(x, buffer, 45 | jkj::fp::policy::trailing_zero::allow, 46 | jkj::fp::policy::binary_rounding::nearest_to_even, 47 | jkj::fp::policy::decimal_rounding::to_even); 48 | } 49 | 50 | auto dummy = []() -> register_function_for_to_chars_shortest_roundtrip_benchmark { 51 | if constexpr (benchmark_kind == benchmark_no_trailing_zero) 52 | { 53 | return { "fp", 54 | float_to_chars, 55 | double_to_chars 56 | }; 57 | } 58 | else { 59 | return { "fp (w/o trailing zero removal)", 60 | float_to_chars_wo_tzremoval, 61 | double_to_chars_wo_tzremoval 62 | }; 63 | } 64 | }(); 65 | } 66 | -------------------------------------------------------------------------------- /subproject/benchmark/source/grisu_exact_shortest_roundtrip.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "to_chars_shortest_roundtrip_benchmark.h" 19 | #include "fp_to_chars.h" 20 | 21 | namespace { 22 | void float_to_chars(float x, char* buffer) 23 | { 24 | jkj::fp_to_chars(x, buffer, 25 | jkj::grisu_exact_rounding_modes::nearest_to_even{}, 26 | jkj::grisu_exact_correct_rounding::tie_to_even{}); 27 | } 28 | void double_to_chars(double x, char* buffer) 29 | { 30 | jkj::fp_to_chars(x, buffer, 31 | jkj::grisu_exact_rounding_modes::nearest_to_even{}, 32 | jkj::grisu_exact_correct_rounding::tie_to_even{}); 33 | } 34 | 35 | auto dummy = []() -> register_function_for_to_chars_shortest_roundtrip_benchmark { 36 | if constexpr (benchmark_kind == benchmark_no_trailing_zero) { 37 | return { "Grisu-Exact", 38 | float_to_chars, 39 | double_to_chars 40 | }; 41 | } 42 | else { 43 | return {}; 44 | } 45 | }(); 46 | } 47 | -------------------------------------------------------------------------------- /subproject/benchmark/source/ryu_fixed_precision.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "to_chars_fixed_precision_benchmark.h" 19 | #include "ryu/ryu.h" 20 | 21 | namespace { 22 | void float_to_chars(float x, char* buffer, int precision) 23 | { 24 | d2exp_buffered(x, precision, buffer); 25 | } 26 | void double_to_chars(double x, char* buffer, int precision) 27 | { 28 | d2exp_buffered(x, precision, buffer); 29 | } 30 | 31 | auto dummy = []() -> register_function_for_to_chars_fixed_precision_benchmark { 32 | return{ "Ryu", 33 | float_to_chars, 34 | double_to_chars 35 | }; 36 | }(); 37 | } -------------------------------------------------------------------------------- /subproject/benchmark/source/ryu_shortest_roundtrip.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "to_chars_shortest_roundtrip_benchmark.h" 19 | #include "ryu/ryu.h" 20 | 21 | namespace { 22 | auto dummy = []() -> register_function_for_to_chars_shortest_roundtrip_benchmark { 23 | if constexpr (benchmark_kind == benchmark_no_trailing_zero) { 24 | return { "Ryu", 25 | f2s_buffered, 26 | d2s_buffered 27 | }; 28 | } 29 | else { 30 | return {}; 31 | } 32 | }(); 33 | } 34 | -------------------------------------------------------------------------------- /subproject/benchmark/source/ryu_stof.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "from_chars_limited_precision_benchmark.h" 19 | #include "ryu/ryu_parse.h" 20 | 21 | namespace { 22 | float float_from_chars(std::string const& str) 23 | { 24 | float ret; 25 | s2f_n(str.data(), int(str.length()), &ret); 26 | return ret; 27 | 28 | } 29 | double double_from_chars(std::string const& str) 30 | { 31 | double ret; 32 | s2d_n(str.data(), int(str.length()), &ret); 33 | return ret; 34 | } 35 | 36 | auto dummy = []() -> register_function_for_from_chars_limited_precision_benchmark { 37 | return{ "Ryu", 38 | float_from_chars, 39 | double_from_chars 40 | }; 41 | }(); 42 | } -------------------------------------------------------------------------------- /subproject/benchmark/source/schubfach_shortest_roundtrip.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "to_chars_shortest_roundtrip_benchmark.h" 19 | #include "schubfach_32.h" 20 | #include "schubfach_64.h" 21 | 22 | namespace { 23 | void float_to_chars(float x, char* buf) { 24 | schubfach::Ftoa(buf, x); 25 | } 26 | void double_to_chars(double x, char* buf) { 27 | schubfach::Dtoa(buf, x); 28 | } 29 | 30 | auto dummy = []() -> register_function_for_to_chars_shortest_roundtrip_benchmark { 31 | if constexpr (benchmark_kind == benchmark_no_trailing_zero) { 32 | return {}; 33 | } 34 | else { 35 | return { "Schubfach", 36 | float_to_chars, 37 | double_to_chars 38 | }; 39 | } 40 | }(); 41 | } 42 | -------------------------------------------------------------------------------- /subproject/benchmark/source/std_from_chars.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #if defined(_MSC_VER) && _MSC_VER >= 1915 19 | 20 | #include "from_chars_unlimited_precision_benchmark.h" 21 | #include 22 | 23 | namespace { 24 | float float_from_chars(std::string const& str) 25 | { 26 | float value; 27 | std::from_chars(str.data(), str.data() + str.length(), value); 28 | return value; 29 | 30 | } 31 | double double_from_chars(std::string const& str) 32 | { 33 | double value; 34 | std::from_chars(str.data(), str.data() + str.length(), value); 35 | return value; 36 | } 37 | 38 | auto dummy = []() -> register_function_for_from_chars_unlimited_precision_benchmark { 39 | return{ "std::from_chars", 40 | float_from_chars, 41 | double_from_chars 42 | }; 43 | }(); 44 | } 45 | 46 | #endif -------------------------------------------------------------------------------- /subproject/benchmark/source/stod.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "from_chars_unlimited_precision_benchmark.h" 19 | 20 | namespace { 21 | float float_from_chars(std::string const& str) 22 | { 23 | // Ignore out_of_range error 24 | try { 25 | return std::stof(str); 26 | } 27 | catch (...) { 28 | return 0; 29 | } 30 | 31 | } 32 | double double_from_chars(std::string const& str) 33 | { 34 | // Ignore out_of_range error 35 | try { 36 | return std::stod(str); 37 | } 38 | catch (...) { 39 | return 0; 40 | } 41 | } 42 | 43 | auto dummy = []() -> register_function_for_from_chars_unlimited_precision_benchmark { 44 | return{ "stof/stod", 45 | float_from_chars, 46 | double_from_chars 47 | }; 48 | }(); 49 | } -------------------------------------------------------------------------------- /subproject/benchmark/source/to_chars_fixed_precision_benchmark.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "to_chars_fixed_precision_benchmark.h" 19 | #include "random_float.h" 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | template 32 | class benchmark_holder 33 | { 34 | public: 35 | static benchmark_holder& get_instance() { 36 | static benchmark_holder inst; 37 | return inst; 38 | } 39 | 40 | // Generate random samples 41 | void prepare_samples(std::size_t number_of_samples) 42 | { 43 | samples_.resize(number_of_samples); 44 | for (auto& sample : samples_) { 45 | sample = jkj::fp::detail::uniformly_randomly_generate_finite_float(rg_); 46 | } 47 | } 48 | 49 | // { "name" : [measured_time_for_each_precision] } 50 | using output_type = std::unordered_map>; 51 | void run(double duration_per_each_precision_in_sec, 52 | std::string_view float_name, int max_precision, output_type& out) 53 | { 54 | assert(max_precision >= 0); 55 | auto buffer = std::make_unique(10000); 56 | auto dur = std::chrono::duration{ duration_per_each_precision_in_sec }; 57 | 58 | for (int precision = 0; precision <= max_precision; ++precision) { 59 | std::cout << "Benchmark for precision = " << precision << 60 | " with uniformly random " << float_name << "'s...\n"; 61 | 62 | for (auto const& name_func_pair : name_func_pairs_) { 63 | auto& measured_times = out[name_func_pair.first]; 64 | if (measured_times.empty()) { 65 | measured_times.resize(max_precision + 1); 66 | } 67 | 68 | std::size_t iterations = 0; 69 | std::size_t sample_idx = 0; 70 | auto from = std::chrono::steady_clock::now(); 71 | auto to = from + dur; 72 | auto now = std::chrono::steady_clock::now(); 73 | 74 | while (now <= to) { 75 | name_func_pair.second(samples_[sample_idx], buffer.get(), precision); 76 | 77 | if (++sample_idx == samples_.size()) { 78 | sample_idx = 0; 79 | } 80 | ++iterations; 81 | now = std::chrono::steady_clock::now(); 82 | } 83 | 84 | measured_times[precision] = 85 | double(std::chrono::duration_cast(now - from).count()) 86 | / iterations; 87 | } 88 | } 89 | } 90 | 91 | output_type run(double duration_per_each_precision_in_sec, 92 | std::string_view float_name, int max_precision) 93 | { 94 | output_type out; 95 | run(duration_per_each_precision_in_sec, float_name, max_precision, out); 96 | return out; 97 | } 98 | 99 | void register_function(std::string_view name, void(*func)(Float, char*, int)) 100 | { 101 | name_func_pairs_.emplace(name, func); 102 | } 103 | 104 | private: 105 | benchmark_holder() : rg_(jkj::fp::detail::generate_correctly_seeded_mt19937_64()) {} 106 | 107 | std::vector samples_; 108 | std::mt19937_64 rg_; 109 | std::unordered_map name_func_pairs_; 110 | }; 111 | 112 | register_function_for_to_chars_fixed_precision_benchmark::register_function_for_to_chars_fixed_precision_benchmark( 113 | std::string_view name, 114 | void(*func_float)(float, char*, int)) 115 | { 116 | benchmark_holder::get_instance().register_function(name, func_float); 117 | }; 118 | 119 | register_function_for_to_chars_fixed_precision_benchmark::register_function_for_to_chars_fixed_precision_benchmark( 120 | std::string_view name, 121 | void(*func_double)(double, char*, int)) 122 | { 123 | benchmark_holder::get_instance().register_function(name, func_double); 124 | }; 125 | 126 | register_function_for_to_chars_fixed_precision_benchmark::register_function_for_to_chars_fixed_precision_benchmark( 127 | std::string_view name, 128 | void(*func_float)(float, char*, int), 129 | void(*func_double)(double, char*, int)) 130 | { 131 | benchmark_holder::get_instance().register_function(name, func_float); 132 | benchmark_holder::get_instance().register_function(name, func_double); 133 | }; 134 | 135 | 136 | #define RUN_MATLAB 137 | #ifdef RUN_MATLAB 138 | #include 139 | 140 | void run_matlab() { 141 | std::system("matlab -nosplash -r \"cd('matlab');" 142 | "plot_fixed_precision_benchmark(\'../results/to_chars_fixed_precision_benchmark_binary32.csv\');" 143 | "plot_fixed_precision_benchmark(\'../results/to_chars_fixed_precision_benchmark_binary64.csv\');\""); 144 | } 145 | #endif 146 | 147 | template 148 | static void benchmark_test(std::string_view float_name, std::size_t number_of_samples, 149 | double duration_per_each_precision_in_sec, int max_precision) 150 | { 151 | auto& inst = benchmark_holder::get_instance(); 152 | std::cout << "Generating random samples...\n"; 153 | inst.prepare_samples(number_of_samples); 154 | auto out = inst.run(duration_per_each_precision_in_sec, float_name, max_precision); 155 | 156 | std::cout << "Benchmarking done.\n" << "Now writing to files...\n"; 157 | 158 | // Write benchmark results 159 | auto filename = std::string("results/to_chars_fixed_precision_benchmark_"); 160 | filename += float_name; 161 | filename += ".csv"; 162 | std::ofstream out_file{ filename }; 163 | out_file << "number_of_samples," << number_of_samples << std::endl;; 164 | out_file << "name,precision,time\n"; 165 | 166 | for (auto const& name_result_pair : out) { 167 | for (int precision = 0; precision <= max_precision; ++precision) { 168 | out_file << "\"" << name_result_pair.first << "\"," 169 | << precision << "," << name_result_pair.second[precision] << "\n"; 170 | } 171 | } 172 | } 173 | 174 | int main() { 175 | constexpr bool benchmark_float = true; 176 | constexpr std::size_t number_of_benchmark_samples_float = 1000000; 177 | constexpr double duration_per_each_precision_in_sec_float = 0.1; 178 | constexpr int max_precision_float = 120; // max_nonzero_decimal_digits = 112 179 | 180 | constexpr bool benchmark_double = true; 181 | constexpr std::size_t number_of_benchmark_samples_double = 1000000; 182 | constexpr double duration_per_each_precision_in_sec_double = 0.1; 183 | constexpr int max_precision_double = 780; // max_nonzero_decimal_digits = 767 184 | 185 | if constexpr (benchmark_float) { 186 | std::cout << "[Running fixed-precision formatting benchmark for binary32...]\n"; 187 | benchmark_test("binary32", 188 | number_of_benchmark_samples_float, 189 | duration_per_each_precision_in_sec_float, 190 | max_precision_float); 191 | std::cout << "Done.\n\n\n"; 192 | } 193 | if constexpr (benchmark_double) { 194 | std::cout << "[Running fixed-precision formatting benchmark for binary64...]\n"; 195 | benchmark_test("binary64", 196 | number_of_benchmark_samples_double, 197 | duration_per_each_precision_in_sec_double, 198 | max_precision_double); 199 | std::cout << "Done.\n\n\n"; 200 | } 201 | 202 | #ifdef RUN_MATLAB 203 | run_matlab(); 204 | #endif 205 | } -------------------------------------------------------------------------------- /subproject/common/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14 FATAL_ERROR) 2 | 3 | project(jkj_fp_common LANGUAGES CXX) 4 | 5 | include(FetchContent) 6 | if (NOT TARGET jkj_fp) 7 | FetchContent_Declare(jkj_fp SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../..") 8 | FetchContent_MakeAvailable(jkj_fp) 9 | endif() 10 | 11 | add_library(jkj_fp_common INTERFACE) 12 | add_library(jkj_fp::common ALIAS jkj_fp_common) 13 | 14 | target_include_directories(jkj_fp_common 15 | INTERFACE 16 | $) 17 | 18 | target_compile_features(jkj_fp_common INTERFACE cxx_std_17) 19 | 20 | target_link_libraries(jkj_fp_common INTERFACE jkj_fp::fp) 21 | 22 | # ---- MSVC Specifics ---- 23 | if (MSVC) 24 | # No need to not generate PDB 25 | # /permissive- should be the default 26 | # The compilation will fail without /experimental:newLambdaProcessor 27 | target_compile_options(jkj_fp_common INTERFACE 28 | /Zi /permissive- 29 | $<$>:/experimental:newLambdaProcessor>) 30 | endif() -------------------------------------------------------------------------------- /subproject/common/include/cache_write_helper.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "minmax_euclid.h" 19 | #include "jkj/fp/detail/wuint.h" 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | namespace { 27 | template 28 | std::ostream& print_as(std::ostream& out, jkj::fp::detail::bigint_impl const& x) { 29 | if constexpr (std::is_same_v) { 30 | assert(x.leading_one_pos.element_pos == 0); 31 | out << "0x" << std::hex << std::setw(16) << std::setfill('0') << x.elements[0]; 32 | } 33 | else if constexpr (std::is_same_v || 34 | std::is_same_v) 35 | { 36 | assert(x.leading_one_pos.element_pos < 1 || 37 | (x.leading_one_pos.element_pos == 1 && x.leading_one_pos.bit_pos <= 32)); 38 | out << "{ 0x" << std::hex << std::setw(8) << std::setfill('0') << std::uint32_t(x.elements[1]) 39 | << ", 0x" << std::hex << std::setw(8) << std::setfill('0') << std::uint32_t(x.elements[0] >> 32) 40 | << ", 0x" << std::hex << std::setw(8) << std::setfill('0') << std::uint32_t(x.elements[0]) << " }"; 41 | } 42 | else if constexpr (std::is_same_v || 43 | std::is_same_v) 44 | { 45 | assert(x.leading_one_pos.element_pos <= 1); 46 | out << "{ 0x" << std::hex << std::setw(16) << std::setfill('0') << x.elements[1] 47 | << ", 0x" << std::hex << std::setw(16) << std::setfill('0') << x.elements[0] << " }"; 48 | } 49 | else if constexpr(std::is_same_v || 50 | std::is_same_v) 51 | { 52 | assert(x.leading_one_pos.element_pos <= 2); 53 | out << "{ 0x" << std::hex << std::setw(16) << std::setfill('0') << x.elements[2] 54 | << ", 0x" << std::hex << std::setw(16) << std::setfill('0') << x.elements[1] 55 | << ", 0x" << std::hex << std::setw(16) << std::setfill('0') << x.elements[0] << " }"; 56 | } 57 | else { 58 | static_assert(std::is_same_v || 59 | std::is_same_v); 60 | 61 | assert(x.leading_one_pos.element_pos <= 3); 62 | out << "{ 0x" << std::hex << std::setw(16) << std::setfill('0') << x.elements[3] 63 | << ", 0x" << std::hex << std::setw(16) << std::setfill('0') << x.elements[2] 64 | << ", 0x" << std::hex << std::setw(16) << std::setfill('0') << x.elements[1] 65 | << ", 0x" << std::hex << std::setw(16) << std::setfill('0') << x.elements[0] << " }"; 66 | } 67 | return out; 68 | } 69 | } -------------------------------------------------------------------------------- /subproject/common/include/random_float.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #ifndef JKJ_HEADER_FP_RANDOM_FLOAT 19 | #define JKJ_HEADER_FP_RANDOM_FLOAT 20 | 21 | //////////////////////////////////////////////////////////////////////////////////////// 22 | // This file is only used for cache generation, and need not be included for real use 23 | //////////////////////////////////////////////////////////////////////////////////////// 24 | 25 | #include "jkj/fp/dragonbox.h" 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | 32 | namespace jkj::fp { 33 | namespace detail { 34 | // For correct seeding 35 | class repeating_seed_seq { 36 | public: 37 | using result_type = std::uint32_t; 38 | 39 | repeating_seed_seq() : stored_values{ 0 } {} 40 | template 41 | repeating_seed_seq(InputIterator first, InputIterator last) : 42 | stored_values(first, last) {} 43 | template 44 | repeating_seed_seq(std::initializer_list list) : 45 | stored_values(list) {} 46 | 47 | repeating_seed_seq(std::random_device&& rd, std::size_t count) { 48 | stored_values.resize(count); 49 | for (auto& elem : stored_values) 50 | elem = rd(); 51 | } 52 | 53 | template 54 | void generate(RandomAccessIterator first, RandomAccessIterator last) 55 | { 56 | auto count = last - first; 57 | auto q = count / stored_values.size(); 58 | for (std::size_t i = 0; i < q; ++i) { 59 | std::copy_n(stored_values.cbegin(), stored_values.size(), first); 60 | first += stored_values.size(); 61 | } 62 | count -= q * stored_values.size(); 63 | std::copy_n(stored_values.cbegin(), count, first); 64 | } 65 | 66 | std::size_t size() const noexcept { 67 | return stored_values.size(); 68 | } 69 | 70 | template 71 | void param(OutputIterator first) const { 72 | std::copy(stored_values.begin(), stored_values.end(), first); 73 | } 74 | 75 | private: 76 | std::vector stored_values; 77 | }; 78 | 79 | inline std::mt19937_64 generate_correctly_seeded_mt19937_64() 80 | { 81 | repeating_seed_seq seed_seq{ std::random_device{}, 82 | std::mt19937_64::state_size * std::mt19937_64::word_size / (sizeof(std::uint32_t) * 8) }; 83 | return std::mt19937_64{ seed_seq }; 84 | } 85 | 86 | template 87 | Float uniformly_randomly_generate_finite_float(RandGen& rg) 88 | { 89 | using ieee754_format_info = ieee754_format_info::format>; 90 | using carrier_uint = typename ieee754_traits::carrier_uint; 91 | using uniform_distribution = std::uniform_int_distribution; 92 | 93 | // Generate sign bit 94 | auto sign_bit = uniform_distribution{ 0, 1 }(rg); 95 | 96 | // Generate exponent bits 97 | auto exponent_bits = uniform_distribution{ 0, 98 | (carrier_uint(1) << ieee754_format_info::exponent_bits) - 2 }(rg); 99 | 100 | // Generate significand bits 101 | auto significand_bits = uniform_distribution{ 0, 102 | (carrier_uint(1) << ieee754_format_info::significand_bits) - 1 }(rg); 103 | 104 | auto bit_representation = (sign_bit << (ieee754_traits::carrier_bits - 1)) 105 | | (exponent_bits << (ieee754_format_info::significand_bits)) 106 | | significand_bits; 107 | 108 | return ieee754_traits::carrier_to_float(bit_representation); 109 | } 110 | 111 | template 112 | Float uniformly_randomly_generate_general_float(RandGen& rg) 113 | { 114 | using carrier_uint = typename ieee754_traits::carrier_uint; 115 | using uniform_distribution = std::uniform_int_distribution; 116 | 117 | // Generate sign bit 118 | auto bit_representation = uniform_distribution{ 119 | 0, std::numeric_limits::max() }(rg); 120 | return ieee754_traits::carrier_to_float(bit_representation); 121 | } 122 | 123 | // This function tries to uniformly randomly generate a float number with the 124 | // given number of decimal digits, and the end-result is not perfectly bias-free. 125 | // However, I don't think there is an easy way to do it correctly. 126 | template 127 | Float randomly_generate_float_with_given_digits(unsigned int digits, RandGen& rg) 128 | { 129 | using carrier_uint = typename ieee754_traits::carrier_uint; 130 | using signed_int_t = std::make_signed_t; 131 | 132 | assert(digits >= 1); 133 | assert(digits <= ieee754_format_info::format>::decimal_digits); 134 | 135 | // Generate sign uniformly randomly 136 | signed_int_t sign = std::uniform_int_distribution{ 0, 1 }(rg) == 0 ? 1 : -1; 137 | 138 | 139 | // Try to generate significand uniformly randomly 140 | Float result; 141 | signed_int_t from = 0, to = 9; 142 | if (digits > 1) { 143 | from = 1; 144 | for (unsigned int e = 1; e < digits - 1; ++e) { 145 | from *= 10; 146 | } 147 | to = from * 10 - 1; 148 | } 149 | 150 | while (true) { 151 | auto significand = std::uniform_int_distribution{ from, to }(rg); 152 | if (digits > 1) { 153 | significand *= 10; 154 | significand += std::uniform_int_distribution{ 1, 9 }(rg); 155 | } 156 | 157 | // Generate exponent uniformly randomly 158 | auto exp = std::uniform_int_distribution{ 159 | std::numeric_limits::min_exponent10 - (int(digits) - 1), 160 | std::numeric_limits::max_exponent10 - (int(digits) - 1) }(rg); 161 | 162 | // Cook up 163 | auto str = std::to_string(sign * significand) + 'e' + std::to_string(exp); 164 | 165 | try { 166 | if constexpr (std::is_same_v) { 167 | result = std::stof(str); 168 | } 169 | else { 170 | result = std::stod(str); 171 | } 172 | 173 | // Discard if a shorter representation exists 174 | // We don't need to care about sign and correct rounding here 175 | auto roundtrip = jkj::fp::to_shortest_decimal(result, 176 | jkj::fp::policy::sign::ignore, 177 | jkj::fp::policy::binary_rounding::nearest_to_even, 178 | jkj::fp::policy::decimal_rounding::do_not_care); 179 | if (from != 0 && roundtrip.significand <= carrier_uint(from * 10)) { 180 | continue; 181 | } 182 | } 183 | catch (std::out_of_range&) { 184 | continue; 185 | } 186 | break; 187 | } 188 | 189 | return result; 190 | } 191 | } 192 | } 193 | 194 | #endif -------------------------------------------------------------------------------- /subproject/meta/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14 FATAL_ERROR) 2 | 3 | project(jkj_fp_meta LANGUAGES CXX) 4 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 5 | 6 | include(FetchContent) 7 | if (NOT TARGET jkj_fp) 8 | FetchContent_Declare(jkj_fp SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../..") 9 | FetchContent_MakeAvailable(jkj_fp) 10 | endif() 11 | if (NOT TARGET common) 12 | FetchContent_Declare(common SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../common") 13 | FetchContent_MakeAvailable(common) 14 | endif() 15 | if (NOT TARGET ryu) 16 | FetchContent_Declare(ryu SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../3rdparty/ryu") 17 | FetchContent_MakeAvailable(ryu) 18 | endif() 19 | if (NOT TARGET fmt) 20 | FetchContent_Declare(fmt SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../3rdparty/fmt") 21 | FetchContent_MakeAvailable(fmt) 22 | endif() 23 | 24 | function(meta_exe NAME) 25 | add_executable(${NAME} source/${NAME}.cpp) 26 | 27 | target_compile_features(${NAME} PRIVATE cxx_std_17) 28 | 29 | target_link_libraries(${NAME} PRIVATE ${ARGN}) 30 | 31 | # ---- MSVC Specifics ---- 32 | if (MSVC) 33 | # No need to not generate PDB 34 | # /permissive- should be the default 35 | # The compilation will fail without /experimental:newLambdaProcessor 36 | # See also https://gitlab.kitware.com/cmake/cmake/-/issues/16478 37 | target_compile_options(${NAME} PUBLIC 38 | /Zi /permissive- 39 | $<$>:/experimental:newLambdaProcessor> 40 | $<$:/GL>) 41 | target_link_options(${NAME} PUBLIC $<$:/LTCG> /DEBUG:FASTLINK) 42 | set_target_properties(${NAME} PROPERTIES 43 | VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}") 44 | endif() 45 | set_target_properties(${NAME} PROPERTIES FOLDER fp/meta) 46 | endfunction() 47 | 48 | meta_exe(to_chars_fixed_precision_live_test jkj_fp::charconv) 49 | meta_exe(to_chars_shortest_roundtrip_live_test jkj_fp::charconv) 50 | meta_exe(from_chars_limited_precision_live_test ryu jkj_fp::charconv) 51 | meta_exe(from_chars_unlimited_precision_live_test ryu jkj_fp::charconv) 52 | meta_exe(ryu_printf_generate_fast_cache jkj_fp::common) 53 | meta_exe(dragonbox_generate_cache jkj_fp::common) 54 | meta_exe(dragonbox_generate_compact_cache_error_table jkj_fp::common) 55 | meta_exe(sandbox ryu fmt jkj_fp::charconv jkj_fp::common) -------------------------------------------------------------------------------- /subproject/meta/results/dragonbox_binary32_fast_cache.txt: -------------------------------------------------------------------------------- 1 | static constexpr int min_k = -55; 2 | static constexpr int max_k = 46; 3 | 4 | static constexpr cache_entry_type cache[] = { 5 | 0x9ced737bb6c4183e, 6 | 0xc428d05aa4751e4d, 7 | 0xf53304714d9265e0, 8 | 0x993fe2c6d07b7fac, 9 | 0xbf8fdb78849a5f97, 10 | 0xef73d256a5c0f77d, 11 | 0x95a8637627989aae, 12 | 0xbb127c53b17ec15a, 13 | 0xe9d71b689dde71b0, 14 | 0x9226712162ab070e, 15 | 0xb6b00d69bb55c8d2, 16 | 0xe45c10c42a2b3b06, 17 | 0x8eb98a7a9a5b04e4, 18 | 0xb267ed1940f1c61d, 19 | 0xdf01e85f912e37a4, 20 | 0x8b61313bbabce2c7, 21 | 0xae397d8aa96c1b78, 22 | 0xd9c7dced53c72256, 23 | 0x881cea14545c7576, 24 | 0xaa242499697392d3, 25 | 0xd4ad2dbfc3d07788, 26 | 0x84ec3c97da624ab5, 27 | 0xa6274bbdd0fadd62, 28 | 0xcfb11ead453994bb, 29 | 0x81ceb32c4b43fcf5, 30 | 0xa2425ff75e14fc32, 31 | 0xcad2f7f5359a3b3f, 32 | 0xfd87b5f28300ca0e, 33 | 0x9e74d1b791e07e49, 34 | 0xc612062576589ddb, 35 | 0xf79687aed3eec552, 36 | 0x9abe14cd44753b53, 37 | 0xc16d9a0095928a28, 38 | 0xf1c90080baf72cb2, 39 | 0x971da05074da7bef, 40 | 0xbce5086492111aeb, 41 | 0xec1e4a7db69561a6, 42 | 0x9392ee8e921d5d08, 43 | 0xb877aa3236a4b44a, 44 | 0xe69594bec44de15c, 45 | 0x901d7cf73ab0acda, 46 | 0xb424dc35095cd810, 47 | 0xe12e13424bb40e14, 48 | 0x8cbccc096f5088cc, 49 | 0xafebff0bcb24aaff, 50 | 0xdbe6fecebdedd5bf, 51 | 0x89705f4136b4a598, 52 | 0xabcc77118461cefd, 53 | 0xd6bf94d5e57a42bd, 54 | 0x8637bd05af6c69b6, 55 | 0xa7c5ac471b478424, 56 | 0xd1b71758e219652c, 57 | 0x83126e978d4fdf3c, 58 | 0xa3d70a3d70a3d70b, 59 | 0xcccccccccccccccd, 60 | 0x8000000000000000, 61 | 0xa000000000000000, 62 | 0xc800000000000000, 63 | 0xfa00000000000000, 64 | 0x9c40000000000000, 65 | 0xc350000000000000, 66 | 0xf424000000000000, 67 | 0x9896800000000000, 68 | 0xbebc200000000000, 69 | 0xee6b280000000000, 70 | 0x9502f90000000000, 71 | 0xba43b74000000000, 72 | 0xe8d4a51000000000, 73 | 0x9184e72a00000000, 74 | 0xb5e620f480000000, 75 | 0xe35fa931a0000000, 76 | 0x8e1bc9bf04000000, 77 | 0xb1a2bc2ec5000000, 78 | 0xde0b6b3a76400000, 79 | 0x8ac7230489e80000, 80 | 0xad78ebc5ac620000, 81 | 0xd8d726b7177a8000, 82 | 0x878678326eac9000, 83 | 0xa968163f0a57b400, 84 | 0xd3c21bcecceda100, 85 | 0x84595161401484a0, 86 | 0xa56fa5b99019a5c8, 87 | 0xcecb8f27f4200f3a, 88 | 0x813f3978f8940984, 89 | 0xa18f07d736b90be5, 90 | 0xc9f2c9cd04674ede, 91 | 0xfc6f7c4045812296, 92 | 0x9dc5ada82b70b59d, 93 | 0xc5371912364ce305, 94 | 0xf684df56c3e01bc6, 95 | 0x9a130b963a6c115c, 96 | 0xc097ce7bc90715b3, 97 | 0xf0bdc21abb48db20, 98 | 0x96769950b50d88f4, 99 | 0xbc143fa4e250eb31, 100 | 0xeb194f8e1ae525fd, 101 | 0x92efd1b8d0cf37be, 102 | 0xb7abc627050305ad, 103 | 0xe596b7b0c643c719, 104 | 0x8f7e32ce7bea5c6f, 105 | 0xb35dbf821ae4f38b, 106 | 0xe0352f62a19e306e 107 | }; -------------------------------------------------------------------------------- /subproject/meta/results/dragonbox_binary64_compressed_cache_error_table.txt: -------------------------------------------------------------------------------- 1 | static constexpr std::uint32_t errors[] = { 2 | 0x50001400, 0x54044100, 0x54014555, 0x55954415, 0x54115555, 3 | 0x00000001, 0x50000000, 0x00104000, 0x54010004, 0x05004001, 4 | 0x55555544, 0x41545555, 0x54040551, 0x15445545, 0x51555514, 5 | 0x10000015, 0x00101100, 0x01100015, 0x00000000, 0x00000000, 6 | 0x00000000, 0x00000000, 0x04450514, 0x45414110, 0x55555145, 7 | 0x50544050, 0x15040155, 0x11054140, 0x50111514, 0x11451454, 8 | 0x00400541, 0x00000000, 0x55555450, 0x10056551, 0x10054011, 9 | 0x55551014, 0x69514555, 0x05151109, 0x00155555 10 | }; -------------------------------------------------------------------------------- /subproject/meta/results/ryu_printf_binary32_fast_cache.txt: -------------------------------------------------------------------------------- 1 | static constexpr int min_n = -4; 2 | static constexpr int max_n = 17; 3 | 4 | static constexpr cache_entry_type cache[] = { 5 | { 0x00000000, 0x00000001, 0x54484933 }, 6 | { 0x00000000, 0x00000551, 0x2124cb4c }, 7 | { 0x00000000, 0x00000002, 0x79d346df }, 8 | { 0x00000000, 0x000009e7, 0x4d1b791f }, 9 | { 0x00000000, 0x00279d34, 0x6de47820 }, 10 | { 0x00000000, 0x9e74d1b7, 0x91e07e49 }, 11 | { 0x00000279, 0xd346de47, 0x81f921de }, 12 | { 0x00000000, 0x00000004, 0x9c977475 }, 13 | { 0x00000000, 0x00001272, 0x5dd1d244 }, 14 | { 0x00000000, 0x0049c977, 0x47490eaf }, 15 | { 0x00000001, 0x2725dd1d, 0x243aba0f }, 16 | { 0x0000049c, 0x97747490, 0xeae839d8 }, 17 | { 0x0012725d, 0xd1d243ab, 0xa0e75fe7 }, 18 | { 0x49c97747, 0x490eae83, 0x9d7f9918 }, 19 | { 0xd997bd24, 0x3aba0e75, 0xfe645cc5 }, 20 | { 0x00000000, 0x00000008, 0x9705f414 }, 21 | { 0x00000000, 0x0000225c, 0x17d04dae }, 22 | { 0x00000000, 0x0089705f, 0x4136b4a6 }, 23 | { 0x00000002, 0x25c17d04, 0xdad2965d }, 24 | { 0x00000897, 0x05f4136b, 0x4a597317 }, 25 | { 0x00225c17, 0xd04dad29, 0x65cc5a03 }, 26 | { 0x89705f41, 0x36b4a597, 0x31680a89 }, 27 | { 0x4686d4da, 0xd2965cc5, 0xa02a23e3 }, 28 | { 0xd8ea3b4a, 0x59731680, 0xa88f8954 }, 29 | { 0x993ab165, 0xcc5a02a2, 0x3e254c0d }, 30 | { 0x1b58c731, 0x680a88f8, 0x953030fe }, 31 | { 0x00000000, 0x00000010, 0x00000000 }, 32 | { 0x00000000, 0x00004000, 0x00000000 }, 33 | { 0x00000000, 0x01000000, 0x00000000 }, 34 | { 0x00000004, 0x00000000, 0x00000000 }, 35 | { 0x00001000, 0x00000000, 0x00000000 }, 36 | { 0x00400000, 0x00000000, 0x00000000 }, 37 | { 0x1194d800, 0x00000000, 0x00000000 }, 38 | { 0x79fb4800, 0x00000000, 0x00000000 }, 39 | { 0xd8354800, 0x00000000, 0x00000000 }, 40 | { 0x90af0000, 0x00000000, 0x00000000 }, 41 | { 0x620ff800, 0x00000000, 0x00000000 }, 42 | { 0x29a73800, 0x00000000, 0x00000000 }, 43 | { 0xd65e3000, 0x00000000, 0x00000000 }, 44 | { 0xa7a84000, 0x00000000, 0x00000000 }, 45 | { 0x00000000, 0x0000001d, 0xcd650000 }, 46 | { 0x00000000, 0x00007735, 0x94000000 }, 47 | { 0x00000000, 0x01dcd650, 0x00000000 }, 48 | { 0x00000007, 0x73594000, 0x00000000 }, 49 | { 0x00001dcd, 0x65000000, 0x00000000 }, 50 | { 0x00773594, 0x00000000, 0x00000000 }, 51 | { 0x00000000, 0x00000037, 0x82dace9d }, 52 | { 0x00000000, 0x0000de0b, 0x6b3a7640 }, 53 | { 0x00000000, 0x03782dac, 0xe9d90000 }, 54 | { 0x0000000d, 0xe0b6b3a7, 0x64000000 }, 55 | { 0x00003782, 0xdace9d90, 0x00000000 }, 56 | { 0x00de0b6b, 0x3a764000, 0x00000000 }, 57 | { 0xacec34e9, 0xd9000000, 0x00000000 }, 58 | { 0xa63db764, 0x00000000, 0x00000000 }, 59 | { 0x00000000, 0x00000067, 0x65c793fa }, 60 | { 0x00000000, 0x00019d97, 0x1e4fe840 }, 61 | { 0x00000000, 0x06765c79, 0x3fa10079 }, 62 | { 0x00000019, 0xd971e4fe, 0x8401e740 }, 63 | { 0x00006765, 0xc793fa10, 0x079d0000 }, 64 | { 0x019d971e, 0x4fe8401e, 0x74000000 }, 65 | { 0xdfd9893f, 0xa10079d0, 0x00000000 }, 66 | { 0x65e3d684, 0x01e74000, 0x00000000 }, 67 | { 0x926ec807, 0x9d000000, 0x00000000 }, 68 | { 0xdc41fe74, 0x00000000, 0x00000000 }, 69 | { 0x00000000, 0x000000c0, 0x97ce7bc9 }, 70 | { 0x00000000, 0x0003025f, 0x39ef241c }, 71 | { 0x00000000, 0x0c097ce7, 0xbc90715b }, 72 | { 0x00000030, 0x25f39ef2, 0x41c56cd2 }, 73 | { 0x0000c097, 0xce7bc907, 0x15b34b9f }, 74 | { 0x03025f39, 0xef241c56, 0xcd2e7c40 }, 75 | { 0xdc7707bc, 0x90715b34, 0xb9f10000 }, 76 | { 0xd4252241, 0xc56cd2e7, 0xc4000000 }, 77 | { 0x2535af15, 0xb34b9f10, 0x00000000 }, 78 | { 0xc22e7ecd, 0x2e7c4000, 0x00000000 }, 79 | { 0x00e2e4b9, 0xf1000000, 0x00000000 }, 80 | { 0xc0516fc4, 0x00000000, 0x00000000 }, 81 | { 0x00000000, 0x166bb7f0, 0x435c9e71 }, 82 | { 0x00000059, 0xaedfc10d, 0x7279c5ee }, 83 | { 0x000166bb, 0x7f0435c9, 0xe717bb45 }, 84 | { 0x059aedfc, 0x10d7279c, 0x5eed1401 }, 85 | { 0x11ac3043, 0x5c9e717b, 0xb4500591 }, 86 | { 0xd75c5572, 0x79c5eed1, 0x40164540 }, 87 | { 0xe69169e7, 0x17bb4500, 0x59150000 }, 88 | { 0x4342ec5e, 0xed140164, 0x54000000 }, 89 | { 0xd3247bb4, 0x50059150, 0x00000000 }, 90 | { 0xcab34140, 0x16454000, 0x00000000 }, 91 | { 0x8cdb1059, 0x15000000, 0x00000000 }, 92 | { 0xe76f0454, 0x00000000, 0x00000000 }, 93 | { 0x0a70c3c4, 0x0a64e6c5, 0x1999090b }, 94 | { 0xc8a43029, 0x939b1466, 0x64242d97 }, 95 | { 0xb25b1e4e, 0x6c519990, 0x90b65f67 }, 96 | { 0x07d789b1, 0x46664242, 0xd97d9f64 }, 97 | { 0xa2569d19, 0x99090b65, 0xf67d9240 }, 98 | { 0x38b47e64, 0x242d97d9, 0xf6490000 }, 99 | { 0x82429890, 0xb65f67d9, 0x24000000 }, 100 | { 0x6e65ead9, 0x7d9f6490, 0x00000000 }, 101 | { 0x254355f6, 0x7d924000, 0x00000000 }, 102 | { 0x0a5ed9f6, 0x49000000, 0x00000000 }, 103 | { 0x80fcf924, 0x00000000, 0x00000000 }, 104 | { 0x04d7142b, 0xbb1e62af, 0xa4fc4759 }, 105 | { 0xbbf18eec, 0x798abe93, 0xf11d65ee }, 106 | { 0x327099e6, 0x2afa4fc4, 0x7597b9fc }, 107 | { 0x97fdd8ab, 0xe93f11d6, 0x5ee7f340 }, 108 | { 0xbe78cfa4, 0xfc47597b, 0x9fcd0000 }, 109 | { 0x10d8c3f1, 0x1d65ee7f, 0x34000000 }, 110 | { 0x54ec8475, 0x97b9fcd0, 0x00000000 }, 111 | { 0xb1b4f65e, 0xe7f34000, 0x00000000 }, 112 | { 0x3a79439f, 0xcd000000, 0x00000000 }, 113 | { 0x21fe4734, 0x00000000, 0x00000000 }, 114 | { 0xce57dd57, 0xa51bf8c7, 0x373d9bd8 }, 115 | { 0x3898ee94, 0x6fe31cdc, 0xf66f634e }, 116 | { 0x140359bf, 0x8c7373d9, 0xbd8d3840 }, 117 | { 0xe3d2b631, 0xcdcf66f6, 0x34e10000 }, 118 | { 0x7579f737, 0x3d9bd8d3, 0x84000000 }, 119 | { 0x84e61cf6, 0x6f634e10, 0x00000000 }, 120 | { 0xbddcc9bd, 0x8d384000, 0x00000000 }, 121 | { 0x6c029e34, 0xe1000000, 0x00000000 }, 122 | { 0xd6ab7b84, 0x00000000, 0x00000000 }, 123 | { 0xc41822e3, 0x47bf3f22, 0xac4f809c }, 124 | { 0x3419fd1e, 0xfcfc8ab1, 0x3e027140 }, 125 | { 0xb89ca3f3, 0xf22ac4f8, 0x09c50000 }, 126 | { 0xd70c0fc8, 0xab13e027, 0x14000000 }, 127 | { 0x93e5eaac, 0x4f809c50, 0x00000000 }, 128 | { 0x33de793e, 0x02714000, 0x00000000 }, 129 | { 0xb8f84809, 0xc5000000, 0x00000000 }, 130 | { 0x68c61714, 0x00000000, 0x00000000 }, 131 | { 0x989e7e6b, 0xc0c6acdc, 0x3fe6ee40 }, 132 | { 0x75ce5703, 0x1ab370ff, 0x9bb90000 }, 133 | { 0xe7fa246a, 0xcdc3fe6e, 0xe4000000 }, 134 | { 0x4faa0b37, 0x0ff9bb90, 0x00000000 }, 135 | { 0x25056c3f, 0xe6ee4000, 0x00000000 }, 136 | { 0x0123279b, 0xb9000000, 0x00000000 }, 137 | { 0xd2f1cee4, 0x00000000, 0x00000000 }, 138 | { 0xbf5ba863, 0xbbc1cf3a, 0x20253f40 }, 139 | { 0xd0fa46ef, 0x073ce880, 0x94fd0000 }, 140 | { 0x83a4941c, 0xf3a20253, 0xf4000000 }, 141 | { 0x5fd12bce, 0x88094fd0, 0x00000000 }, 142 | { 0x7ea60220, 0x253f4000, 0x00000000 }, 143 | { 0xe2bea894, 0xfd000000, 0x00000000 }, 144 | { 0xcd5b4bf4, 0x00000000, 0x00000000 }, 145 | { 0xcea3f6ff, 0xf7c792b2, 0x60d10000 }, 146 | { 0x7a9467df, 0x1e4ac983, 0x44000000 }, 147 | { 0x71734c79, 0x2b260d10, 0x00000000 }, 148 | { 0x3f58ccac, 0x98344000, 0x00000000 }, 149 | { 0x11583260, 0xd1000000, 0x00000000 }, 150 | { 0x75cff344, 0x00000000, 0x00000000 }, 151 | { 0xea9734c1, 0xaabe523d, 0xd4000000 }, 152 | { 0x8550aeaa, 0xf948f750, 0x00000000 }, 153 | { 0x8b4d4be5, 0x23dd4000, 0x00000000 }, 154 | { 0x46e0248f, 0x75000000, 0x00000000 }, 155 | { 0x6152bdd4, 0x00000000, 0x00000000 }, 156 | { 0xc6b7c857, 0xcbe4a290, 0x00000000 }, 157 | { 0x7415172f, 0x928a4000, 0x00000000 }, 158 | { 0x87e8ee4a, 0x29000000, 0x00000000 }, 159 | { 0xadb110a4, 0x00000000, 0x00000000 }, 160 | { 0xd62787c6, 0xc5cb4000, 0x00000000 }, 161 | { 0xbb728317, 0x2d000000, 0x00000000 }, 162 | { 0x131794b4, 0x00000000, 0x00000000 }, 163 | { 0x5c1ae02d, 0xc1000000, 0x00000000 }, 164 | { 0x8c29ff04, 0x00000000, 0x00000000 }, 165 | { 0xd114f894, 0x00000000, 0x00000000 } 166 | }; 167 | 168 | static constexpr index_type starting_index_minus_min_k[] = { 169 | -5, -1, 6, 16, 29, 45, 53, 63, 170 | 75, 87, 98, 108, 117, 125, 132, 139, 171 | 145, 150, 154, 157, 159, 160 172 | }; -------------------------------------------------------------------------------- /subproject/meta/source/dragonbox_generate_compact_cache_error_table.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "jkj/fp/dragonbox.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | 25 | int main() 26 | { 27 | using namespace jkj::fp::detail; 28 | using fast_cache_holder = dragonbox::cache_holder; 29 | using jkj::fp::policy::cache::fast; 30 | 31 | std::cout << "[Generating error table for compressed cache for Dragonbox...]\n"; 32 | 33 | std::vector results; 34 | 35 | constexpr int recov_size = 27; 36 | 37 | std::uint32_t error = 0; 38 | int error_count = 0; 39 | for (int k = fast_cache_holder::min_k; k <= fast_cache_holder::max_k; ++k) 40 | { 41 | auto real_cache = fast.get_cache(k); 42 | 43 | // Compute base index 44 | int kb = ((k - fast_cache_holder::min_k) / recov_size) * recov_size + fast_cache_holder::min_k; 45 | 46 | // Get base cache 47 | auto base_cache = fast.get_cache(kb); 48 | 49 | // Get index offset 50 | auto offset = k - kb; 51 | 52 | if (offset != 0) { 53 | // Compute corresponding power of 5 54 | std::uint64_t pow5 = 1; 55 | for (int i = 0; i < offset; ++i) { 56 | pow5 *= 5; 57 | } 58 | 59 | // Compute the required amount of bit-shift 60 | auto alpha = log::floor_log2_pow10(kb + offset) - log::floor_log2_pow10(kb) - offset; 61 | assert(alpha > 0 && alpha < 64); 62 | 63 | // Try to recover the real cache 64 | auto recovered_cache = wuint::umul128(base_cache.high(), pow5); 65 | auto middle_low = wuint::umul128(base_cache.low() - (kb < 0 ? 1 : 0), pow5); 66 | 67 | recovered_cache += middle_low.high(); 68 | 69 | auto high_to_middle = recovered_cache.high() << (64 - alpha); 70 | auto middle_to_low = recovered_cache.low() << (64 - alpha); 71 | 72 | recovered_cache = wuint::uint128{ 73 | (recovered_cache.low() >> alpha) | high_to_middle, 74 | ((middle_low.low() >> alpha) | middle_to_low) 75 | }; 76 | 77 | if (kb < 0) { 78 | if (recovered_cache.low() + 1 == 0) { 79 | recovered_cache = { recovered_cache.high() + 1, 0 }; 80 | } 81 | else { 82 | recovered_cache = { recovered_cache.high(), recovered_cache.low() + 1 }; 83 | } 84 | } 85 | 86 | // Measure the difference 87 | assert(real_cache.high() == recovered_cache.high()); 88 | assert(real_cache.low() >= recovered_cache.low()); 89 | auto diff = std::uint32_t(real_cache.low() - recovered_cache.low()); 90 | 91 | assert((diff >> 2) == 0); 92 | 93 | error |= std::uint32_t(diff << (error_count * 2)); 94 | } 95 | 96 | if (++error_count == 16) { 97 | results.push_back(error); 98 | error = 0; 99 | error_count = 0; 100 | } 101 | } 102 | 103 | if (error_count != 0) { 104 | results.push_back(error); 105 | } 106 | 107 | // Print out 108 | std::ofstream out{ "results/dragonbox_binary64_compressed_cache_error_table.txt" }; 109 | out << "static constexpr std::uint32_t errors[] = {\n\t"; 110 | for (std::size_t i = 0; i < results.size(); ++i) { 111 | if (i != 0) { 112 | if (i % 5 == 0) { 113 | out << ",\n\t"; 114 | } 115 | else { 116 | out << ", "; 117 | } 118 | } 119 | out << std::hex << std::setfill('0') << "0x" << std::setw(8) << results[i]; 120 | } 121 | out << "\n};"; 122 | 123 | std::cout << "Done.\n\n\n"; 124 | } 125 | -------------------------------------------------------------------------------- /subproject/meta/source/from_chars_limited_precision_live_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "jkj/fp/from_chars/from_chars.h" 19 | #include "ryu/ryu.h" 20 | #include 21 | #include 22 | #include 23 | 24 | template 25 | static void live_test() 26 | { 27 | char buffer[64]; 28 | std::string str; 29 | 30 | constexpr auto ieee754_format = jkj::fp::ieee754_traits::format; 31 | using ieee754_format_info = jkj::fp::ieee754_format_info; 32 | constexpr auto hex_precision = (ieee754_format_info::significand_bits + 3) / 4; 33 | 34 | while (true) { 35 | std::cout << "Input: "; 36 | std::cin >> str; 37 | auto x = jkj::fp::from_chars_limited(str.data(), str.data() + str.length()); 38 | if constexpr (ieee754_format == jkj::fp::ieee754_format::binary32) { 39 | f2s_buffered(x.to_float(), buffer); 40 | } 41 | else { 42 | d2s_buffered(x.to_float(), buffer); 43 | } 44 | std::cout << "Parsing output: " << buffer << " [" 45 | << std::hexfloat << std::setprecision(hex_precision) << x.to_float() << "]\n\n"; 46 | } 47 | } 48 | 49 | int main() 50 | { 51 | constexpr enum { 52 | test_float, 53 | test_double 54 | } test = test_double; 55 | 56 | if constexpr (test == test_float) { 57 | std::cout << "[Start limited-precision parsing live test for binary32]\n"; 58 | live_test(); 59 | } 60 | else if constexpr (test == test_double) { 61 | std::cout << "[Start limited-precision parsing live test for binary64]\n"; 62 | live_test(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /subproject/meta/source/from_chars_unlimited_precision_live_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "jkj/fp/from_chars/from_chars.h" 19 | #include "ryu/ryu.h" 20 | #include 21 | #include 22 | #include 23 | 24 | template 25 | static void live_test() 26 | { 27 | char buffer[64]; 28 | std::string str; 29 | 30 | constexpr auto ieee754_format = jkj::fp::ieee754_traits::format; 31 | using ieee754_format_info = jkj::fp::ieee754_format_info; 32 | constexpr auto hex_precision = (ieee754_format_info::significand_bits + 3) / 4; 33 | 34 | while (true) { 35 | std::cout << "Input: "; 36 | std::cin >> str; 37 | auto x = jkj::fp::from_chars_unlimited(str.data(), str.data() + str.length()); 38 | if constexpr (ieee754_format == jkj::fp::ieee754_format::binary32) { 39 | f2s_buffered(x.to_float(), buffer); 40 | } 41 | else { 42 | d2s_buffered(x.to_float(), buffer); 43 | } 44 | std::cout << "Parsing output: " << buffer << " [" 45 | << std::hexfloat << std::setprecision(hex_precision) << x.to_float() << "]\n\n"; 46 | } 47 | } 48 | 49 | int main() 50 | { 51 | constexpr enum { 52 | test_float, 53 | test_double 54 | } test = test_double; 55 | 56 | if constexpr (test == test_float) { 57 | std::cout << "[Start unlimited-precision parsing live test for binary32]\n"; 58 | live_test(); 59 | } 60 | else if constexpr (test == test_double) { 61 | std::cout << "[Start unlimited-precision parsing live test for binary64]\n"; 62 | live_test(); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /subproject/meta/source/sandbox.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "jkj/fp/dooly.h" 19 | #include "jkj/fp/from_chars/from_chars.h" 20 | #include "ryu/ryu.h" 21 | 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | 31 | int main() 32 | { 33 | using float_type = double; 34 | while (true) { 35 | std::string str; 36 | std::cin >> str; 37 | 38 | char buffer[64]; 39 | auto x = jkj::fp::from_chars_unlimited(str.data(), str.data() + str.length()); 40 | 41 | if constexpr (std::is_same_v) { 42 | f2s_buffered(x.to_float(), buffer); 43 | } 44 | else { 45 | d2s_buffered(x.to_float(), buffer); 46 | } 47 | std::cout << std::hexfloat << 48 | std::setprecision(std::is_same_v ? 6 : 13) 49 | << x.to_float() << " (" << buffer << ")\n"; 50 | } 51 | } -------------------------------------------------------------------------------- /subproject/meta/source/to_chars_fixed_precision_live_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "jkj/fp/to_chars/fixed_precision.h" 19 | 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | template 27 | static void live_test() 28 | { 29 | auto buffer = std::make_unique(100000); 30 | 31 | while (true) { 32 | Float x; 33 | std::string str; 34 | while (true) { 35 | std::cout << "Input a floating-point number: "; 36 | std::getline(std::cin, str); 37 | try { 38 | if constexpr (std::is_same_v) { 39 | x = std::stof(str); 40 | } 41 | else { 42 | x = std::stod(str); 43 | } 44 | } 45 | catch (...) { 46 | std::cout << "Not a valid input; input again.\n"; 47 | continue; 48 | } 49 | break; 50 | } 51 | int precision; 52 | while (true) { 53 | std::cout << "Input decimal precision: "; 54 | std::getline(std::cin, str); 55 | try { 56 | precision = std::stoi(str); 57 | if (x < 0 || x > 9000) { 58 | throw std::out_of_range{ "out of range" }; 59 | } 60 | } 61 | catch (...) { 62 | std::cout << "Not a valid input; input again.\n"; 63 | continue; 64 | } 65 | break; 66 | } 67 | 68 | auto xx = jkj::fp::ieee754_bits{ x }; 69 | std::cout << " sign: " << (xx.is_negative() ? "-" : "+") << std::endl; 70 | std::cout << " exponent bits: " << "0x" << std::hex << std::setfill('0') 71 | << xx.extract_exponent_bits() << std::dec 72 | << " (value: " << xx.binary_exponent() << ")\n"; 73 | std::cout << " significand bits: " << "0x" << std::hex << std::setfill('0'); 74 | if constexpr (std::is_same_v) { 75 | std::cout << std::setw(8); 76 | } 77 | else { 78 | std::cout << std::setw(16); 79 | } 80 | std::cout << xx.extract_significand_bits() 81 | << " (value: 0x" << xx.binary_significand() << ")\n" << std::dec; 82 | 83 | jkj::fp::to_chars_fixed_precision_scientific(x, buffer.get(), precision); 84 | std::cout << "output: " << buffer.get() << "\n\n"; 85 | } 86 | } 87 | 88 | int main() 89 | { 90 | constexpr enum { 91 | test_float, 92 | test_double 93 | } test = test_double; 94 | 95 | if constexpr (test == test_float) { 96 | std::cout << "[Start fixed-precision formatting live test for binary32]\n"; 97 | live_test(); 98 | } 99 | else if constexpr (test == test_double) { 100 | std::cout << "[Start fixed-precision formatting live test for binary64]\n"; 101 | live_test(); 102 | } 103 | } 104 | -------------------------------------------------------------------------------- /subproject/meta/source/to_chars_shortest_roundtrip_live_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "jkj/fp/to_chars/shortest_roundtrip.h" 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | template 25 | static void live_test() 26 | { 27 | char buffer[41]; 28 | 29 | while (true) { 30 | Float x; 31 | std::string x_str; 32 | while (true) { 33 | std::getline(std::cin, x_str); 34 | try { 35 | if constexpr (std::is_same_v) { 36 | x = std::stof(x_str); 37 | } 38 | else { 39 | x = std::stod(x_str); 40 | } 41 | } 42 | catch (...) { 43 | std::cout << "Not a valid input; input again.\n"; 44 | continue; 45 | } 46 | break; 47 | } 48 | 49 | auto xx = jkj::fp::ieee754_bits{ x }; 50 | std::cout << " sign: " << (xx.is_negative() ? "-" : "+") << std::endl; 51 | std::cout << " exponent bits: " << "0x" << std::hex << std::setfill('0') 52 | << xx.extract_exponent_bits() << std::dec 53 | << " (value: " << xx.binary_exponent() << ")\n"; 54 | std::cout << " significand bits: " << "0x" << std::hex << std::setfill('0'); 55 | if constexpr (std::is_same_v) { 56 | std::cout << std::setw(8); 57 | } 58 | else { 59 | std::cout << std::setw(16); 60 | } 61 | std::cout << xx.extract_significand_bits() 62 | << " (value: 0x" << xx.binary_significand() << ")\n" << std::dec; 63 | 64 | jkj::fp::to_chars_shortest_scientific(x, buffer); 65 | std::cout << " output: " << buffer << "\n\n"; 66 | } 67 | } 68 | 69 | int main() 70 | { 71 | constexpr enum { 72 | test_float, 73 | test_double 74 | } test = test_double; 75 | 76 | if constexpr (test == test_float) { 77 | std::cout << "[Start shortest-roundtrip formatting live test for binary32]\n"; 78 | live_test(); 79 | } 80 | else if constexpr (test == test_double) { 81 | std::cout << "[Start shortest-roundtrip formatting live test for binary64]\n"; 82 | live_test(); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /subproject/test/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.14 FATAL_ERROR) 2 | 3 | project(jkj_fp_tests LANGUAGES CXX) 4 | set_property(GLOBAL PROPERTY USE_FOLDERS ON) 5 | 6 | # ---- Add dependencies ---- 7 | 8 | # We want warnings in tests 9 | set(jkj_fp_INCLUDE_WITHOUT_SYSTEM ON CACHE INTERNAL "") 10 | 11 | include(FetchContent) 12 | if (NOT TARGET jkj_fp) 13 | FetchContent_Declare(jkj_fp SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../..") 14 | FetchContent_MakeAvailable(jkj_fp) 15 | endif() 16 | if (NOT TARGET common) 17 | FetchContent_Declare(common SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../common") 18 | FetchContent_MakeAvailable(common) 19 | endif() 20 | if (NOT TARGET ryu) 21 | FetchContent_Declare(ryu SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../3rdparty/ryu") 22 | FetchContent_MakeAvailable(ryu) 23 | endif() 24 | 25 | # ---- Tests ---- 26 | 27 | enable_testing() 28 | 29 | # setup convenience umbrella targets 30 | add_custom_target(fp-test-build) # target for building all tests 31 | add_custom_target(fp-test-run # target for running all tests 32 | COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $ ${FP_CTEST_OPTIONS} 33 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 34 | DEPENDS fp-test-build) 35 | add_custom_target(fp-test-run-verbose # target for running all tests in verbose mode 36 | COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure -C $ ${FP_CTEST_OPTIONS} -VV 37 | WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} 38 | DEPENDS fp-test-build) 39 | set_target_properties(fp-test-build PROPERTIES FOLDER fp/test) 40 | set_target_properties(fp-test-run PROPERTIES FOLDER fp/test) 41 | set_target_properties(fp-test-run-verbose PROPERTIES FOLDER fp/test) 42 | if(NOT TARGET test) # maybe this target is defined in a higher level project 43 | add_custom_target(test) 44 | set_target_properties(test PROPERTIES FOLDER fp/test) 45 | endif() 46 | add_dependencies(test fp-test-run) 47 | 48 | function(fp_add_test NAME) 49 | cmake_parse_arguments(TEST "CHARCONV;RYU" "" "" ${ARGN}) 50 | if(TEST_CHARCONV) 51 | set(jkj_fp jkj_fp::charconv) 52 | else() 53 | set(jkj_fp jkj_fp::fp) 54 | endif() 55 | add_executable(${NAME} source/${NAME}.cpp) 56 | add_dependencies(fp-test-build ${NAME}) 57 | target_link_libraries(${NAME} PRIVATE ${jkj_fp} jkj_fp::common) 58 | if(TEST_RYU) 59 | target_link_libraries(${NAME} PRIVATE ryu::ryu) 60 | endif() 61 | target_compile_features(${NAME} PRIVATE cxx_std_17) 62 | add_test(NAME ${NAME} COMMAND $) 63 | # ---- MSVC Specifics ---- 64 | if (MSVC) 65 | # No need to not generate PDB 66 | # /permissive- should be the default 67 | # The compilation will fail without /experimental:newLambdaProcessor 68 | # See also https://gitlab.kitware.com/cmake/cmake/-/issues/16478 69 | target_compile_options(${NAME} PUBLIC 70 | /Zi /permissive- 71 | $<$>:/experimental:newLambdaProcessor> 72 | $<$:/GL>) 73 | target_link_options(${NAME} PUBLIC $<$:/LTCG> /DEBUG:FASTLINK) 74 | set_target_properties(${NAME} PROPERTIES 75 | VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_CURRENT_LIST_DIR}") 76 | endif() 77 | set_target_properties(${NAME} PROPERTIES FOLDER fp/test) 78 | endfunction() 79 | 80 | fp_add_test(test_bigint) 81 | fp_add_test(test_minmax_euclid) 82 | fp_add_test(test_policy_holder) 83 | fp_add_test(verify_log_computation) 84 | fp_add_test(dragonbox_test_all_shorter_interval_cases CHARCONV RYU) 85 | fp_add_test(dragonbox_uniform_random_test CHARCONV RYU) 86 | fp_add_test(dragonbox_verify_fast_multiplication) 87 | fp_add_test(dragonbox_verify_magic_division) 88 | fp_add_test(dragonbox_dooly_binary32_exhaustive_joint_test RYU) 89 | fp_add_test(dragonbox_dooly_binary64_uniform_random_joint_test RYU) 90 | fp_add_test(ryu_printf_uniform_random_test CHARCONV RYU) 91 | fp_add_test(ryu_printf_dooly_uniform_random_joint_test CHARCONV RYU) 92 | -------------------------------------------------------------------------------- /subproject/test/source/dragonbox_dooly_binary32_exhaustive_joint_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "jkj/fp/dooly.h" 19 | #include "jkj/fp/dragonbox.h" 20 | #include "ryu/ryu.h" 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | 33 | int main() 34 | { 35 | std::cout << "[Joint-testing Dragonbox and Dooly for every finite non-zero binary32 inputs...]\n"; 36 | 37 | // Find the optimal number of threads 38 | auto const hw_concurrency = std::max(1u, std::thread::hardware_concurrency()); 39 | 40 | // Divide the range of inputs 41 | std::vector ranges(hw_concurrency + 1); 42 | ranges[0] = 0; 43 | 44 | auto q = (std::uint64_t(1) << 32) / hw_concurrency; 45 | auto r = (std::uint64_t(1) << 32) % hw_concurrency; 46 | 47 | for (std::size_t i = 0; i < hw_concurrency; ++i) { 48 | ranges[i + 1] = std::uint64_t(q * i); 49 | } 50 | for (std::size_t i = 0; i < r; ++i) { 51 | ranges[i + 1] += i + 1; 52 | } 53 | assert(ranges[hw_concurrency] == (std::uint64_t(1) << 32)); 54 | 55 | // Spawn threads 56 | using ieee754_bits = jkj::fp::ieee754_bits; 57 | struct failure_case_t { 58 | ieee754_bits input; 59 | ieee754_bits roundtrip; 60 | }; 61 | std::vector>> tasks(hw_concurrency); 62 | for (std::size_t i = 0; i < hw_concurrency; ++i) { 63 | tasks[i] = std::async([from = ranges[i], to = ranges[i + 1]]() { 64 | std::vector failure_cases; 65 | 66 | for (std::uint32_t u = std::uint32_t(from); u < to; ++u) { 67 | // Exclude 0 and non-finite inputs 68 | ieee754_bits x{ u }; 69 | if (x.is_nonzero() && x.is_finite()) { 70 | auto dec = jkj::fp::to_shortest_decimal(x.to_float()); 71 | auto roundtrip = jkj::fp::to_binary_limited_precision(dec); 72 | 73 | if (roundtrip.u != u) { 74 | failure_cases.push_back({ x, roundtrip }); 75 | } 76 | } 77 | } 78 | 79 | return failure_cases; 80 | }); 81 | } 82 | 83 | // Get merged list of failure cases 84 | std::vector failure_cases; 85 | for (auto& task : tasks) { 86 | auto failure_cases_subset = task.get(); 87 | failure_cases.insert(failure_cases.end(), 88 | failure_cases_subset.begin(), failure_cases_subset.end()); 89 | } 90 | 91 | if (failure_cases.empty()) { 92 | std::cout << "No error case was found.\n"; 93 | } 94 | else { 95 | std::cout << "Roundtrip fails for:\n"; 96 | for (auto const failure_case : failure_cases) { 97 | char buffer[64]; 98 | f2s_buffered(failure_case.input.to_float(), buffer); 99 | std::cout << "[0x" << std::hex << std::setw(8) << failure_case.input.u << "] " 100 | << buffer << " (roundtrip = "; 101 | f2s_buffered(failure_case.roundtrip.to_float(), buffer); 102 | std::cout << buffer << ")\n"; 103 | } 104 | 105 | std::cout << "Done.\n\n\n"; 106 | return -1; 107 | } 108 | 109 | std::cout << "Done.\n\n\n"; 110 | } -------------------------------------------------------------------------------- /subproject/test/source/dragonbox_dooly_binary64_uniform_random_joint_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "jkj/fp/dragonbox.h" 19 | #include "jkj/fp/dooly.h" 20 | #include "ryu/ryu.h" 21 | #include "random_float.h" 22 | #include 23 | #include 24 | 25 | template 26 | static bool uniform_random_test(std::size_t number_of_tests, TypenameString&& type_name_string) 27 | { 28 | auto rg = jkj::fp::detail::generate_correctly_seeded_mt19937_64(); 29 | bool success = true; 30 | for (std::size_t test_idx = 0; test_idx < number_of_tests; ++test_idx) { 31 | auto x = jkj::fp::detail::uniformly_randomly_generate_finite_float(rg); 32 | auto dec = jkj::fp::to_shortest_decimal(x); 33 | auto roundtrip = jkj::fp::to_binary_limited_precision(dec); 34 | 35 | if (x != roundtrip.to_float()) { 36 | char buffer1[64]; 37 | char buffer2[64]; 38 | if constexpr (jkj::fp::ieee754_traits::format == 39 | jkj::fp::ieee754_format::binary32) 40 | { 41 | f2s_buffered(x, buffer1); 42 | f2s_buffered(roundtrip.to_float(), buffer2); 43 | } 44 | else 45 | { 46 | d2s_buffered(x, buffer2); 47 | d2s_buffered(roundtrip.to_float(), buffer2); 48 | } 49 | std::cout << "Error detected! [Input = " << buffer1 50 | << ", Roundtrip = " << buffer2 << "]\n"; 51 | success = false; 52 | } 53 | } 54 | 55 | if (success) { 56 | std::cout << "Uniform random test for " << type_name_string 57 | << " with " << number_of_tests << " examples succeeded.\n"; 58 | } 59 | 60 | return success; 61 | } 62 | 63 | int main() 64 | { 65 | constexpr std::size_t number_of_uniform_random_tests = 10000000; 66 | bool success = true; 67 | 68 | std::cout << "[Joint-testing Dragonbox and Dooly for uniformly randomly generated binary64 inputs...]\n"; 69 | success &= uniform_random_test(number_of_uniform_random_tests, "binary64"); 70 | std::cout << "Done.\n\n\n"; 71 | 72 | if (!success) { 73 | return -1; 74 | } 75 | } -------------------------------------------------------------------------------- /subproject/test/source/dragonbox_test_all_shorter_interval_cases.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "jkj/fp/to_chars/shortest_roundtrip.h" 19 | #include "ryu/ryu.h" 20 | 21 | #include 22 | #include 23 | #include 24 | 25 | template 26 | static bool test_all_shorter_interval_cases_impl() 27 | { 28 | using ieee754_traits = jkj::fp::ieee754_traits; 29 | using ieee754_format_info = jkj::fp::ieee754_format_info; 30 | using carrier_uint = typename ieee754_traits::carrier_uint; 31 | 32 | char buffer1[64]; 33 | char buffer2[64]; 34 | 35 | bool success = true; 36 | for (int e = ieee754_format_info::min_exponent + 1; 37 | e <= ieee754_format_info::max_exponent; ++e) 38 | { 39 | // Compose a floating-point number 40 | carrier_uint br = carrier_uint(e) << ieee754_format_info::significand_bits; 41 | auto x = jkj::fp::ieee754_bits{ br }.to_float(); 42 | 43 | jkj::fp::to_chars_shortest_scientific(x, buffer1); 44 | if constexpr (std::is_same_v) { 45 | f2s_buffered(x, buffer2); 46 | } 47 | else { 48 | d2s_buffered(x, buffer2); 49 | } 50 | 51 | std::string_view view1(buffer1); 52 | std::string_view view2(buffer2); 53 | 54 | if (view1 != view2) { 55 | std::cout << "Error detected! [Ryu = " << buffer2 56 | << ", Dragonbox = " << buffer1 << "]\n"; 57 | success = false; 58 | } 59 | } 60 | 61 | if (success) { 62 | std::cout << "All cases are verified.\n"; 63 | } 64 | else { 65 | std::cout << "Error detected.\n"; 66 | } 67 | return success; 68 | } 69 | 70 | int main() 71 | { 72 | bool success = true; 73 | 74 | std::cout << "[Testing Dragonbox for all shorter interval cases for binary32...]\n"; 75 | success &= test_all_shorter_interval_cases_impl(); 76 | std::cout << "Done.\n\n\n"; 77 | 78 | std::cout << "[Testing Dragonbox for all shorter interval cases for binary64...]\n"; 79 | success &= test_all_shorter_interval_cases_impl(); 80 | std::cout << "Done.\n\n\n"; 81 | 82 | if (!success) { 83 | return -1; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /subproject/test/source/dragonbox_uniform_random_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "jkj/fp/to_chars/shortest_roundtrip.h" 19 | #include "random_float.h" 20 | #include "ryu/ryu.h" 21 | #include 22 | #include 23 | 24 | template 25 | static bool uniform_random_test(std::size_t number_of_tests, TypenameString&& type_name_string) 26 | { 27 | char buffer1[64]; 28 | char buffer2[64]; 29 | auto rg = jkj::fp::detail::generate_correctly_seeded_mt19937_64(); 30 | bool success = true; 31 | for (std::size_t test_idx = 0; test_idx < number_of_tests; ++test_idx) { 32 | auto x = jkj::fp::detail::uniformly_randomly_generate_general_float(rg); 33 | 34 | // Check if the output is identical to that of Ryu 35 | jkj::fp::to_chars_shortest_scientific(x, buffer1); 36 | if constexpr (std::is_same_v) { 37 | f2s_buffered(x, buffer2); 38 | } 39 | else { 40 | d2s_buffered(x, buffer2); 41 | } 42 | 43 | std::string_view view1(buffer1); 44 | std::string_view view2(buffer2); 45 | 46 | if (view1 != view2) { 47 | std::cout << "Error detected! [Ryu = " << buffer2 48 | << ", Dragonbox = " << buffer1 << "]\n"; 49 | success = false; 50 | } 51 | } 52 | 53 | if (success) { 54 | std::cout << "Uniform random test for " << type_name_string 55 | << " with " << number_of_tests << " examples succeeded.\n"; 56 | } 57 | 58 | return success; 59 | } 60 | 61 | int main() 62 | { 63 | constexpr bool run_float = true; 64 | constexpr std::size_t number_of_uniform_random_tests_float = 10000000; 65 | 66 | constexpr bool run_double = true; 67 | constexpr std::size_t number_of_uniform_random_tests_double = 10000000; 68 | 69 | bool success = true; 70 | 71 | if constexpr (run_float) { 72 | std::cout << "[Testing Dragonbox for uniformly randomly generated binary32 inputs...]\n"; 73 | success &= uniform_random_test(number_of_uniform_random_tests_float, "binary32"); 74 | std::cout << "Done.\n\n\n"; 75 | } 76 | if constexpr (run_double) { 77 | std::cout << "[Testing Dragonbox for uniformly randomly generated binary64 inputs...]\n"; 78 | success &= uniform_random_test(number_of_uniform_random_tests_double, "binary64"); 79 | std::cout << "Done.\n\n\n"; 80 | } 81 | 82 | if (!success) { 83 | return -1; 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /subproject/test/source/dragonbox_verify_fast_multiplication.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "jkj/fp/dragonbox.h" 19 | 20 | #include 21 | 22 | template 23 | static bool verify_fast_multiplication_xz() 24 | { 25 | using impl = jkj::fp::detail::dragonbox::impl; 26 | using carrier_uint = typename impl::carrier_uint; 27 | 28 | constexpr auto fl = (carrier_uint(1) << (impl::significand_bits + 2)) - 1; 29 | constexpr auto fr = (carrier_uint(1) << (impl::significand_bits + 2)) + 2; 30 | 31 | using jkj::fp::detail::log::floor_log10_pow2_minus_log10_4_over_3; 32 | using jkj::fp::detail::log::floor_log2_pow10; 33 | 34 | bool success = true; 35 | 36 | for (int e = impl::min_exponent + 1; e <= impl::max_exponent; ++e) { 37 | int const exponent = e - impl::significand_bits; 38 | 39 | // Compute k and beta 40 | int const minus_k = floor_log10_pow2_minus_log10_4_over_3(exponent); 41 | int const beta_minus_1 = exponent + floor_log2_pow10(-minus_k); 42 | int const beta_minus_2 = beta_minus_1 - 1; 43 | 44 | // Load cache 45 | auto const cache = jkj::fp::policy::cache::fast.get_cache(-minus_k); 46 | 47 | // Compute the endpoints using the fast method 48 | auto x_fast = impl::compute_left_endpoint_for_shorter_interval_case(cache, beta_minus_1); 49 | auto z_fast = impl::compute_right_endpoint_for_shorter_interval_case(cache, beta_minus_1); 50 | 51 | // Compute the endpoints using the exact method 52 | auto x_exact = beta_minus_2 >= 0 ? 53 | impl::compute_mul(fl << beta_minus_2, cache) : 54 | impl::compute_mul(fl, cache) >> -beta_minus_2; 55 | auto z_exact = beta_minus_2 >= 0 ? 56 | impl::compute_mul(fr << beta_minus_2, cache) : 57 | impl::compute_mul(fr, cache) >> -beta_minus_2; 58 | 59 | if (x_fast != x_exact) { 60 | std::cout << "(e = " << e << ") left endpoint is not correct; computed = " 61 | << x_fast << "; true_value = " << x_exact << "\n"; 62 | success = false; 63 | } 64 | if (z_fast != z_exact) { 65 | std::cout << "(e = " << e << ") right endpoint is not correct; computed = " 66 | << z_fast << "; true_value = " << z_exact << "\n"; 67 | success = false; 68 | } 69 | } 70 | 71 | if (success) { 72 | std::cout << "All cases are verified.\n"; 73 | } 74 | else { 75 | std::cout << "Error detected.\n"; 76 | } 77 | 78 | return success; 79 | } 80 | 81 | template 82 | static bool verify_fast_multiplication_yru() 83 | { 84 | using impl = jkj::fp::detail::dragonbox::impl; 85 | bool success = true; 86 | 87 | for (int k = impl::min_k; k < 0; ++k) { 88 | auto const cache = jkj::fp::policy::cache::fast.get_cache(k); 89 | 90 | // Since p + beta <= q, suffices to check that the lower half of the cache is not 0 91 | auto const lower_half = [cache] { 92 | if constexpr (impl::format == jkj::fp::ieee754_format::binary32) 93 | { 94 | return std::uint32_t(cache); 95 | } 96 | else 97 | { 98 | return cache.low(); 99 | } 100 | }(); 101 | 102 | if (lower_half == 0) { 103 | std::cout << "(k = " << k << ") computation might be incorrect\n"; 104 | success = false; 105 | } 106 | } 107 | 108 | if (success) { 109 | std::cout << "All cases are verified.\n"; 110 | } 111 | else { 112 | std::cout << "Error detected.\n"; 113 | } 114 | 115 | return success; 116 | } 117 | 118 | int main() 119 | { 120 | bool success = true; 121 | 122 | std::cout << "[Verifying fast computation of xi and zi for the closer boundary case (binary32)...]\n"; 123 | success &= verify_fast_multiplication_xz(); 124 | std::cout << "Done.\n\n\n"; 125 | 126 | std::cout << "[Verifying fast computation of yru for the closer boundary case (binary32)...]\n"; 127 | success &= verify_fast_multiplication_yru(); 128 | std::cout << "Done.\n\n\n"; 129 | 130 | std::cout << "[Verifying fast computation of xi and zi for the closer boundary case (binary64)...]\n"; 131 | success &= verify_fast_multiplication_xz(); 132 | std::cout << "Done.\n\n\n"; 133 | 134 | std::cout << "[Verifying fast computation of yru for the closer boundary case (binary64)...]\n"; 135 | success &= verify_fast_multiplication_yru(); 136 | std::cout << "Done.\n\n\n"; 137 | 138 | if (!success) { 139 | return -1; 140 | } 141 | } 142 | -------------------------------------------------------------------------------- /subproject/test/source/dragonbox_verify_magic_division.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "jkj/fp/dragonbox.h" 19 | 20 | #include 21 | #include 22 | 23 | template 24 | static bool verify_check_divisibility_and_divide_by_pow5() 25 | { 26 | using namespace jkj::fp::detail; 27 | 28 | constexpr int kappa = dragonbox::impl::kappa; 29 | constexpr auto max_n = compute_power(std::uint32_t(5)) * 2; 30 | constexpr auto divisor = compute_power(std::uint32_t(5)); 31 | 32 | bool success = true; 33 | for (std::uint32_t n = 0; n <= max_n; ++n) { 34 | std::uint32_t computed_quotient = n; 35 | auto computed_divisibility = 36 | div::check_divisibility_and_divide_by_pow5(computed_quotient); 37 | 38 | if (computed_quotient != (n / divisor)) { 39 | std::cout << "Dividing n = " << n << " by " << divisor 40 | << "; computed_quotient = " << computed_quotient 41 | << "; true_quotient = " << (n / divisor) << std::endl; 42 | success = false; 43 | } 44 | if (computed_divisibility != (n % divisor == 0)) { 45 | std::cout << "Dividing n = " << n << " by " << divisor 46 | << "; computed_divisibility = " << 47 | std::boolalpha << computed_divisibility 48 | << "; true_divisibility = " << (n % divisor == 0) << std::endl; 49 | success = false; 50 | } 51 | } 52 | 53 | if (success) { 54 | std::cout << "All cases are verified.\n"; 55 | } 56 | else { 57 | std::cout << "Error detected.\n"; 58 | } 59 | 60 | return success; 61 | } 62 | 63 | template 64 | static bool verify_divide_by_pow10() 65 | { 66 | using namespace jkj::fp::detail; 67 | 68 | constexpr int kappa = dragonbox::impl::kappa; 69 | constexpr auto max_n = compute_power(std::uint32_t(10)); 70 | constexpr auto divisor = compute_power(std::uint32_t(10)); 71 | 72 | bool success = true; 73 | for (std::uint32_t n = 0; n <= max_n; ++n) { 74 | auto computed_quotient = div::small_division_by_pow10(n); 75 | 76 | if (computed_quotient != (n / divisor)) { 77 | std::cout << "Dividing n = " << n << " by " << divisor 78 | << "; computed_quotient = " << computed_quotient 79 | << "; true_quotient = " << (n / divisor) << std::endl; 80 | success = false; 81 | } 82 | } 83 | 84 | if (success) { 85 | std::cout << "All cases are verified.\n"; 86 | } 87 | else { 88 | std::cout << "Error detected.\n"; 89 | } 90 | 91 | return success; 92 | } 93 | 94 | int main() 95 | { 96 | bool success = true; 97 | 98 | std::cout << "[Verifying divisibility check and division by 5^kappa for binary32...]\n"; 99 | success &= verify_check_divisibility_and_divide_by_pow5(); 100 | std::cout << "Done.\n\n\n"; 101 | 102 | std::cout << "[Verifying division by 10^kappa for binary32...]\n"; 103 | success &= verify_divide_by_pow10(); 104 | std::cout << "Done.\n\n\n"; 105 | 106 | std::cout << "[Verifying divisibility check and division by 5^kappa for binary64...]\n"; 107 | success &= verify_check_divisibility_and_divide_by_pow5(); 108 | std::cout << "Done.\n\n\n"; 109 | 110 | std::cout << "[Verifying division by 10^kappa for binary64...]\n"; 111 | success &= verify_divide_by_pow10(); 112 | std::cout << "Done.\n\n\n"; 113 | 114 | if (!success) { 115 | return -1; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /subproject/test/source/ryu_printf_dooly_uniform_random_joint_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "jkj/fp/from_chars/from_chars.h" 19 | #include "jkj/fp/to_chars/shortest_precise.h" 20 | #include "ryu/ryu.h" 21 | #include "random_float.h" 22 | #include 23 | #include 24 | #include 25 | 26 | template 27 | static bool uniform_random_test(std::size_t number_of_tests, TypenameString&& type_name_string) 28 | { 29 | auto buffer = std::make_unique(10000); 30 | 31 | auto rg = jkj::fp::detail::generate_correctly_seeded_mt19937_64(); 32 | bool success = true; 33 | for (std::size_t test_idx = 0; test_idx < number_of_tests; ++test_idx) { 34 | auto x = jkj::fp::detail::uniformly_randomly_generate_finite_float(rg); 35 | char* ptr = buffer.get(); 36 | ptr = jkj::fp::to_chars_precise_scientific_n(x, ptr); 37 | 38 | // Roudtrip 39 | auto roundtrip = jkj::fp::from_chars_unlimited(buffer.get(), ptr); 40 | 41 | if (x != roundtrip.to_float()) { 42 | char buffer1[64]; 43 | char buffer2[64]; 44 | if constexpr (jkj::fp::ieee754_traits::format == 45 | jkj::fp::ieee754_format::binary32) 46 | { 47 | f2s_buffered(x, buffer1); 48 | f2s_buffered(roundtrip.to_float(), buffer2); 49 | } 50 | else 51 | { 52 | d2s_buffered(x, buffer2); 53 | d2s_buffered(roundtrip.to_float(), buffer2); 54 | } 55 | std::cout << "Error detected! [Input = " << buffer1 56 | << ", Roundtrip = " << buffer2 << "]\n"; 57 | success = false; 58 | } 59 | } 60 | 61 | if (success) { 62 | std::cout << "Uniform random test for " << type_name_string 63 | << " with " << number_of_tests << " examples succeeded.\n"; 64 | } 65 | 66 | return success; 67 | } 68 | 69 | int main() 70 | { 71 | constexpr std::size_t number_of_uniform_random_tests = 10000000; 72 | bool success = true; 73 | 74 | std::cout << "[Joint-testing Ryu-printf and Dooly for uniformly randomly generated binary32 inputs...]\n"; 75 | success &= uniform_random_test(number_of_uniform_random_tests, "binary32"); 76 | std::cout << "Done.\n\n\n"; 77 | 78 | std::cout << "[Joint-testing Ryu-printf and Dooly for uniformly randomly generated binary64 inputs...]\n"; 79 | success &= uniform_random_test(number_of_uniform_random_tests, "binary64"); 80 | std::cout << "Done.\n\n\n"; 81 | 82 | if (!success) { 83 | return -1; 84 | } 85 | } -------------------------------------------------------------------------------- /subproject/test/source/ryu_printf_uniform_random_test.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "jkj/fp/to_chars/fixed_precision.h" 19 | #include "jkj/fp/to_chars/shortest_roundtrip.h" 20 | #include "random_float.h" 21 | #include "ryu/ryu.h" 22 | #include 23 | #include 24 | #include 25 | #include 26 | 27 | template 28 | bool test_scientific(std::size_t number_of_samples, int max_precision, TypenameString&& type_name_string) 29 | { 30 | assert(max_precision >= 0); 31 | auto buffer1 = std::make_unique(10000); 32 | auto buffer2 = std::make_unique(10000); 33 | char buffer3[41]; 34 | bool success = true; 35 | 36 | // Generate random inputs 37 | std::cout << "Generating samples...\n"; 38 | auto rg = jkj::fp::detail::generate_correctly_seeded_mt19937_64(); 39 | std::vector samples(number_of_samples); 40 | for (std::size_t i = 0; i < number_of_samples; ++i) { 41 | samples[i] = jkj::fp::detail::uniformly_randomly_generate_finite_float(rg); 42 | } 43 | std::cout << "Done.\n\n\n"; 44 | 45 | // For each precision, test the output against ryu 46 | for (int precision = 0; precision <= max_precision; ++precision) { 47 | std::cout << "Testing for precision = " << precision << "...\n"; 48 | 49 | for (auto const& sample : samples) { 50 | std::string_view s1{ buffer1.get(), std::size_t( 51 | jkj::fp::to_chars_fixed_precision_scientific_n(sample, buffer1.get(), precision) - buffer1.get()) }; 52 | std::string_view s2{ buffer2.get(), std::size_t( 53 | d2exp_buffered_n(double(sample), precision, buffer2.get())) }; 54 | 55 | if (s1 != s2) { 56 | jkj::fp::to_chars_shortest_scientific(sample, buffer3); 57 | std::cout << "Error detected! [sample = " << buffer3 58 | << ", Ryu = " << s2 << ", fp = " << s1 << "]\n"; 59 | success = false; 60 | } 61 | } 62 | 63 | std::cout << std::endl; 64 | } 65 | 66 | if (success) { 67 | std::cout << "\nUniform random test for " << type_name_string 68 | << " with " << number_of_samples << " examples succeeded.\n"; 69 | } 70 | 71 | return success; 72 | } 73 | 74 | int main() 75 | { 76 | constexpr bool run_float = true; 77 | constexpr std::size_t number_of_samples_float = 100000; 78 | constexpr int max_precision_float = 120; // max_nonzero_decimal_digits = 112 79 | 80 | constexpr bool run_double = true; 81 | constexpr std::size_t number_of_samples_double = 100000; 82 | constexpr int max_precision_double = 780; // max_nonzero_decimal_digits = 767 83 | 84 | bool success = true; 85 | 86 | if constexpr (run_float) { 87 | std::cout << "[Testing fixed-precision scientific formatting with " 88 | << "uniformly randomly generated binary32 inputs...]\n"; 89 | success &= test_scientific(number_of_samples_float, max_precision_float, "binary32"); 90 | std::cout << "Done.\n\n\n"; 91 | } 92 | if constexpr (run_double) { 93 | std::cout << "[Testing fixed-precision scientific formatting with " 94 | << "uniformly randomly generated binary64 inputs...]\n"; 95 | success &= test_scientific(number_of_samples_double, max_precision_double, "binary64"); 96 | std::cout << "Done.\n\n\n"; 97 | } 98 | 99 | if (!success) { 100 | return -1; 101 | } 102 | } -------------------------------------------------------------------------------- /subproject/test/source/test_minmax_euclid.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "minmax_euclid.h" 19 | #include 20 | 21 | int main() 22 | { 23 | using jkj::fp::detail::bigint; 24 | using jkj::fp::detail::minmax_euclid; 25 | 26 | bool success = true; 27 | 28 | std::cout << "[Min-max Euclid algorithm test]\n"; 29 | 30 | { 31 | bigint<64> a = 3; 32 | bigint<64> b = 7; 33 | bigint<64> N = 3; 34 | auto ret = minmax_euclid(a, b, N); 35 | if (ret.min != 2 || ret.max != 6 || 36 | ret.argmin != 3 || ret.argmax != 2) 37 | { 38 | std::cout << "Test failed! (a = 3, b = 7, N = 3)\n"; 39 | success = false; 40 | } 41 | } 42 | 43 | { 44 | bigint<64> a = 16; 45 | bigint<64> b = 6; 46 | bigint<64> N = 3; 47 | auto ret = minmax_euclid(a, b, N); 48 | if (ret.min != 0 || ret.max != 4 || 49 | ret.argmin != 3 || ret.argmax != 1) 50 | { 51 | std::cout << "Test failed! (a = 16, b = 6, N = 4)\n"; 52 | success = false; 53 | } 54 | } 55 | 56 | { 57 | bigint<64> a = 1234567; 58 | bigint<64> b = 1234567; 59 | bigint<64> N = 123456789; 60 | auto ret = minmax_euclid(a, b, N); 61 | if (ret.min != 0 || ret.max != 0) 62 | { 63 | std::cout << "Test failed! (a = 1234567, b = 1234567, N = 123456789)\n"; 64 | success = false; 65 | } 66 | } 67 | 68 | { 69 | bigint<64> a = 13; 70 | bigint<64> b = 69; 71 | bigint<64> N = 40; 72 | auto ret = minmax_euclid(a, b, N); 73 | if (ret.min != 1 || ret.max != 67 || 74 | ret.argmin != 16 || ret.argmax != 37) 75 | { 76 | std::cout << "Test failed! (a = 13, b = 69, N = 40)\n"; 77 | success = false; 78 | } 79 | } 80 | 81 | std::cout << std::endl; 82 | std::cout << "Done.\n\n\n"; 83 | 84 | if (!success) { 85 | return -1; 86 | } 87 | } -------------------------------------------------------------------------------- /subproject/test/source/test_policy_holder.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Junekey Jeon 2 | // 3 | // The contents of this file may be used under the terms of 4 | // the Apache License v2.0 with LLVM Exceptions. 5 | // 6 | // (See accompanying file LICENSE-Apache or copy at 7 | // https://llvm.org/foundation/relicensing/LICENSE.txt) 8 | // 9 | // Alternatively, the contents of this file may be used under the terms of 10 | // the Boost Software License, Version 1.0. 11 | // (See accompanying file LICENSE-Boost or copy at 12 | // https://www.boost.org/LICENSE_1_0.txt) 13 | // 14 | // Unless required by applicable law or agreed to in writing, this software 15 | // is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | // KIND, either express or implied. 17 | 18 | #include "jkj/fp/policy.h" 19 | #include 20 | #include 21 | 22 | namespace test_policy_kind { 23 | struct a {}; 24 | struct b {}; 25 | struct c {}; 26 | struct d {}; 27 | } 28 | 29 | namespace a { 30 | struct policy1 { 31 | using policy_kind = test_policy_kind::a; 32 | int x; 33 | auto get_a() { return x; } 34 | }; 35 | 36 | struct policy2 { 37 | using policy_kind = test_policy_kind::a; 38 | float x; 39 | auto get_a() { return x; } 40 | }; 41 | } 42 | 43 | namespace b { 44 | struct policy1 { 45 | using policy_kind = test_policy_kind::b; 46 | int x; 47 | auto get_b() { return x; } 48 | }; 49 | 50 | struct policy2 { 51 | using policy_kind = test_policy_kind::b; 52 | float x; 53 | auto get_b() { return x; } 54 | }; 55 | } 56 | 57 | namespace c { 58 | struct policy1 { 59 | using policy_kind = test_policy_kind::c; 60 | int x; 61 | auto get_c() { return x; } 62 | }; 63 | 64 | struct policy2 { 65 | using policy_kind = test_policy_kind::c; 66 | float x; 67 | auto get_c() { return x; } 68 | }; 69 | 70 | struct policy3 { 71 | using policy_kind = test_policy_kind::c; 72 | auto get_c() { return 1.2345; } 73 | }; 74 | } 75 | 76 | namespace d { 77 | struct policy1 { 78 | using policy_kind = test_policy_kind::d; 79 | }; 80 | } 81 | 82 | int main() 83 | { 84 | using namespace jkj::fp::detail::policy; 85 | bool success = true; 86 | 87 | std::cout << "[Policy holder test]\n"; 88 | 89 | { 90 | auto policy_holder = make_policy_holder( 91 | make_default_list( 92 | make_default(a::policy1{ 10 }), 93 | make_default_generator([]() { return b::policy2{ 0.5f }; }), 94 | make_default(c::policy2{ 0.1f }) 95 | ), 96 | a::policy1{ 4 } 97 | ); 98 | 99 | success &= (policy_holder.get_a() == 4); 100 | success &= (policy_holder.get_b() == 0.5f); 101 | success &= (policy_holder.get_c() == 0.1f); 102 | } 103 | 104 | { 105 | auto policy_holder = make_policy_holder( 106 | make_default_list( 107 | make_default(a::policy1{ 10 }), 108 | make_default_generator([]() { return b::policy2{ 0.5f }; }), 109 | make_default(c::policy2{ 0.1f }) 110 | ), 111 | b::policy1{ 100 }, a::policy2{ 0.3f } 112 | ); 113 | 114 | success &= (policy_holder.get_a() == 0.3f); 115 | success &= (policy_holder.get_b() == 100); 116 | success &= (policy_holder.get_c() == 0.1f); 117 | } 118 | 119 | { 120 | auto policy_holder = make_policy_holder( 121 | make_default_list( 122 | make_default(c::policy2{ 0.6f }), 123 | make_default(d::policy1{}) 124 | ), 125 | c::policy3{} 126 | ); 127 | 128 | success &= std::is_empty_v; 129 | } 130 | 131 | std::cout << std::endl; 132 | std::cout << "Done.\n\n\n"; 133 | 134 | if (!success) { 135 | return -1; 136 | } 137 | } --------------------------------------------------------------------------------