diff options
Diffstat (limited to 'libc/src')
104 files changed, 6785 insertions, 5150 deletions
diff --git a/libc/src/__support/CMakeLists.txt b/libc/src/__support/CMakeLists.txt index df524c2..64cf3687 100644 --- a/libc/src/__support/CMakeLists.txt +++ b/libc/src/__support/CMakeLists.txt @@ -391,6 +391,21 @@ add_header_library( libc.src.__support.macros.attributes ) +add_header_library( + weak_avl + HDRS + weak_avl.h + DEPENDS + libc.hdr.stdint_proxy + libc.src.__support.CPP.bit + libc.src.__support.CPP.new + libc.src.__support.CPP.utility + libc.src.__support.CPP.optional + libc.src.__support.libc_assert + libc.src.__support.macros.attributes + libc.src.__support.macros.config +) + add_subdirectory(FPUtil) add_subdirectory(OSUtil) add_subdirectory(StringUtil) diff --git a/libc/src/__support/CPP/limits.h b/libc/src/__support/CPP/limits.h index cf4beb9..76158b2 100644 --- a/libc/src/__support/CPP/limits.h +++ b/libc/src/__support/CPP/limits.h @@ -1,4 +1,4 @@ -//===-- A self contained equivalent of std::limits --------------*- C++ -*-===// +//===-- A self contained equivalent of <limits> ----------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -13,78 +13,42 @@ #include "src/__support/CPP/type_traits/is_integral.h" #include "src/__support/CPP/type_traits/is_signed.h" #include "src/__support/macros/attributes.h" // LIBC_INLINE -#include "src/__support/macros/config.h" -#include "src/__support/macros/properties/types.h" // LIBC_TYPES_HAS_INT128 namespace LIBC_NAMESPACE_DECL { namespace cpp { namespace internal { -template <typename T, T min_value, T max_value> struct integer_impl { - static_assert(cpp::is_integral_v<T>); - LIBC_INLINE static constexpr T max() { return max_value; } - LIBC_INLINE static constexpr T min() { return min_value; } +template <typename T, bool is_integral> struct numeric_limits_impl {}; + +template <typename T> struct numeric_limits_impl<T, true> { + LIBC_INLINE_VAR static constexpr bool is_signed = T(-1) < T(0); + LIBC_INLINE_VAR static constexpr int digits = - CHAR_BIT * sizeof(T) - cpp::is_signed_v<T>; + (CHAR_BIT * sizeof(T)) - is_signed; + + LIBC_INLINE static constexpr T min() { + if constexpr (is_signed) { + return T(T(1) << digits); + } else { + return 0; + } + } + + LIBC_INLINE static constexpr T max() { + if constexpr (is_signed) { + return T(T(~0) ^ min()); + } else { + return T(~0); + } + } }; } // namespace internal -template <class T> struct numeric_limits {}; - -// TODO: Add numeric_limits specializations as needed for new types. -template <> -struct numeric_limits<short> - : public internal::integer_impl<short, SHRT_MIN, SHRT_MAX> {}; - -template <> -struct numeric_limits<unsigned short> - : public internal::integer_impl<unsigned short, 0, USHRT_MAX> {}; - -template <> -struct numeric_limits<int> - : public internal::integer_impl<int, INT_MIN, INT_MAX> {}; - -template <> -struct numeric_limits<unsigned int> - : public internal::integer_impl<unsigned int, 0, UINT_MAX> {}; - -template <> -struct numeric_limits<long> - : public internal::integer_impl<long, LONG_MIN, LONG_MAX> {}; - -template <> -struct numeric_limits<unsigned long> - : public internal::integer_impl<unsigned long, 0, ULONG_MAX> {}; - -template <> -struct numeric_limits<long long> - : public internal::integer_impl<long long, LLONG_MIN, LLONG_MAX> {}; - -template <> -struct numeric_limits<unsigned long long> - : public internal::integer_impl<unsigned long long, 0, ULLONG_MAX> {}; - -template <> -struct numeric_limits<char> - : public internal::integer_impl<char, CHAR_MIN, CHAR_MAX> {}; - -template <> -struct numeric_limits<signed char> - : public internal::integer_impl<signed char, SCHAR_MIN, SCHAR_MAX> {}; - -template <> -struct numeric_limits<unsigned char> - : public internal::integer_impl<unsigned char, 0, UCHAR_MAX> {}; - -#ifdef LIBC_TYPES_HAS_INT128 -// On platform where UInt128 resolves to __uint128_t, this specialization -// provides the limits of UInt128. -template <> -struct numeric_limits<__uint128_t> - : public internal::integer_impl<__uint128_t, 0, ~__uint128_t(0)> {}; -#endif +template <typename T> +struct numeric_limits + : public internal::numeric_limits_impl<T, is_integral_v<T>> {}; } // namespace cpp } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/__support/CPP/type_traits/is_integral.h b/libc/src/__support/CPP/type_traits/is_integral.h index 96ba09a..09047cb 100644 --- a/libc/src/__support/CPP/type_traits/is_integral.h +++ b/libc/src/__support/CPP/type_traits/is_integral.h @@ -26,13 +26,18 @@ private: } public: - LIBC_INLINE_VAR static constexpr bool value = __is_unqualified_any_of< - T, + LIBC_INLINE_VAR static constexpr bool value = + __is_unqualified_any_of<T, #ifdef LIBC_TYPES_HAS_INT128 - __int128_t, __uint128_t, + __int128_t, __uint128_t, #endif - char, signed char, unsigned char, short, unsigned short, int, - unsigned int, long, unsigned long, long long, unsigned long long, bool>(); +#ifdef __cpp_char8_t + char8_t, +#endif + char16_t, char32_t, char, signed char, + unsigned char, short, unsigned short, int, + unsigned int, long, unsigned long, long long, + unsigned long long, bool>(); }; template <typename T> LIBC_INLINE_VAR constexpr bool is_integral_v = is_integral<T>::value; diff --git a/libc/src/__support/CPP/type_traits/is_unsigned.h b/libc/src/__support/CPP/type_traits/is_unsigned.h index b4267ee..87c352b 100644 --- a/libc/src/__support/CPP/type_traits/is_unsigned.h +++ b/libc/src/__support/CPP/type_traits/is_unsigned.h @@ -10,7 +10,7 @@ #include "include/llvm-libc-macros/stdfix-macros.h" #include "src/__support/CPP/type_traits/bool_constant.h" -#include "src/__support/CPP/type_traits/is_arithmetic.h" +#include "src/__support/CPP/type_traits/is_integral.h" #include "src/__support/CPP/type_traits/is_same.h" #include "src/__support/CPP/type_traits/remove_cv.h" #include "src/__support/macros/attributes.h" @@ -23,7 +23,7 @@ namespace cpp { #ifndef LIBC_COMPILER_HAS_FIXED_POINT template <typename T> -struct is_unsigned : bool_constant<(is_arithmetic_v<T> && (T(-1) > T(0)))> { +struct is_unsigned : bool_constant<(is_integral_v<T> && (T(-1) > T(0)))> { LIBC_INLINE constexpr operator bool() const { return is_unsigned::value; } LIBC_INLINE constexpr bool operator()() const { return is_unsigned::value; } }; @@ -37,7 +37,7 @@ private: public: LIBC_INLINE_VAR static constexpr bool value = - (is_arithmetic_v<T> && (T(-1) > T(0))) || + (is_integral_v<T> && (T(-1) > T(0))) || __is_unqualified_any_of<T, unsigned short fract, unsigned fract, unsigned long fract, unsigned short accum, unsigned accum, unsigned long accum, diff --git a/libc/src/__support/GPU/allocator.cpp b/libc/src/__support/GPU/allocator.cpp index 7182180..f8a3b46 100644 --- a/libc/src/__support/GPU/allocator.cpp +++ b/libc/src/__support/GPU/allocator.cpp @@ -498,20 +498,21 @@ public: result = gpu::shuffle(lane_mask, cpp::countr_zero(uniform), result); count = gpu::shuffle(lane_mask, cpp::countr_zero(uniform), count); + if (!result) + return nullptr; + // We defer storing the newly allocated slab until now so that we can use // multiple lanes to initialize it and release it for use. - uint64_t slab_mask = - gpu::ballot(lane_mask, result && impl::is_sentinel(count)); - if (slab_mask & impl::id_in_mask()) { - result->initialize(slab_mask, uniform); + if (impl::is_sentinel(count)) { + uint64_t count_mask = gpu::get_lane_mask(); + result->initialize(count_mask, uniform); if (gpu::get_lane_id() == uint32_t(cpp::countr_zero(uniform))) finalize(result, cpp::popcount(uniform), count); - count = gpu::shuffle(slab_mask, cpp::countr_zero(uniform), count); + count = gpu::shuffle(count_mask, cpp::countr_zero(uniform), count); } - if (result) - count = count - cpp::popcount(uniform) + - impl::lane_count(uniform, gpu::get_lane_id()); + count = count - cpp::popcount(uniform) + + impl::lane_count(uniform, gpu::get_lane_id()); return result; } diff --git a/libc/src/__support/math/CMakeLists.txt b/libc/src/__support/math/CMakeLists.txt index 4139a1b..aad2270 100644 --- a/libc/src/__support/math/CMakeLists.txt +++ b/libc/src/__support/math/CMakeLists.txt @@ -390,7 +390,6 @@ add_header_library( cosf.h DEPENDS .sincosf_utils - libc.src.errno.errno libc.src.__support.FPUtil.basic_operations libc.src.__support.FPUtil.fenv_impl libc.src.__support.FPUtil.fp_bits @@ -595,6 +594,15 @@ add_header_library( ) add_header_library( + f16sqrtl + HDRS + f16sqrtl.h + DEPENDS + libc.src.__support.FPUtil.generic.sqrt + libc.src.__support.macros.properties.types +) + +add_header_library( frexpf128 HDRS frexpf128.h @@ -604,6 +612,22 @@ add_header_library( ) add_header_library( + fsqrt + HDRS + fsqrt.h + DEPENDS + libc.src.__support.FPUtil.generic.sqrt +) + +add_header_library( + fsqrtl + HDRS + fsqrtl.h + DEPENDS + libc.src.__support.FPUtil.generic.sqrt +) + +add_header_library( inv_trigf_utils HDRS inv_trigf_utils.h @@ -632,6 +656,36 @@ add_header_library( ) add_header_library( + f16fma + HDRS + f16fma.h + DEPENDS + libc.src.__support.FPUtil.fma + libc.src.__support.macros.config + libc.include.llvm-libc-macros.float16_macros +) + +add_header_library( + f16fmal + HDRS + f16fmal.h + DEPENDS + libc.src.__support.macros.config + libc.src.__support.FPUtil.fma + libc.include.llvm-libc-macros.float16_macros +) + +add_header_library( + ilogb + HDRS + ilogb.h + DEPENDS + libc.src.__support.common + libc.src.__support.macros.config + libc.src.__support.FPUtil.manipulation_functions +) + +add_header_library( ilogbf16 HDRS ilogbf16.h @@ -643,6 +697,36 @@ add_header_library( ) add_header_library( + ilogbf128 + HDRS + ilogbf128.h + DEPENDS + libc.src.__support.macros.properties.types + libc.src.__support.FPUtil.manipulation_functions + libc.include.llvm-libc-types.float128 +) + +add_header_library( + llogbf16 + HDRS + llogbf16.h + DEPENDS + libc.src.__support.macros.config + libc.src.__support.FPUtil.manipulation_functions + libc.include.llvm-libc-macros.float16_macros +) + +add_header_library( + ilogbf + HDRS + ilogbf.h + DEPENDS + libc.src.__support.macros.config + libc.src.__support.macros.properties.types + libc.src.__support.FPUtil.manipulation_functions +) + +add_header_library( ldexpf128 HDRS ldexpf128.h @@ -653,6 +737,16 @@ add_header_library( ) add_header_library( + llogbf128 + HDRS + llogbf128.h + DEPENDS + libc.src.__support.macros.config + libc.src.__support.FPUtil.manipulation_functions + libc.include.llvm-libc-types.float128 +) + +add_header_library( ldexpf16 HDRS ldexpf16.h @@ -671,6 +765,37 @@ add_header_library( ) add_header_library( + llogbf + HDRS + llogbf.h + DEPENDS + libc.src.__support.FPUtil.manipulation_functions + libc.src.__support.common + libc.src.__support.macros.config +) + +add_header_library( + logf16 + HDRS + logf16.h + DEPENDS + .expxf16_utils + libc.hdr.errno_macros + libc.hdr.fenv_macros + libc.src.__support.common + libc.src.__support.FPUtil.cast + libc.src.__support.FPUtil.except_value_utils + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.polyeval + libc.src.__support.macros.config + libc.src.__support.macros.optimization + libc.src.__support.macros.properties.cpu_features + libc.include.llvm-libc-macros.float16_macros +) + +add_header_library( exp_constants HDRS exp_constants.h @@ -936,6 +1061,38 @@ add_header_library( ) add_header_library( + fsqrtf128 + HDRS + fsqrtf128.h + DEPENDS + libc.src.__support.FPUtil.generic.sqrt + libc.src.__support.macros.properties.types +) + +add_header_library( + hypotf + HDRS + hypotf.h + DEPENDS + libc.src.__support.FPUtil.double_double + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.sqrt + libc.src.__support.macros.optimization +) + +add_header_library( + ilogbl + HDRS + ilogbl.h + DEPENDS + libc.src.__support.FPUtil.manipulation_functions + libc.src.__support.common + libc.src.__support.macros.config +) + +add_header_library( range_reduction_double HDRS range_reduction_double_common.h @@ -994,6 +1151,15 @@ add_header_library( ) add_header_library( + sqrtf16 + HDRS + sqrtf16.h + DEPENDS + libc.src.__support.FPUtil.sqrt + libc.include.llvm-libc-macros.float16_macros +) + +add_header_library( sincos_eval HDRS sincos_eval.h @@ -1037,6 +1203,31 @@ add_header_library( ) add_header_library( + sinpif + HDRS + sinpif.h + DEPENDS + .sincosf_utils + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.polyeval + libc.src.__support.FPUtil.multiply_add + libc.src.__support.common + libc.src.__support.macros.config + libc.src.__support.macros.optimization +) + +add_header_library( + llogb + HDRS + llogb.h + DEPENDS + libc.src.__support.FPUtil.manipulation_functions + libc.src.__support.common + libc.src.__support.macros.config +) + +add_header_library( log HDRS log.h @@ -1054,6 +1245,99 @@ add_header_library( ) add_header_library( + log10 + HDRS + log10.h + DEPENDS + .common_constants + .log_range_reduction + libc.src.__support.FPUtil.double_double + libc.src.__support.FPUtil.dyadic_float + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.polyeval + libc.src.__support.integer_literals + libc.src.__support.macros.optimization +) + +add_header_library( + log1p + HDRS + log1p.h + DEPENDS + .common_constants + libc.src.__support.FPUtil.double_double + libc.src.__support.FPUtil.dyadic_float + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.polyeval + libc.src.__support.integer_literals + libc.src.__support.macros.optimization +) + +add_header_library( + log2 + HDRS + log2.h + DEPENDS + .common_constants + .log_range_reduction + libc.src.__support.FPUtil.double_double + libc.src.__support.FPUtil.dyadic_float + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.polyeval + libc.src.__support.integer_literals + libc.src.__support.macros.optimization +) + +add_header_library( + logbf128 + HDRS + logbf128.h + DEPENDS + libc.src.__support.FPUtil.manipulation_functions + libc.src.__support.macros.properties.types +) + +add_header_library( + logbf16 + HDRS + logbf16.h + DEPENDS + libc.src.__support.FPUtil.manipulation_functions + libc.src.__support.macros.properties.types +) + +add_header_library( + logbf + HDRS + logbf.h + DEPENDS + libc.src.__support.FPUtil.manipulation_functions +) + +add_header_library( + logf + HDRS + logf.h + DEPENDS + .common_constants + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.polyeval + libc.src.__support.FPUtil.except_value_utils + libc.src.__support.FPUtil.multiply_add + libc.src.__support.common + libc.src.__support.macros.config + libc.src.__support.macros.optimization + libc.src.__support.macros.properties.cpu_features +) + +add_header_library( log_range_reduction HDRS log_range_reduction.h @@ -1078,3 +1362,128 @@ add_header_library( libc.src.__support.math.sincos_eval libc.src.__support.macros.optimization ) + +add_header_library( + sinf + HDRS + sinf.h + DEPENDS + .range_reduction + .sincosf_utils + libc.src.__support.FPUtil.basic_operations + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fma + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.polyeval + libc.src.__support.FPUtil.rounding_mode + libc.src.__support.macros.optimization +) + +add_header_library( + sinf16 + HDRS + sinf16.h + DEPENDS + .sincosf16_utils + libc.hdr.errno_macros + libc.hdr.fenv_macros + libc.include.llvm-libc-macros.float16_macros + libc.src.__support.FPUtil.cast + libc.src.__support.FPUtil.except_value_utils + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.multiply_add + libc.src.__support.macros.optimization + libc.src.__support.macros.properties.types +) + +add_header_library( + sinhf + HDRS + sinhf.h + DEPENDS + .sinhfcoshf_utils + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.rounding_mode + libc.src.__support.macros.config + libc.src.__support.macros.optimization +) + +add_header_library( + sinhf16 + HDRS + sinhf16.h + DEPENDS + .expxf16_utils + libc.hdr.errno_macros + libc.hdr.fenv_macros + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.except_value_utils + libc.src.__support.FPUtil.rounding_mode + libc.src.__support.common + libc.src.__support.macros.config + libc.src.__support.macros.optimization +) + +add_header_library( + sqrt + HDRS + sqrt.h + DEPENDS + libc.src.__support.FPUtil.sqrt +) + +add_header_library( + dfmal + HDRS + dfmal.h + DEPENDS + libc.src.__support.FPUtil.fma + libc.src.__support.common + libc.src.__support.macros.config +) + +add_header_library( + dfmaf128 + HDRS + dfmaf128.h + DEPENDS + libc.src.__support.FPUtil.fma + libc.src.__support.common + libc.src.__support.macros.config + libc.include.llvm-libc-types.float128 +) + +add_header_library( + tan + HDRS + tan.h + DEPENDS + .range_reduction_double + libc.hdr.errno_macros + libc.src.__support.FPUtil.double_double + libc.src.__support.FPUtil.dyadic_float + libc.src.__support.FPUtil.except_value_utils + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fp_bits + libc.src.__support.FPUtil.multiply_add + libc.src.__support.macros.optimization +) + +add_header_library( + tanf + HDRS + tanf.h + DEPENDS + .range_reduction + .sincosf_utils + libc.src.__support.FPUtil.except_value_utils + libc.src.__support.FPUtil.fenv_impl + libc.src.__support.FPUtil.fma + libc.src.__support.FPUtil.multiply_add + libc.src.__support.FPUtil.nearest_integer + libc.src.__support.FPUtil.polyeval + libc.src.__support.macros.optimization +) diff --git a/libc/src/__support/math/asin.h b/libc/src/__support/math/asin.h index 5e06d04..396a535 100644 --- a/libc/src/__support/math/asin.h +++ b/libc/src/__support/math/asin.h @@ -25,7 +25,7 @@ namespace LIBC_NAMESPACE_DECL { namespace math { -LIBC_INLINE static constexpr double asin(double x) { +LIBC_INLINE static double asin(double x) { using namespace asin_internal; using FPBits = fputil::FPBits<double>; diff --git a/libc/src/__support/math/atan2f_float.h b/libc/src/__support/math/atan2f_float.h index 8bd7095..cc5ea77 100644 --- a/libc/src/__support/math/atan2f_float.h +++ b/libc/src/__support/math/atan2f_float.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LIBC_SRC___SUPPORT_MATH_ATAN2F_FLOAT_H -#define LIBC_SRC___SUPPORT_MATH_ATAN2F_FLOAT_H +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_ATAN2F_FLOAT_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_ATAN2F_FLOAT_H #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/double_double.h" @@ -242,4 +242,4 @@ LIBC_INLINE static constexpr float atan2f(float y, float x) { } // namespace LIBC_NAMESPACE_DECL -#endif // LIBC_SRC___SUPPORT_MATH_ATAN2F_FLOAT_H +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_ATAN2F_FLOAT_H diff --git a/libc/src/__support/math/atanf_float.h b/libc/src/__support/math/atanf_float.h index 3e5adf3..8794cec 100644 --- a/libc/src/__support/math/atanf_float.h +++ b/libc/src/__support/math/atanf_float.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LIBC_SRC___SUPPORT_MATH_ATANF_FLOAT_H -#define LIBC_SRC___SUPPORT_MATH_ATANF_FLOAT_H +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_ATANF_FLOAT_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_ATANF_FLOAT_H #include "src/__support/FPUtil/FEnvImpl.h" #include "src/__support/FPUtil/FPBits.h" @@ -165,4 +165,4 @@ LIBC_INLINE static float atanf(float x) { } // namespace LIBC_NAMESPACE_DECL -#endif // LIBC_SRC___SUPPORT_MATH_ATANF_FLOAT_H +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_ATANF_FLOAT_H diff --git a/libc/src/__support/math/cbrt.h b/libc/src/__support/math/cbrt.h index fe6bc19..38df9fb 100644 --- a/libc/src/__support/math/cbrt.h +++ b/libc/src/__support/math/cbrt.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LIBC_SRC___SUPPORT_MATH_CBRT_H -#define LIBC_SRC___SUPPORT_MATH_CBRT_H +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_CBRT_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_CBRT_H #include "src/__support/FPUtil/FEnvImpl.h" #include "src/__support/FPUtil/FPBits.h" @@ -347,4 +347,4 @@ LIBC_INLINE static constexpr double cbrt(double x) { } // namespace LIBC_NAMESPACE_DECL -#endif // LIBC_SRC___SUPPORT_MATH_CBRT_H +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_CBRT_H diff --git a/libc/src/__support/math/cbrtf.h b/libc/src/__support/math/cbrtf.h index f82892b..d7ff1cd 100644 --- a/libc/src/__support/math/cbrtf.h +++ b/libc/src/__support/math/cbrtf.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LIBC_SRC___SUPPORT_MATH_CBRTF_H -#define LIBC_SRC___SUPPORT_MATH_CBRTF_H +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_CBRTF_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_CBRTF_H #include "src/__support/FPUtil/FEnvImpl.h" #include "src/__support/FPUtil/FPBits.h" @@ -158,4 +158,4 @@ LIBC_INLINE static constexpr float cbrtf(float x) { } // namespace LIBC_NAMESPACE_DECL -#endif // LIBC_SRC___SUPPORT_MATH_CBRTF_H +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_CBRTF_H diff --git a/libc/src/__support/math/cos.h b/libc/src/__support/math/cos.h index 0802f9e..cd4abc2 100644 --- a/libc/src/__support/math/cos.h +++ b/libc/src/__support/math/cos.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LIBC_SRC___SUPPORT_MATH_COS_H -#define LIBC_SRC___SUPPORT_MATH_COS_H +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_COS_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_COS_H #include "range_reduction_double_common.h" #include "sincos_eval.h" @@ -170,4 +170,4 @@ LIBC_INLINE static constexpr double cos(double x) { } // namespace LIBC_NAMESPACE_DECL -#endif // LIBC_SRC___SUPPORT_MATH_COS_H +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_COS_H diff --git a/libc/src/__support/math/cosf.h b/libc/src/__support/math/cosf.h index 48ba71a..e635d30 100644 --- a/libc/src/__support/math/cosf.h +++ b/libc/src/__support/math/cosf.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LIBC_SRC___SUPPORT_MATH_COSF_H -#define LIBC_SRC___SUPPORT_MATH_COSF_H +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_COSF_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_COSF_H #include "src/__support/FPUtil/FEnvImpl.h" #include "src/__support/FPUtil/FPBits.h" @@ -169,6 +169,6 @@ LIBC_INLINE static constexpr float cosf(float x) { } // namespace LIBC_NAMESPACE_DECL -#endif // LIBC_SRC___SUPPORT_MATH_COSF_H +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_COSF_H #endif // LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT diff --git a/libc/src/__support/math/dfmaf128.h b/libc/src/__support/math/dfmaf128.h new file mode 100644 index 0000000..0a266d4 --- /dev/null +++ b/libc/src/__support/math/dfmaf128.h @@ -0,0 +1,31 @@ +//===-- Implementation header for dfmaf128 --------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_DFMAF128_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_DFMAF128_H + +#include "include/llvm-libc-types/float128.h" + +#ifdef LIBC_TYPES_HAS_FLOAT128 + +#include "src/__support/FPUtil/FMA.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace math { + +LIBC_INLINE static double dfmaf128(float128 x, float128 y, float128 z) { + return fputil::fma<double>(x, y, z); +} + +} // namespace math +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_TYPES_HAS_FLOAT128 +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_DFMAF128_H diff --git a/libc/src/__support/math/dfmal.h b/libc/src/__support/math/dfmal.h new file mode 100644 index 0000000..ffe94bc --- /dev/null +++ b/libc/src/__support/math/dfmal.h @@ -0,0 +1,26 @@ +//===-- Implementation header for dfmal -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_DFMAL_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_DFMAL_H + +#include "src/__support/FPUtil/FMA.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace math { + +LIBC_INLINE static double dfmal(long double x, long double y, long double z) { + return fputil::fma<double>(x, y, z); +} + +} // namespace math +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_DFMAL_H diff --git a/libc/src/__support/math/f16fma.h b/libc/src/__support/math/f16fma.h new file mode 100644 index 0000000..f7bb2fe --- /dev/null +++ b/libc/src/__support/math/f16fma.h @@ -0,0 +1,33 @@ +//===-- Implementation header for f16fma ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_F16FMA_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_F16FMA_H + +#include "include/llvm-libc-macros/float16-macros.h" + +#ifdef LIBC_TYPES_HAS_FLOAT16 + +#include "src/__support/FPUtil/FMA.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +LIBC_INLINE static float16 f16fma(double x, double y, double z) { + return fputil::fma<float16>(x, y, z); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_TYPES_HAS_FLOAT16 + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_F16FMA_H diff --git a/libc/src/__support/math/f16fmal.h b/libc/src/__support/math/f16fmal.h new file mode 100644 index 0000000..6e9c4b9 --- /dev/null +++ b/libc/src/__support/math/f16fmal.h @@ -0,0 +1,34 @@ +//===-- Implementation header for f16fmal -----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_F16FMAL_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_F16FMAL_H + +#include "include/llvm-libc-macros/float16-macros.h" + +#ifdef LIBC_TYPES_HAS_FLOAT16 + +#include "src/__support/FPUtil/FMA.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +LIBC_INLINE static float16 f16fmal(long double x, long double y, + long double z) { + return fputil::fma<float16>(x, y, z); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_TYPES_HAS_FLOAT16 + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_F16FMAL_H diff --git a/libc/src/__support/math/f16sqrtl.h b/libc/src/__support/math/f16sqrtl.h new file mode 100644 index 0000000..86f0e59 --- /dev/null +++ b/libc/src/__support/math/f16sqrtl.h @@ -0,0 +1,33 @@ +//===-- Implementation header of f16sqrt function -------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_F16SQRTL_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_F16SQRTL_H + +#include "include/llvm-libc-macros/float16-macros.h" + +#ifdef LIBC_TYPES_HAS_FLOAT16 + +#include "src/__support/FPUtil/sqrt.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +LIBC_INLINE static constexpr float16 f16sqrtl(long double x) { + return fputil::sqrt<float16>(x); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_TYPES_HAS_FLOAT16 +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_F16SQRTL_H diff --git a/libc/src/__support/math/fsqrt.h b/libc/src/__support/math/fsqrt.h new file mode 100644 index 0000000..8dd6afc --- /dev/null +++ b/libc/src/__support/math/fsqrt.h @@ -0,0 +1,26 @@ +//===-- Implementation header for fsqrt ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_FSQRT_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_FSQRT_H + +#include "src/__support/FPUtil/generic/sqrt.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +LIBC_INLINE static constexpr float fsqrt(double x) { + return fputil::sqrt<float>(x); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_FSQRT_H diff --git a/libc/src/__support/math/fsqrtf128.h b/libc/src/__support/math/fsqrtf128.h new file mode 100644 index 0000000..8ca274ef --- /dev/null +++ b/libc/src/__support/math/fsqrtf128.h @@ -0,0 +1,33 @@ +//===-- Implementation header for fsqrtf128 ---------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_FSQRTF128_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_FSQRTF128_H + +#include "include/llvm-libc-types/float128.h" + +#ifdef LIBC_TYPES_HAS_FLOAT128 + +#include "src/__support/FPUtil/generic/sqrt.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +LIBC_INLINE static constexpr float fsqrtf128(float128 x) { + return fputil::sqrt<float>(x); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_TYPES_HAS_FLOAT128 +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_FSQRTF128_H diff --git a/libc/src/__support/math/fsqrtl.h b/libc/src/__support/math/fsqrtl.h new file mode 100644 index 0000000..3033f0a5 --- /dev/null +++ b/libc/src/__support/math/fsqrtl.h @@ -0,0 +1,26 @@ +//===-- Implementation header for fsqrtl ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_FSQRTL_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_FSQRTL_H + +#include "src/__support/FPUtil/generic/sqrt.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +LIBC_INLINE static constexpr float fsqrtl(long double x) { + return fputil::sqrt<float>(x); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_FSQRTL_H diff --git a/libc/src/__support/math/hypotf.h b/libc/src/__support/math/hypotf.h new file mode 100644 index 0000000..e712a07 --- /dev/null +++ b/libc/src/__support/math/hypotf.h @@ -0,0 +1,107 @@ +//===-- Implementation header for hypotf ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_HYPOTF_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_HYPOTF_H + +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/double_double.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/FPUtil/sqrt.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +LIBC_INLINE static float hypotf(float x, float y) { + using DoubleBits = fputil::FPBits<double>; + using FPBits = fputil::FPBits<float>; + + FPBits x_abs = FPBits(x).abs(); + FPBits y_abs = FPBits(y).abs(); + + bool x_abs_larger = x_abs.uintval() >= y_abs.uintval(); + + FPBits a_bits = x_abs_larger ? x_abs : y_abs; + FPBits b_bits = x_abs_larger ? y_abs : x_abs; + + uint32_t a_u = a_bits.uintval(); + uint32_t b_u = b_bits.uintval(); + + // Note: replacing `a_u >= FPBits::EXP_MASK` with `a_bits.is_inf_or_nan()` + // generates extra exponent bit masking instructions on x86-64. + if (LIBC_UNLIKELY(a_u >= FPBits::EXP_MASK)) { + // x or y is inf or nan + if (a_bits.is_signaling_nan() || b_bits.is_signaling_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + if (a_bits.is_inf() || b_bits.is_inf()) + return FPBits::inf().get_val(); + return a_bits.get_val(); + } + + if (LIBC_UNLIKELY(a_u - b_u >= + static_cast<uint32_t>((FPBits::FRACTION_LEN + 2) + << FPBits::FRACTION_LEN))) + return x_abs.get_val() + y_abs.get_val(); + + double ad = static_cast<double>(a_bits.get_val()); + double bd = static_cast<double>(b_bits.get_val()); + + // These squares are exact. + double a_sq = ad * ad; +#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE + double sum_sq = fputil::multiply_add(bd, bd, a_sq); +#else + double b_sq = bd * bd; + double sum_sq = a_sq + b_sq; +#endif + + // Take sqrt in double precision. + DoubleBits result(fputil::sqrt<double>(sum_sq)); + uint64_t r_u = result.uintval(); + + // If any of the sticky bits of the result are non-zero, except the LSB, then + // the rounded result is correct. + if (LIBC_UNLIKELY(((r_u + 1) & 0x0000'0000'0FFF'FFFE) == 0)) { + double r_d = result.get_val(); + + // Perform rounding correction. +#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE + double sum_sq_lo = fputil::multiply_add(bd, bd, a_sq - sum_sq); + double err = sum_sq_lo - fputil::multiply_add(r_d, r_d, -sum_sq); +#else + fputil::DoubleDouble r_sq = fputil::exact_mult(r_d, r_d); + double sum_sq_lo = b_sq - (sum_sq - a_sq); + double err = (sum_sq - r_sq.hi) + (sum_sq_lo - r_sq.lo); +#endif + + if (err > 0) { + r_u |= 1; + } else if ((err < 0) && (r_u & 1) == 0) { + r_u -= 1; + } else if ((r_u & 0x0000'0000'1FFF'FFFF) == 0) { + // The rounded result is exact. + fputil::clear_except_if_required(FE_INEXACT); + } + return static_cast<float>(DoubleBits(r_u).get_val()); + } + + return static_cast<float>(result.get_val()); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_HYPOTF_H diff --git a/libc/src/__support/math/ilogb.h b/libc/src/__support/math/ilogb.h new file mode 100644 index 0000000..0215314 --- /dev/null +++ b/libc/src/__support/math/ilogb.h @@ -0,0 +1,27 @@ +//===-- Implementation header for ilogb -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_ILOGB_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_ILOGB_H + +#include "src/__support/FPUtil/ManipulationFunctions.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +LIBC_INLINE static constexpr int ilogb(double x) { + return fputil::intlogb<int>(x); +} +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_ILOGB_H diff --git a/libc/src/__support/math/ilogbf.h b/libc/src/__support/math/ilogbf.h new file mode 100644 index 0000000..dfc8f62 --- /dev/null +++ b/libc/src/__support/math/ilogbf.h @@ -0,0 +1,26 @@ +//===-- Implementation header for ilogbf ----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_ILOGBF_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_ILOGBF_H + +#include "src/__support/FPUtil/ManipulationFunctions.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +LIBC_INLINE constexpr int ilogbf(float x) { return fputil::intlogb<int>(x); } + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_ILOGBF_H diff --git a/libc/src/__support/math/ilogbf128.h b/libc/src/__support/math/ilogbf128.h new file mode 100644 index 0000000..47c3643 --- /dev/null +++ b/libc/src/__support/math/ilogbf128.h @@ -0,0 +1,34 @@ +//===-- Implementation header for ilogbf128 --------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_ILOGBF128_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_ILOGBF128_H + +#include "include/llvm-libc-types/float128.h" + +#ifdef LIBC_TYPES_HAS_FLOAT128 + +#include "src/__support/FPUtil/ManipulationFunctions.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +LIBC_INLINE static constexpr int ilogbf128(float128 x) { + return fputil::intlogb<int>(x); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_TYPES_HAS_FLOAT128 + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_ILOGBF128_H diff --git a/libc/src/__support/math/ilogbl.h b/libc/src/__support/math/ilogbl.h new file mode 100644 index 0000000..1d6a8b5 --- /dev/null +++ b/libc/src/__support/math/ilogbl.h @@ -0,0 +1,28 @@ +//===-- Implementation header for ilogbl ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_ILOGBL_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_ILOGBL_H + +#include "src/__support/FPUtil/ManipulationFunctions.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +LIBC_INLINE static constexpr int ilogbl(long double x) { + return fputil::intlogb<int>(x); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_ILOGBL_H diff --git a/libc/src/__support/math/llogb.h b/libc/src/__support/math/llogb.h new file mode 100644 index 0000000..0c6acf0 --- /dev/null +++ b/libc/src/__support/math/llogb.h @@ -0,0 +1,27 @@ +//===-- Implementation header for llogb -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_LLOGB_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_LLOGB_H + +#include "src/__support/FPUtil/ManipulationFunctions.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace math { + +LIBC_INLINE static constexpr long llogb(double x) { + return fputil::intlogb<long>(x); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_LLOGB_H diff --git a/libc/src/__support/math/llogbf.h b/libc/src/__support/math/llogbf.h new file mode 100644 index 0000000..1dcdcd0 --- /dev/null +++ b/libc/src/__support/math/llogbf.h @@ -0,0 +1,28 @@ +//===-- Implementation header for llogbf ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_LLOGBF_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_LLOGBF_H + +#include "src/__support/FPUtil/ManipulationFunctions.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +LIBC_INLINE static constexpr long llogbf(float x) { + return fputil::intlogb<long>(x); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_LLOGBF_H diff --git a/libc/src/__support/math/llogbf128.h b/libc/src/__support/math/llogbf128.h new file mode 100644 index 0000000..5168647 --- /dev/null +++ b/libc/src/__support/math/llogbf128.h @@ -0,0 +1,34 @@ +//===-- Implementation header for llogbf128 ---------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_LLOGBF128_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_LLOGBF128_H + +#include "include/llvm-libc-types/float128.h" + +#ifdef LIBC_TYPES_HAS_FLOAT128 + +#include "src/__support/FPUtil/ManipulationFunctions.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +LIBC_INLINE static constexpr long llogbf128(float128 x) { + return fputil::intlogb<long>(x); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_TYPES_HAS_FLOAT128 + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_LLOGBF128_H diff --git a/libc/src/__support/math/llogbf16.h b/libc/src/__support/math/llogbf16.h new file mode 100644 index 0000000..55ddd3b9 --- /dev/null +++ b/libc/src/__support/math/llogbf16.h @@ -0,0 +1,34 @@ +//===-- Implementation header for llogbf16 ----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_LLOGBF16_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_LLOGBF16_H + +#include "include/llvm-libc-macros/float16-macros.h" + +#ifdef LIBC_TYPES_HAS_FLOAT16 + +#include "src/__support/FPUtil/ManipulationFunctions.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +LIBC_INLINE static constexpr long llogbf16(float16 x) { + return fputil::intlogb<long>(x); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_TYPES_HAS_FLOAT16 + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_LLOGBF16_H diff --git a/libc/src/__support/math/log10.h b/libc/src/__support/math/log10.h new file mode 100644 index 0000000..8861c89 --- /dev/null +++ b/libc/src/__support/math/log10.h @@ -0,0 +1,919 @@ +//===-- Double-precision log10(x) function --------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_LOG10_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_LOG10_H + +#include "common_constants.h" +#include "log_range_reduction.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/PolyEval.h" +#include "src/__support/FPUtil/double_double.h" +#include "src/__support/FPUtil/dyadic_float.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/common.h" +#include "src/__support/integer_literals.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY + +namespace LIBC_NAMESPACE_DECL { + +namespace math { +namespace log10_internal { +// 128-bit precision dyadic floating point numbers. +using Float128 = typename fputil::DyadicFloat<128>; + +using LIBC_NAMESPACE::operator""_u128; + +using namespace common_constants_internal; +using namespace math::log_range_reduction_internal; + +LIBC_INLINE_VAR constexpr fputil::DoubleDouble LOG10_E = {0x1.95355baaafad3p-57, + 0x1.bcb7b1526e50ep-2}; + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS +// A simple upper bound for the error of e_x * log(2) - log(r). +LIBC_INLINE_VAR constexpr double HI_ERR = 0x1.0p-85; + +// Extra errors from P is from using x^2 to reduce evaluation latency. +LIBC_INLINE_VAR constexpr double P_ERR = 0x1.0p-51; + +// log10(2) with 128-bit precision generated by SageMath with: +// def format_hex(value): +// l = hex(value)[2:] +// n = 8 +// x = [l[i:i + n] for i in range(0, len(l), n)] +// return "0x" + "'".join(x) + "_u128" +// (s, m, e) = RealField(128)(2).log10().sign_exponent_mantissa(); +// print(format_hex(m)); +LIBC_INLINE_VAR constexpr Float128 + LOG10_2(Sign::POS, + /*exponent=*/-129, /*mantissa=*/ + 0x9a209a84'fbcff798'8f8959ac'0b7c9178_u128); + +alignas(16) LIBC_INLINE_VAR constexpr LogRR LOG10_TABLE = { + // -log10(r) with 128-bit precision generated by SageMath with: + // + // for i in range(128): + // r = 2^-8 * ceil( 2^8 * (1 - 2^(-8)) / (1 + i*2^(-7)) ); + // s, m, e = RealField(128)(r).log10().sign_mantissa_exponent(); + // print("{Sign::POS,", e, ", format_hex(m), "},"); + /* .step_1 = */ { + {Sign::POS, 0, 0_u128}, + {Sign::POS, -136, 0xdf3b5ebb'da7e186b'65af394f'e05eafd3_u128}, + {Sign::POS, -135, 0xe01d4057'2f029c16'a8fb8d87'b30163b5_u128}, + {Sign::POS, -134, 0xa8c1263a'c3f57eb3'6bb0170e'5bb5d630_u128}, + {Sign::POS, -134, 0xe1e841bb'c26204e5'fc2ea6eb'0ea1370e_u128}, + {Sign::POS, -133, 0x8dc2eb02'274d6ff4'dc8a199a'4bb63382_u128}, + {Sign::POS, -133, 0xaacde920'361dd054'86b57ea6'10c7db33_u128}, + {Sign::POS, -133, 0xc81618eb'15421bab'5f034a40'e6a2f09d_u128}, + {Sign::POS, -133, 0xe59c7e66'c5fedb4b'594a31b2'c5cc891c_u128}, + {Sign::POS, -133, 0xf477584f'97b654de'221efda5'8221904b_u128}, + {Sign::POS, -132, 0x892e8219'75106e09'68a0dc47'567691c9_u128}, + {Sign::POS, -132, 0x9841c66e'17dfe7da'10bc94f4'4d216b49_u128}, + {Sign::POS, -132, 0x9fd7be33'18306cc5'e303ea7e'23c9d6fb_u128}, + {Sign::POS, -132, 0xaf1cb35b'f494a8dd'ce697dba'a00d4c7d_u128}, + {Sign::POS, -132, 0xbe8380a2'fa7eba5a'9c216079'dcf0ea96_u128}, + {Sign::POS, -132, 0xc643c775'8283a271'75278940'eecfc3a9_u128}, + {Sign::POS, -132, 0xd5de75ec'27e4fe68'2d3467d2'53e2d1fc_u128}, + {Sign::POS, -132, 0xddb904e8'f1272a95'ead4055d'cdec7b22_u128}, + {Sign::POS, -132, 0xed88f6bb'355fa196'e1e0dda0'b3d375a4_u128}, + {Sign::POS, -132, 0xf57e8281'ade9d92d'38dc40c4'fe11e608_u128}, + {Sign::POS, -131, 0x82c2941b'b20bbe1f'3bcdcfe7'b23976cd_u128}, + {Sign::POS, -131, 0x86cb3663'2807cdcd'456350b0'bda452a6_u128}, + {Sign::POS, -131, 0x8eeaa306'458b760a'78185dcc'37fda01a_u128}, + {Sign::POS, -131, 0x93018395'12fc1168'307643ad'bbbde1b3_u128}, + {Sign::POS, -131, 0x9b3dd1d5'50c41443'6c449d40'9f883fe3_u128}, + {Sign::POS, -131, 0x9f6356aa'03c34389'8ea7b30c'8b4ad886_u128}, + {Sign::POS, -131, 0xa7bd56cd'de5d76a2'961c6e69'0d8879b4_u128}, + {Sign::POS, -131, 0xabf1ea3e'1d7bd7cf'042643ce'd81ec14a_u128}, + {Sign::POS, -131, 0xb02b9af7'4c2f879e'4742fb3d'0b5cdd19_u128}, + {Sign::POS, -131, 0xb8ae8671'b3d7dd6c'f7e2ab36'f09e9014_u128}, + {Sign::POS, -131, 0xbcf7dabd'87c01afc'8d3fc634'85e7ff13_u128}, + {Sign::POS, -131, 0xc1467f69'4d10a581'f3edc493'75fbc5a5_u128}, + {Sign::POS, -131, 0xc9f3ef07'e1f3fc5e'5fcd7d0c'e937375f_u128}, + {Sign::POS, -131, 0xce52d50b'94fa253a'58252dad'a9f06111_u128}, + {Sign::POS, -131, 0xd2b74192'fae43777'62f01e5f'f43708ab_u128}, + {Sign::POS, -131, 0xd72142a8'4ca85abd'481d9b31'31f52639_u128}, + {Sign::POS, -131, 0xdb90e68b'8abf14af'b305ced1'419fe924_u128}, + {Sign::POS, -131, 0xe48150cf'32888b9c'849266a8'5513dc6d_u128}, + {Sign::POS, -131, 0xe90234c6'5a15e533'080ecf32'66b4dcf4_u128}, + {Sign::POS, -131, 0xed88f6bb'355fa196'e1e0dda0'b3d375a4_u128}, + {Sign::POS, -131, 0xf215a60b'6557943f'ce3537a3'a211b25b_u128}, + {Sign::POS, -131, 0xf6a85251'3757dfbd'5dab6830'7fedefcd_u128}, + {Sign::POS, -131, 0xffdfe15d'e3c01bac'1be2585c'279c50a5_u128}, + {Sign::POS, -130, 0x8242724a'155219f3'18aa3021'71017dcb_u128}, + {Sign::POS, -130, 0x849812d0'ccbb5cbd'abc7e698'502d43c0_u128}, + {Sign::POS, -130, 0x86f0dab1'ab5822b6'c339089a'51663370_u128}, + {Sign::POS, -130, 0x894cd27d'9f182c63'26f70b34'ce5cf201_u128}, + {Sign::POS, -130, 0x8bac02e8'ac3e09ac'676f20a8'7ab433df_u128}, + {Sign::POS, -130, 0x8e0e74ca'ae062e24'6db4169c'c4b83bc3_u128}, + {Sign::POS, -130, 0x90743120'1c7f651a'cd3fdb2f'ad0d1fd6_u128}, + {Sign::POS, -130, 0x92dd410a'd7bfe103'49d03e16'3250d1d4_u128}, + {Sign::POS, -130, 0x9549add2'f8a3c7e0'9ec7dc02'd5e723b9_u128}, + {Sign::POS, -130, 0x97b980e7'a743d71c'34698d03'a5442573_u128}, + {Sign::POS, -130, 0x9a2cc3df'f7548556'0522904d'1e47f3de_u128}, + {Sign::POS, -130, 0x9ca3807b'ca9fe93f'791a7264'6c87b976_u128}, + {Sign::POS, -130, 0x9f1dc0a4'b9cea286'3826f190'd655d736_u128}, + {Sign::POS, -130, 0xa19b8e6f'03b60e45'544ab3e4'8199b299_u128}, + {Sign::POS, -130, 0xa41cf41a'83643487'be775fa8'2961114e_u128}, + {Sign::POS, -130, 0xa6a1fc13'ad241953'45798e50'19e6c082_u128}, + {Sign::POS, -130, 0xa92ab0f4'92b772bd'91fb1ed0'cdc4d1fb_u128}, + {Sign::POS, -130, 0xabb71d85'ef05380d'818b8b9c'bbd17b72_u128}, + {Sign::POS, -130, 0xae474cc0'397f0d4f'a50c2fea'60c5b3b2_u128}, + {Sign::POS, -130, 0xb0db49cc'c1823c8e'58ea3498'0ad8b720_u128}, + {Sign::POS, -130, 0xb3732006'd1fbbba5'4b5f7194'1be508a4_u128}, + {Sign::POS, -130, 0xb60edafc'dd99ad1d'9e405fb8'bcb1ff1e_u128}, + {Sign::POS, -130, 0xb60edafc'dd99ad1d'9e405fb8'bcb1ff1e_u128}, + {Sign::POS, -130, 0xb8ae8671'b3d7dd6c'f7e2ab36'f09e9014_u128}, + {Sign::POS, -130, 0xbb522e5d'bf37f63b'c6696396'40c305bb_u128}, + {Sign::POS, -130, 0xbdf9def0'4cf980ff'a3dc9e46'4e98764b_u128}, + {Sign::POS, -130, 0xc0a5a490'dea95b5e'ffd3256b'59fa9c59_u128}, + {Sign::POS, -130, 0xc3558be0'85e3f4bc'b0a2d486'72a051a5_u128}, + {Sign::POS, -130, 0xc3558be0'85e3f4bc'b0a2d486'72a051a5_u128}, + {Sign::POS, -130, 0xc609a1bb'4aa98f59'acb2ca5d'4ca1c10e_u128}, + {Sign::POS, -130, 0xc8c1f339'9ca7d33b'43690b9e'3cde0d02_u128}, + {Sign::POS, -130, 0xcb7e8db1'cfe04827'18b1fd60'383f7e5a_u128}, + {Sign::POS, -130, 0xce3f7eb9'a517c969'0248757e'5f45af3d_u128}, + {Sign::POS, -130, 0xd104d427'de7fbcc4'7c4acd60'5be48bc1_u128}, + {Sign::POS, -130, 0xd104d427'de7fbcc4'7c4acd60'5be48bc1_u128}, + {Sign::POS, -130, 0xd3ce9c15'e10ec927'58ff6362'9a92652d_u128}, + {Sign::POS, -130, 0xd69ce4e1'6303fcdd'6b49be3b'd8c89f10_u128}, + {Sign::POS, -130, 0xd96fbd2e'2814c9cc'e6dd603a'881e9060_u128}, + {Sign::POS, -130, 0xd96fbd2e'2814c9cc'e6dd603a'881e9060_u128}, + {Sign::POS, -130, 0xdc4733e7'cbcbfc8c'89e281c9'8c1d705c_u128}, + {Sign::POS, -130, 0xdf235843'9aa5dd12'dc0db7cf'0cce9f32_u128}, + {Sign::POS, -130, 0xe20439c2'7a7c01b8'fdf1c5b8'46db9deb_u128}, + {Sign::POS, -130, 0xe20439c2'7a7c01b8'fdf1c5b8'46db9deb_u128}, + {Sign::POS, -130, 0xe4e9e832'e2da0c05'3dd7eab4'8869c402_u128}, + {Sign::POS, -130, 0xe7d473b2'e5db8f2a'4e8fcc90'0b41daef_u128}, + {Sign::POS, -130, 0xe7d473b2'e5db8f2a'4e8fcc90'0b41daef_u128}, + {Sign::POS, -130, 0xeac3ecb2'4a3ac7b4'7593e1a9'e917359a_u128}, + {Sign::POS, -130, 0xedb863f4'b73f982d'e7741396'b49e1ce5_u128}, + {Sign::POS, -130, 0xedb863f4'b73f982d'e7741396'b49e1ce5_u128}, + {Sign::POS, -130, 0xf0b1ea93'f34675a7'c8ba4f8f'47b85a5c_u128}, + {Sign::POS, -130, 0xf3b09202'359f9787'7007c127'6821b705_u128}, + {Sign::POS, -130, 0xf3b09202'359f9787'7007c127'6821b705_u128}, + {Sign::POS, -130, 0xf6b46c0c'8c8fdea1'7ee19afe'6db7e324_u128}, + {Sign::POS, -130, 0xf9bd8add'584687f0'edf54f37'f6d40420_u128}, + {Sign::POS, -130, 0xf9bd8add'584687f0'edf54f37'f6d40420_u128}, + {Sign::POS, -130, 0xfccc00fe'dba4e6fb'efe52ccf'03e7dee1_u128}, + {Sign::POS, -130, 0xffdfe15d'e3c01bac'1be2585c'279c50a5_u128}, + {Sign::POS, -130, 0xffdfe15d'e3c01bac'1be2585c'279c50a5_u128}, + {Sign::POS, -129, 0x817c9fa6'43880404'e0b571f5'c91b0446_u128}, + {Sign::POS, -129, 0x830c1742'7ea55eca'7178594b'ef2def59_u128}, + {Sign::POS, -129, 0x830c1742'7ea55eca'7178594b'ef2def59_u128}, + {Sign::POS, -129, 0x849e6196'487c1d1c'9a741bb1'71158d2a_u128}, + {Sign::POS, -129, 0x849e6196'487c1d1c'9a741bb1'71158d2a_u128}, + {Sign::POS, -129, 0x863388eb'55ebd295'1a618264'446cb495_u128}, + {Sign::POS, -129, 0x87cb97c3'ff9eac18'71dbdbbe'c51d7657_u128}, + {Sign::POS, -129, 0x87cb97c3'ff9eac18'71dbdbbe'c51d7657_u128}, + {Sign::POS, -129, 0x896698dc'e4cff76c'abe0b522'230f7d14_u128}, + {Sign::POS, -129, 0x896698dc'e4cff76c'abe0b522'230f7d14_u128}, + {Sign::POS, -129, 0x8b04972e'9d4d3011'd28e8ada'fea703b4_u128}, + {Sign::POS, -129, 0x8ca59def'7b5cefc5'208422d8'3be34b27_u128}, + {Sign::POS, -129, 0x8ca59def'7b5cefc5'208422d8'3be34b27_u128}, + {Sign::POS, -129, 0x8e49b895'5e3ffb8a'c385cf49'402af0e4_u128}, + {Sign::POS, -129, 0x8e49b895'5e3ffb8a'c385cf49'402af0e4_u128}, + {Sign::POS, -129, 0x8ff0f2d7'960a075c'da982a61'4e12c6dd_u128}, + {Sign::POS, -129, 0x8ff0f2d7'960a075c'da982a61'4e12c6dd_u128}, + {Sign::POS, -129, 0x919b58b0'd999bbc8'038401fc'1c1b5c2c_u128}, + {Sign::POS, -129, 0x919b58b0'd999bbc8'038401fc'1c1b5c2c_u128}, + {Sign::POS, -129, 0x9348f661'4f821394'a9b55d3f'16da746a_u128}, + {Sign::POS, -129, 0x9348f661'4f821394'a9b55d3f'16da746a_u128}, + {Sign::POS, -129, 0x94f9d870'aac256a5'088d2d14'73d4f7f5_u128}, + {Sign::POS, -129, 0x94f9d870'aac256a5'088d2d14'73d4f7f5_u128}, + {Sign::POS, -129, 0x96ae0bb0'5c35d5bd'7c1e117d'ea19e9e6_u128}, + {Sign::POS, -129, 0x96ae0bb0'5c35d5bd'7c1e117d'ea19e9e6_u128}, + {Sign::POS, -129, 0x98659d3d'd9b12532'336db063'0f536fb9_u128}, + {Sign::POS, 0, 0_u128}, + }, + // -log10(r) for the second step, generated by SageMath with: + // + // for i in range(-2^6, 2^7 + 1): + // r = 2^-16 * round( 2^16 / (1 + i*2^(-14)) ); + // s, m, e = RealField(128)(r).log10().sign_mantissa_exponent(); + // print("{Sign::POS," if s == -1 else "{Sign::NEG,", e, ", + // format_hex(m), "},"); + /* .step_2 = */ + { + {Sign::NEG, -137, 0xdeca7290'13cd7c31'7f1ce002'fa34131b_u128}, + {Sign::NEG, -137, 0xdb5475b4'4946d986'639afa08'5dd8b4c7_u128}, + {Sign::NEG, -137, 0xd7de6b0e'10cab7d2'05512632'fe9a58cb_u128}, + {Sign::NEG, -137, 0xd468529c'fc6fb395'b5380a99'53117d07_u128}, + {Sign::NEG, -137, 0xd0f22c60'9e474741'70af2d7d'53be1f31_u128}, + {Sign::NEG, -137, 0xcd7bf858'885dcae2'0ccd499c'49b74cc2_u128}, + {Sign::NEG, -137, 0xca05b684'4cba73cf'5b51ddc3'987ebfb8_u128}, + {Sign::NEG, -137, 0xc68f66e3'7d5f545a'49375f51'89b3782b_u128}, + {Sign::NEG, -137, 0xc3190975'ac495b7a'f6e57738'865c712f_u128}, + {Sign::NEG, -137, 0xbfa29e3a'6b70547e'ca02b10a'8c712acd_u128}, + {Sign::NEG, -137, 0xbc2c2531'4cc6e6b6'78e50382'10208151_u128}, + {Sign::NEG, -137, 0xb8b59e59'e23a9524'0fa099ec'd71ee0ea_u128}, + {Sign::NEG, -137, 0xb53f09b3'bdb3be28'eeb445cc'b8fb09ed_u128}, + {Sign::NEG, -137, 0xb1c8673e'71159b33'c352fff1'8a1c02fb_u128}, + {Sign::NEG, -137, 0xae51b6f9'8e3e406e'7949e03e'cf9b390b_u128}, + {Sign::NEG, -137, 0xaadaf8e4'a7069c6c'2681f33f'30aadedc_u128}, + {Sign::NEG, -137, 0xa7642cff'4d4277d6'f01d5496'eea213b3_u128}, + {Sign::NEG, -137, 0xa3ed5349'12c0751d'e92ef555'ff1de975_u128}, + {Sign::NEG, -137, 0xa0766bc1'894a1022'eb0c7519'b3e7c1e0_u128}, + {Sign::NEG, -137, 0x9c21b6e9'1e7f03a3'f60d204f'f0fe5296_u128}, + {Sign::NEG, -137, 0x98aab049'1050bea8'125c19a4'f057c18b_u128}, + {Sign::NEG, -137, 0x95339bd6'4cd953e7'7e9383ce'1bdf9575_u128}, + {Sign::NEG, -137, 0x91bc7990'65cc57d6'bf274f4d'8f770253_u128}, + {Sign::NEG, -137, 0x8e454976'ecd836ad'656bd9b7'58fe44ba_u128}, + {Sign::NEG, -137, 0x8ace0b89'73a63413'bfdd2c7f'388fc014_u128}, + {Sign::NEG, -137, 0x8756bfc7'8bda6ad0'83fbf6ed'936c493a_u128}, + {Sign::NEG, -137, 0x83df6630'c713cc76'71bfa9a1'8bec01cc_u128}, + {Sign::NEG, -137, 0x8067fec4'b6ec2111'f09d19f5'6dbfef72_u128}, + {Sign::NEG, -138, 0xf9e11305'd9f00dad'4c422713'b1642228_u128}, + {Sign::NEG, -138, 0xf2f20cd5'f58de39a'0c3c7c56'99b7a0a4_u128}, + {Sign::NEG, -138, 0xec02eaf8'e3c656ff'b8db7c69'e3fa0797_u128}, + {Sign::NEG, -138, 0xe513ad6d'c7a3a553'a083eb05'506ff7ed_u128}, + {Sign::NEG, -138, 0xde245433'c425b5c5'c21595e7'45f1fa15_u128}, + {Sign::NEG, -138, 0xd734df49'fc42189b'b9d5bcdb'fe719389_u128}, + {Sign::NEG, -138, 0xd0454eaf'92e4068b'a17a1e85'e93461f4_u128}, + {Sign::NEG, -138, 0xc955a263'aaec6016'e3537584'da333fda_u128}, + {Sign::NEG, -138, 0xc265da65'6731ace5'00963177'f24682c2_u128}, + {Sign::NEG, -138, 0xbb75f6b3'ea801b1e'4ac03734'7bcfc50e_u128}, + {Sign::NEG, -138, 0xb485f74e'57997ec6'901a736a'4364cdfd_u128}, + {Sign::NEG, -138, 0xad95dc33'd1355117'bb550acc'3b9d7247_u128}, + {Sign::NEG, -138, 0xa6a5a563'7a00afdc'663cf2b2'7e8f1ffb_u128}, + {Sign::NEG, -138, 0x9fb552dc'749e5cca'5f89bd08'feb39952_u128}, + {Sign::NEG, -138, 0x98c4e49d'e3a6bcdd'23c2623c'73f494db_u128}, + {Sign::NEG, -138, 0x91d45aa6'e9a7d7b0'4937d3b5'485af61e_u128}, + {Sign::NEG, -138, 0x8ae3b4f6'a92556d9'df14214e'7a6d8111_u128}, + {Sign::NEG, -138, 0x83f2f38c'44988544'bf7cfc14'999fb4bc_u128}, + {Sign::NEG, -139, 0xfa042ccd'bce09d15'a990c0ee'569a8d51_u128}, + {Sign::NEG, -139, 0xec223b0b'32227c9e'a38463e9'd941e1c2_u128}, + {Sign::NEG, -139, 0xde4011cf'2daaff31'ba032453'0edaa03f_u128}, + {Sign::NEG, -139, 0xd05db117'f419b857'5e997a02'dad7ace7_u128}, + {Sign::NEG, -139, 0xc27b18e3'c9f977c7'4a14676d'4d0f817e_u128}, + {Sign::NEG, -139, 0xb4984930'f3c0481c'857c002e'e7a1e473_u128}, + {Sign::NEG, -139, 0xa6b541fd'b5cf6d89'5923b2eb'72d8012a_u128}, + {Sign::NEG, -139, 0x98d20348'5473648b'21cde8f8'5ca1f9fd_u128}, + {Sign::NEG, -139, 0x8aee8d0f'13e3e09e'0be08e08'b1d212d4_u128}, + {Sign::NEG, -140, 0xfa15bea0'708795e1'69502399'8e6bd7b0_u128}, + {Sign::NEG, -140, 0xde4df414'0b42822f'634cea67'50617a92_u128}, + {Sign::NEG, -140, 0xc285ba75'7feb2781'fbd7e970'aef9dbb8_u128}, + {Sign::NEG, -140, 0xa6bd11c1'564a8ace'9aedc1c1'ba7d0695_u128}, + {Sign::NEG, -140, 0x8af3f9f4'1600120a'8d306ba2'07233c44_u128}, + {Sign::NEG, -141, 0xde54e614'8d030322'856a0a3a'00fcf3c1_u128}, + {Sign::NEG, -141, 0xa6c0fa00'de35f314'b3a2c140'7cf6d38d_u128}, + {Sign::NEG, -142, 0xde585f4c'5bbbcd3d'd791cf6a'70c3a504_u128}, + {Sign::NEG, -143, 0xde5a1bf6'27b1f68f'10a633f2'c4a8ea22_u128}, + {Sign::NEG, 0, 0_u128}, + {Sign::POS, -143, 0xde5d9565'8a729eab'ed4a68e5'e6e83ddf_u128}, + {Sign::POS, -142, 0xde5f522b'21e3e25a'3281f187'2cdbee94_u128}, + {Sign::POS, -141, 0xa6c8cb3b'7e5bbbfd'f1466eda'a96e356e_u128}, + {Sign::POS, -141, 0xde62cbd2'1e895473'8a607fd6'95dfc3d9_u128}, + {Sign::POS, -140, 0x8afed570'32bebc7c'c36b8713'ceefe2de_u128}, + {Sign::POS, -140, 0xa6ccb436'a3c72fa4'5c2e76c9'53e3e3e6_u128}, + {Sign::POS, -140, 0xc29b023f'dcb2dccf'8e4950fa'5c943bbf_u128}, + {Sign::POS, -140, 0xde69bf8f'58005dfc'20fa8a73'c585f634_u128}, + {Sign::POS, -140, 0xfa38ec28'905810a3'0aa106d9'b0a9717a_u128}, + {Sign::POS, -139, 0x8b044407'80460c2a'85d70e03'2de41aec_u128}, + {Sign::POS, -139, 0x98ec49a3'11cc30ab'beee21cb'b82a9a78_u128}, + {Sign::POS, -139, 0xa6d486e8'ba5151a0'abd7b0fd'd8efe6f6_u128}, + {Sign::POS, -139, 0xb4bcfbda'377d31cc'3221c56e'2c1aa912_u128}, + {Sign::POS, -139, 0xc2a5a879'470c7c37'57b795a3'6d9c5f19_u128}, + {Sign::POS, -139, 0xd08e8cc7'a6d0c580'131ec142'c053ac3b_u128}, + {Sign::POS, -139, 0xde77a8c7'14b08d28'35e3298f'4bb2aa0a_u128}, + {Sign::POS, -139, 0xec60fc79'4ea73ee4'7133dafd'fc44f160_u128}, + {Sign::POS, -139, 0xfa4a87e0'12c533eb'74b37d23'121c59d5_u128}, + {Sign::POS, -138, 0x841a257e'8f97da22'93bf5f42'07da8a4c_u128}, + {Sign::POS, -138, 0x8b0f22e9'19107c0c'fdb5990e'c6057f4e_u128}, + {Sign::POS, -138, 0x92043c30'84f41481'2d408a58'b1b202fe_u128}, + {Sign::POS, -138, 0x98f97155'b274b1ab'1759381b'61dfbf01_u128}, + {Sign::POS, -138, 0x9feec259'80cedbbe'41e90a05'4df4b9f1_u128}, + {Sign::POS, -138, 0xa6e42f3c'cf49959d'a1e66c62'03725d50_u128}, + {Sign::POS, -138, 0xadd9b800'7d365d83'8693d36a'b45bd7ce_u128}, + {Sign::POS, -138, 0xb4cf5ca5'69f12da9'91e25bb4'0ad3f098_u128}, + {Sign::POS, -138, 0xbbc51d2c'74e07cf0'bdf94392'c4cc7f6c_u128}, + {Sign::POS, -138, 0xc2baf996'7d753f89'6fe37973'354a82f9_u128}, + {Sign::POS, -138, 0xc9b0f1e4'632ae79b'97647b42'67bfd801_u128}, + {Sign::POS, -138, 0xd0a70617'058765ee'dbf5c32a'454f7bdf_u128}, + {Sign::POS, -138, 0xd79d362f'441b2a92'd6edfe04'c37ba916_u128}, + {Sign::POS, -138, 0xde93822d'fe812587'5ad3480c'cfbe9890_u128}, + {Sign::POS, -138, 0xe589ea14'145ec764'c7d9ac76'5be7e325_u128}, + {Sign::POS, -138, 0xec806de2'65640204'6d8f24b9'a3ca011b_u128}, + {Sign::POS, -138, 0xf3770d99'd14b4928'f9b65480'7dcdd5b2_u128}, + {Sign::POS, -138, 0xfa6dc93b'37d99326'f4513f47'45663028_u128}, + {Sign::POS, -137, 0x80b25063'bc6f2cc6'a46e9a72'd80da75f_u128}, + {Sign::POS, -137, 0x842dca1f'ba19cce6'ee60992b'51ffac4b_u128}, + {Sign::POS, -137, 0x87a951d2'04deeaf3'1977fa1c'786886b3_u128}, + {Sign::POS, -137, 0x8b24e77b'0cb60a84'0e5f7c52'cdf119d5_u128}, + {Sign::POS, -137, 0x8ea08b1b'419bf221'3bf9d70d'a1021a10_u128}, + {Sign::POS, -137, 0x921c3cb3'1392ab94'fd0406b0'7523b8e6_u128}, + {Sign::POS, -137, 0x9597fc42'f2a18441'0453ee32'c020f2a8_u128}, + {Sign::POS, -137, 0x9913c9cb'4ed50d72'cfb3ec22'066bf7f6_u128}, + {Sign::POS, -137, 0x9c8fa54c'983f1cb8'215c025b'd493ecf9_u128}, + {Sign::POS, -137, 0x9f2c9319'2e68232b'39c116b7'ee3a83ec_u128}, + {Sign::POS, -137, 0xa2a8870f'24ac5f66'f41f4b3e'de2782f0_u128}, + {Sign::POS, -137, 0xa62488ff'3c735799'61196927'723eb75c_u128}, + {Sign::POS, -137, 0xa9a098e9'e5e2a432'0e615e83'6cb1edab_u128}, + {Sign::POS, -137, 0xad1cb6cf'91252372'6981331c'5fc71cfc_u128}, + {Sign::POS, -137, 0xb098e2b0'ae6af9c2'5f6a4faa'054f11fa_u128}, + {Sign::POS, -137, 0xb4151c8d'ade99205'02a68bc6'81a74c28_u128}, + {Sign::POS, -137, 0xb7916466'ffdb9ded'382ba24d'90566403_u128}, + {Sign::POS, -137, 0xbb0dba3d'14811652'6ad1abe5'1dd22e00_u128}, + {Sign::POS, -137, 0xbe8a1e10'5c1f3b85'456d3f7f'59b13960_u128}, + {Sign::POS, -137, 0xc2068fe1'470095a4'738dd8b7'd66e9058_u128}, + {Sign::POS, -137, 0xc5830fb0'4574f4f1'68e123fe'd7ff11c6_u128}, + {Sign::POS, -137, 0xc8ff9d7d'c7d17225'2f3bd097'80c3aa11_u128}, + {Sign::POS, -137, 0xcc7c394a'3e706ec5'3b48887f'1ce36935_u128}, + {Sign::POS, -137, 0xcff8e316'19b19578'47ddae65'5ecc4633_u128}, + {Sign::POS, -137, 0xd3759ae1'c9f9da5b'37fa81ee'f4819c88_u128}, + {Sign::POS, -137, 0xd6f260ad'bfb37b55'ff6c4a8d'747c65ed_u128}, + {Sign::POS, -137, 0xda6f347a'6b4e0070'921c2949'3a33318c_u128}, + {Sign::POS, -137, 0xddec1648'3d3e3c27'da0631eb'65e731d8_u128}, + {Sign::POS, -137, 0xe1690617'a5fe4bc2'b3da6c07'd110babc_u128}, + {Sign::POS, -137, 0xe4e603e9'160d97a6'f2485c78'68b8835a_u128}, + {Sign::POS, -137, 0xe8630fbc'fdf0d3ae'67f5b7ed'01344055_u128}, + {Sign::POS, -137, 0xebe02993'ce31ff7b'f820df44'5b1d0622_u128}, + {Sign::POS, -137, 0xef5d516d'f76066d0'adefc674'b7eca5cd_u128}, + {Sign::POS, -137, 0xf2da874b'ea10a1e0'da6be6dc'057d3235_u128}, + {Sign::POS, -137, 0xf657cb2e'16dc95a9'392bdde1'52ab5ff5_u128}, + {Sign::POS, -137, 0xf9d51d14'ee637444'1bab58e2'ec99cf73_u128}, + {Sign::POS, -137, 0xfd527d00'e149bd3e'9b51ef7e'3388d692_u128}, + {Sign::POS, -136, 0x8067f579'301c9ef6'e914c6a7'f3f22fa2_u128}, + {Sign::POS, -136, 0x8226b374'edf088e2'0d22862e'b2081c94_u128}, + {Sign::POS, -136, 0x83e57873'e27ad153'29ebd0b4'76cd8fd8_u128}, + {Sign::POS, -136, 0x85a44476'461854a0'98feddc2'806d01ed_u128}, + {Sign::POS, -136, 0x8763177c'512896af'471bfc26'1a401854_u128}, + {Sign::POS, -136, 0x88b23a5b'61430a16'b6f89c19'b4cd1acd_u128}, + {Sign::POS, -136, 0x8a7119a8'5909ebe9'b39aaf34'163fb099_u128}, + {Sign::POS, -136, 0x8c2ffff9'9357e887'1665f0f8'21541c36_u128}, + {Sign::POS, -136, 0x8deeed4f'489679a6'a5051754'e049c1cb_u128}, + {Sign::POS, -136, 0x8fade1a9'b131c159'8c5a9a1c'57b2e986_u128}, + {Sign::POS, -136, 0x916cdd09'05988a35'1d844843'8a26a9ae_u128}, + {Sign::POS, -136, 0x932bdf6d'7e3c477d'8e3a0913'ecd2fd02_u128}, + {Sign::POS, -136, 0x94eae8d7'53911550'bc881a45'f47f1d36_u128}, + {Sign::POS, -136, 0x96a9f946'be0db8d0'f5e51c05'499b06d0_u128}, + {Sign::POS, -136, 0x986910bb'f62ba04f'c1a43be8'1a243fde_u128}, + {Sign::POS, -136, 0x9a282f37'3466e378'aec3cfeb'e971beb7_u128}, + {Sign::POS, -136, 0x9be754b8'b13e437c'2518b293'28614989_u128}, + {Sign::POS, -136, 0x9da68140'a5332b3a'39d6b147'cbe803a4_u128}, + {Sign::POS, -136, 0x9f65b4cf'48c9af6d'87765e30'04ae428d_u128}, + {Sign::POS, -136, 0xa124ef64'd4888ed6'08f896ab'28245bac_u128}, + {Sign::POS, -136, 0xa2e43101'80f93263'f8880fb5'ca630c87_u128}, + {Sign::POS, -136, 0xa4a379a5'86a7ad62'b179397c'f82e935c_u128}, + {Sign::POS, -136, 0xa662c951'1e22bda3'95a8cb71'7197ad81_u128}, + {Sign::POS, -136, 0xa8222004'7ffbcba8'f6394a34'b7f9a4a4_u128}, + {Sign::POS, -136, 0xa9e17dbf'e4c6ead0'ffafd8c2'b57884e8_u128}, + {Sign::POS, -136, 0xaba0e283'851ad980'a970a643'b8a6ac2b_u128}, + {Sign::POS, -136, 0xad604e4f'9991014e'a89b49fb'749d47e0_u128}, + {Sign::POS, -136, 0xaf1fc124'5ac5772e'66475ed2'ac983305_u128}, + {Sign::POS, -136, 0xb06f5be1'bf1918e7'b4fd6209'364bb36f_u128}, + {Sign::POS, -136, 0xb22edb06'36da31d6'8b5ce79b'0965962a_u128}, + {Sign::POS, -136, 0xb3ee6133'f7149769'6724232b'07396427_u128}, + {Sign::POS, -136, 0xb5adee6b'386e62ae'2f02b14d'cad8a49c_u128}, + {Sign::POS, -136, 0xb76d82ac'339058db'bd6443a8'1f792e07_u128}, + {Sign::POS, -136, 0xb92d1df7'2125eb7c'ea1cd962'5749939a_u128}, + {Sign::POS, -136, 0xbaecc04c'39dd389b'97775e31'42198913_u128}, + {Sign::POS, -136, 0xbcac69ab'b6670aeb'c2a701b8'09a2bc39_u128}, + {Sign::POS, -136, 0xbe6c1a15'cf76d9f6'979b990f'39e662e3_u128}, + {Sign::POS, -136, 0xc02bd18a'bdc2ca45'88395c46'3ddd82b2_u128}, + {Sign::POS, -136, 0xc1eb900a'ba03ad8d'66f451bd'9ba5ed05_u128}, + {Sign::POS, -136, 0xc3ab5595'fcf502d9'84cfb941'3f6437a6_u128}, + {Sign::POS, -136, 0xc56b222c'bf54f6b6'd2c1c8d3'2943ca42_u128}, + {Sign::POS, -136, 0xc72af5cf'39e4635f'067c0d1f'd95192e6_u128}, + {Sign::POS, -136, 0xc8ead07d'a566d0e3'c298bf9e'db6441f2_u128}, + {Sign::POS, -136, 0xcaaab238'3aa27559'c22d646a'ddde3910_u128}, + {Sign::POS, -136, 0xcc6a9aff'32603504'07c301e5'c7d1ca40_u128}, + {Sign::POS, -136, 0xce2a8ad2'c56ba27f'0fb44446'4df02505_u128}, + {Sign::POS, -136, 0xcfea81b3'2c92feec'05f1df35'91ae898f_u128}, + {Sign::POS, -136, 0xd13a7f7c'07506f7d'b43caf8e'7b891066_u128}, + {Sign::POS, -136, 0xd2fa82b3'6a610c4f'597fb13f'0d0fdf19_u128}, + {Sign::POS, -136, 0xd4ba8cf8'3dd2a06b'3c21f1c6'0a60b0d6_u128}, + {Sign::POS, -136, 0xd67a9e4a'ba7d7ce5'2b745590'9a0428a4_u128}, + {Sign::POS, -136, 0xd83ab6ab'193ca223'1438b605'73d2da10_u128}, + {Sign::POS, -136, 0xd9fad619'92edc008'49f86400'c5ab2b11_u128}, + {Sign::POS, -136, 0xdbbafc96'60713620'd3c313d1'48a23c35_u128}, + {Sign::POS, -136, 0xdd7b2a21'baaa13cc'bc568523'55e0f0d5_u128}, + }, + // -log10(r) for the third step, generated by SageMath with: + // + // for i in range(-80, 81): + // r = 2^-21 * round( 2^21 / (1 + i*2^(-21)) ); + // s, m, e = RealField(128)(r).log10().sign_mantissa_exponent(); + // print("{Sign::POS," if (s == -1) else "{Sign::NEG,", e, "," , + // format_hex(m), "},"); + /* .step_3 = */ + { + {Sign::NEG, -143, 0x8af8b9b3'22ba8c7d'54d7e498'98ca0093_u128}, + {Sign::NEG, -143, 0x893c0652'9deffc3d'c321bbf1'6665f29c_u128}, + {Sign::NEG, -143, 0x877f52e4'33ac7ec4'8246df71'40c3e4ae_u128}, + {Sign::NEG, -143, 0x85c29f67'e3ef35bc'1deaa9e8'5780e4c1_u128}, + {Sign::NEG, -143, 0x8405ebdd'aeb742cf'0cd8a512'1a9162d0_u128}, + {Sign::NEG, -143, 0x82493845'9403c7a7'b10486fa'4644308d_u128}, + {Sign::NEG, -143, 0x808c849f'93d3e5f0'578a2f61'eedd4be8_u128}, + {Sign::NEG, -144, 0xfd9fa1d7'5c4d7ea6'715b4a49'1790e8a7_u128}, + {Sign::NEG, -144, 0xfa263a53'c5f6eaf4'efb6273a'04c71573_u128}, + {Sign::NEG, -144, 0xf6acd2b4'64a25420'474d9015'60c17807_u128}, + {Sign::NEG, -144, 0xf3336af9'384dfd7c'6b9a5dec'eb80ec57_u128}, + {Sign::NEG, -144, 0xefba0322'40f82a5d'2665a32f'7cc64f79_u128}, + {Sign::NEG, -144, 0xec409b2f'7e9f1e16'17c8a673'16659363_u128}, + {Sign::NEG, -144, 0xe8c73320'f1411bfa'b62cdd3e'f5c8673d_u128}, + {Sign::NEG, -144, 0xe54dcaf6'98dc675e'4e4be6d5'a4a07422_u128}, + {Sign::NEG, -144, 0xe1d462b0'756f4394'032f86ff'08c92e22_u128}, + {Sign::NEG, -144, 0xde5afa4e'86f7f3ee'ce31a0d2'7359396f_u128}, + {Sign::NEG, -144, 0xdae191d0'cd74bbc1'7efc3180'aee36373_u128}, + {Sign::NEG, -144, 0xd7682937'48e3de5e'bb894b1e'0ce72fc4_u128}, + {Sign::NEG, -144, 0xd3eec081'f9439f19'00230f6c'7270f8be_u128}, + {Sign::NEG, -144, 0xd07557b0'de924142'9f63aaa5'63e9a399_u128}, + {Sign::NEG, -144, 0xccfbeec3'f8ce082d'c2354e44'1015e7eb_u128}, + {Sign::NEG, -144, 0xc98285bb'47f5372c'67d22bcf'5a452a4c_u128}, + {Sign::NEG, -144, 0xc6091c96'cc061190'65c46fa3'e3afea18_u128}, + {Sign::NEG, -144, 0xc28fb356'84fedaab'67e63bbe'1405c20d_u128}, + {Sign::NEG, -144, 0xbf1649fa'72ddd5ce'f061a284'212afbad_u128}, + {Sign::NEG, -144, 0xbb9ce082'95a1464c'57b0a190'1625b539_u128}, + {Sign::NEG, -144, 0xb82376ee'ed476f74'cc9d1c79'd93a9a1e_u128}, + {Sign::NEG, -144, 0xb4aa0d3f'79ce9499'5440d7a1'31392da8_u128}, + {Sign::NEG, -144, 0xb130a374'3b34f90a'ca0572f7'c9f7a7de_u128}, + {Sign::NEG, -144, 0xadb7398d'3178e019'dfa464cb'37fe6455_u128}, + {Sign::NEG, -144, 0xaa3dcf8a'5c988d17'1d26f48e'fb62e2e0_u128}, + {Sign::NEG, -144, 0xa6c4656b'bc924352'e0e635a6'81d259e2_u128}, + {Sign::NEG, -144, 0xa34afb31'5164461d'5f8b022f'27cbda35_u128}, + {Sign::NEG, -144, 0x9fd190db'1b0cd8c6'a40df5ca'390a0465_u128}, + {Sign::NEG, -144, 0x9c582669'198a3e9e'8fb76866'f01c4f2d_u128}, + {Sign::NEG, -144, 0x98debbdb'4cdabaf4'da1f690c'752fdeff_u128}, + {Sign::NEG, -144, 0x95655131'b4fc9119'112db8a3'dc07ee78_u128}, + {Sign::NEG, -144, 0x91ebe66c'51ee045a'9919c4c2'2125c79e_u128}, + {Sign::NEG, -144, 0x8e727b8b'23ad5808'ac6aa272'26204db3_u128}, + {Sign::NEG, -144, 0x8af9108e'2a38cf72'5bf708fe'ad2b1780_u128}, + {Sign::NEG, -144, 0x877fa575'658eade6'8ee54cbc'53cd19ed_u128}, + {Sign::NEG, -144, 0x84063a40'd5ad36b4'02ab59d3'8cc6e2c5_u128}, + {Sign::NEG, -144, 0x808ccef0'7a92ad29'4b0eaf0a'99286378_u128}, + {Sign::NEG, -145, 0xfa26c708'a87aa929'a448b11f'012c975c_u128}, + {Sign::NEG, -145, 0xf333eff8'c556e089'b0a1d584'117de73b_u128}, + {Sign::NEG, -145, 0xec4118b1'4bb6870e'e890f9fb'57fdabb6_u128}, + {Sign::NEG, -145, 0xe54e4132'3b962355'261d48c7'1e693130_u128}, + {Sign::NEG, -145, 0xde5b697b'94f23bf7'efecdd48'ed894c32_u128}, + {Sign::NEG, -145, 0xd768918d'57c75792'7944b995'7598a88a_u128}, + {Sign::NEG, -145, 0xd075b967'8411fcbf'a208bc08'75093645_u128}, + {Sign::NEG, -145, 0xc982e10a'19ceb219'f6bb94d8'9da8b432_u128}, + {Sign::NEG, -145, 0xc2900875'18f9fe3b'b07ebbab'782457b0_u128}, + {Sign::NEG, -145, 0xbb9d2fa8'819067be'b5126529'45eb9165_u128}, + {Sign::NEG, -145, 0xb4aa56a4'538e753c'96d57890'e171eea5_u128}, + {Sign::NEG, -145, 0xadb77d68'8ef0ad4e'94c5854b'9cd01726_u128}, + {Sign::NEG, -145, 0xa6c4a3f5'33b3968d'9a7eb881'1ec3e6bb_u128}, + {Sign::NEG, -145, 0x9fd1ca4a'41d3b792'403bd2ab'3e0fa2d7_u128}, + {Sign::NEG, -145, 0x98def067'b94d96f4'cad61d29'db384b6b_u128}, + {Sign::NEG, -145, 0x91ec164d'9a1dbb4d'2bc55fd6'b8a306ec_u128}, + {Sign::NEG, -145, 0x8af93bfb'e440ab33'011fd699'5111a927_u128}, + {Sign::NEG, -145, 0x84066172'97b2ed3d'959a26fa'ac7e5494_u128}, + {Sign::NEG, -146, 0xfa270d63'68e21007'c10eab72'66ac6bc0_u128}, + {Sign::NEG, -146, 0xec415772'74ef0439'0bb178b9'0026b2b2_u128}, + {Sign::NEG, -146, 0xde5ba112'5385c43b'ac3bfd92'5e6b33e1_u128}, + {Sign::NEG, -146, 0xd075ea43'049f5d3b'9d0a01a9'5b355319_u128}, + {Sign::NEG, -146, 0xc2903304'8834dc64'31b3b7b2'0a6a6496_u128}, + {Sign::NEG, -146, 0xb4aa7b56'de3f4ee0'170da891'504620f4_u128}, + {Sign::NEG, -146, 0xa6c4c33a'06b7c1d9'53289e84'744549cb_u128}, + {Sign::NEG, -146, 0x98df0aae'01974279'45519048'b0ce7e7f_u128}, + {Sign::NEG, -146, 0x8af951b2'ced6dde8'a6118c42'bf99407e_u128}, + {Sign::NEG, -147, 0xfa273090'dcdf429f'0e5b474c'c5a64cf6_u128}, + {Sign::NEG, -147, 0xde5bbcdd'c0b533aa'a74dab3b'd6067bc7_u128}, + {Sign::NEG, -147, 0xc290484c'4921a941'9f73f4e3'7357341b_u128}, + {Sign::NEG, -147, 0xa6c4d2dc'7616bdb0'31bf5d5f'815220e7_u128}, + {Sign::NEG, -147, 0x8af95c8e'47868b41'4b987ca5'fca242d7_u128}, + {Sign::NEG, -148, 0xde5bcac3'7ac6587d'19be3fab'd93832c5_u128}, + {Sign::NEG, -148, 0xa6c4daad'af3d75e0'8fd43f0c'9ce444d3_u128}, + {Sign::NEG, -149, 0xde5bd1b6'58ad4676'061cd853'e796bc2c_u128}, + {Sign::NEG, -150, 0xde5bd52f'c7d8545f'87d6afab'fba0644f_u128}, + {Sign::POS, 0, 0_u128}, + {Sign::POS, -150, 0xde5bdc22'a69d9e19'a9bf3200'1043629d_u128}, + {Sign::POS, -149, 0xde5bdf9c'1637d9ef'8014f0f3'60272d82_u128}, + {Sign::POS, -148, 0xa6c4ea50'24795bd2'fe94a02f'c639c0e3_u128}, + {Sign::POS, -148, 0xde5be68e'f5db7f99'bee710a5'ace7c8d4_u128}, + {Sign::POS, -147, 0x8af97245'3faf11e8'1a778d81'00437e4f_u128}, + {Sign::POS, -147, 0xa6c4f221'608e89fe'97d773f8'992f7051_u128}, + {Sign::POS, -147, 0xc29072db'dd9a0dd5'0c9ee584'1a3afa95_u128}, + {Sign::POS, -147, 0xde5bf474'b6df8331'7b644b13'993cf4ef_u128}, + {Sign::POS, -147, 0xfa2776eb'ec6ccfdb'3448f66e'2bd7a0ca_u128}, + {Sign::POS, -146, 0x8af97d20'bf27eccd'6a7ca5f1'a87a1a3c_u128}, + {Sign::POS, -146, 0x98df3f3a'b64b431d'245675fe'3061108f_u128}, + {Sign::POS, -146, 0xa6c501c3'dba75dc2'64136e97'019d0a3b_u128}, + {Sign::POS, -146, 0xb4aac4bc'2f432fa3'6cdadac4'd6925bd4_u128}, + {Sign::POS, -146, 0xc2908823'b125aba7'2899e237'91d29632_u128}, + {Sign::POS, -146, 0xd0764bfa'6155c4b5'28039e1f'0323a4c1_u128}, + {Sign::POS, -146, 0xde5c1040'3fda6db5'a2912e03'afc8cc28_u128}, + {Sign::POS, -146, 0xec41d4f5'4cba9991'7681cc9f'9e0d89f9_u128}, + {Sign::POS, -146, 0xfa279a19'87fd3b32'28dae4b7'241255e1_u128}, + {Sign::POS, -145, 0x8406afd6'78d4a2c0'f2b412f8'dceda28e_u128}, + {Sign::POS, -145, 0x8af992d7'c4e2d5b5'bf5dccd9'67504857_u128}, + {Sign::POS, -145, 0x91ec7610'a82cafed'3716dbf9'50b07f85_u128}, + {Sign::POS, -145, 0x98df5981'22b5aadd'69eebe0b'8e5b18e1_u128}, + {Sign::POS, -145, 0x9fd23d29'34813ffc'bb583ce6'5af56beb_u128}, + {Sign::POS, -145, 0xa6c52108'dd92e8c1'e22978ef'a7a962a0_u128}, + {Sign::POS, -145, 0xadb80520'1dee1ea3'e89bf389'8ef27836_u128}, + {Sign::POS, -145, 0xb4aae96e'f5965b1a'2c4c997e'c90bab0b_u128}, + {Sign::POS, -145, 0xbb9dcdf5'648f179c'5e3bcd6f'21fe6224_u128}, + {Sign::POS, -145, 0xc290b2b3'6adbcda2'82cd723b'f1524680_u128}, + {Sign::POS, -145, 0xc98397a9'087ff6a4'f1c8f574'935e109b_u128}, + {Sign::POS, -145, 0xd0767cd6'3d7f0c1c'565959c2'e4394a59_u128}, + {Sign::POS, -145, 0xd769623b'09dc8781'af0d4157'bc4f05be_u128}, + {Sign::POS, -145, 0xde5c47d7'6d9be24e'4dd6f857'6e9188b8_u128}, + {Sign::POS, -145, 0xe54f2dab'68c095fb'd80c7f46'484eee3d_u128}, + {Sign::POS, -145, 0xec4213b6'fb4e1c04'46679575'12a6bd26_u128}, + {Sign::POS, -145, 0xf334f9fa'2547ede1'e505c36d'95a074fa_u128}, + {Sign::POS, -145, 0xfa27e074'e6b1850f'5368655f'1ce3110b_u128}, + {Sign::POS, -144, 0x808d6393'9fc72d83'c23a5ac5'7f06c112_u128}, + {Sign::POS, -144, 0x8406d708'97f0f4a2'df39eb58'90580f93_u128}, + {Sign::POS, -144, 0x87804a99'5bd7d4a2'cd896f3e'43f38669_u128}, + {Sign::POS, -144, 0x8af9be45'eb7d8a41'83b16ff7'eecace8c_u128}, + {Sign::POS, -144, 0x8e73320e'46e3d23d'21ec7ae8'ffa1531d_u128}, + {Sign::POS, -144, 0x91eca5f2'6e0c6953'f227268d'464ae907_u128}, + {Sign::POS, -144, 0x956619f2'60f90c44'680017af'3bbaf2d3_u128}, + {Sign::POS, -144, 0x98df8e0e'1fab77cd'20c8069e'4ae400de_u128}, + {Sign::POS, -144, 0x9c590245'aa2568ac'e381c465'1a67ee13_u128}, + {Sign::POS, -144, 0x9fd27699'00689ba2'a0e23fff'd718794e_u128}, + {Sign::POS, -144, 0xa34beb08'2276cd6d'73508b92'7f485b97_u128}, + {Sign::POS, -144, 0xa6c55f93'1051bacc'9ee5e19f'2eecdb55_u128}, + {Sign::POS, -144, 0xaa3ed439'c9fb207f'916daa3c'6c8fdc9d_u128}, + {Sign::POS, -144, 0xadb848fc'4f74bb45'e265804b'77126ed3_u128}, + {Sign::POS, -144, 0xb131bdda'a0c047df'52fd36ae'943fd7b4_u128}, + {Sign::POS, -144, 0xb4ab32d4'bddf830b'ce16dd7f'60311bf6_u128}, + {Sign::POS, -144, 0xb824a7ea'a6d4298b'6846c745'1d8105ac_u128}, + {Sign::POS, -144, 0xbb9e1d1c'5b9ff81e'5fd38e2b'0650a884_u128}, + {Sign::POS, -144, 0xbf179269'dc44ab85'1cb61936'9e1c641f_u128}, + {Sign::POS, -144, 0xc29107d3'28c40080'3099a17e'0461648c_u128}, + {Sign::POS, -144, 0xc60a7d58'411fb3d0'56dbb75e'4813a12b_u128}, + {Sign::POS, -144, 0xc983f2f9'25598236'748c47b1'bbe45a07_u128}, + {Sign::POS, -144, 0xccfd68b5'd5732873'986da106'4b5913e1_u128}, + {Sign::POS, -144, 0xd076de8e'516e6348'faf478d3'd0b31300_u128}, + {Sign::POS, -144, 0xd3f05482'994cef77'fe47f0b2'6ba754ff_u128}, + {Sign::POS, -144, 0xd769ca92'ad1089c2'2e419b90'd8e709b7_u128}, + {Sign::POS, -144, 0xdae340be'8cbaeee9'406d82ea'ca788b6f_u128}, + {Sign::POS, -144, 0xde5cb706'384ddbaf'140a2bff'40e0d670_u128}, + {Sign::POS, -144, 0xe1d62d69'afcb0cd5'b2089d06'e51d8034_u128}, + {Sign::POS, -144, 0xe54fa3e8'f3343f1f'4d0c626a'636f2e4f_u128}, + {Sign::POS, -144, 0xe8c91a84'028b2f4e'416b93f8'c6f48d30_u128}, + {Sign::POS, -144, 0xec42913a'ddd19a25'152eda1d'd615c6f5_u128}, + {Sign::POS, -144, 0xefbc080d'85093c66'78117318'6fc07a66_u128}, + {Sign::POS, -144, 0xf3357efb'f833d2d5'43813830'e974324d_u128}, + {Sign::POS, -144, 0xf6aef606'37531a34'7a9ea2ef'6e1f5d41_u128}, + {Sign::POS, -144, 0xfa286d2c'4268cf47'4a3cd252'5dccc623_u128}, + {Sign::POS, -144, 0xfda1e46e'1976aed1'08e19004'ae218d5d_u128}, + {Sign::POS, -143, 0x808dade5'de3f3aca'9b62aaca'25d5d18a_u128}, + {Sign::POS, -143, 0x824a69a2'95c0f02b'bee9a8d4'3e00613c_u128}, + {Sign::POS, -143, 0x8407256d'334155ed'd8d4b69c'2056f729_u128}, + {Sign::POS, -143, 0x85c3e145'b6c14a72'e7cc2860'5d7bb77e_u128}, + {Sign::POS, -143, 0x87809d2c'2041ac1c'ff51b4bd'c834a8f1_u128}, + {Sign::POS, -143, 0x893d5920'6fc3594e'47c0774a'a81c3561_u128}, + {Sign::POS, -143, 0x8afa1522'a5473068'fe4cf331'ecb9eb62_u128}, + }, + // -log10(r) for the fourth step, generated by SageMath with: + // + // for i in range(-65, 65): + // r = 2^-28 * round( 2^28 / (1 + i*2^(-28)) ); + // s, m, e = RealField(128)(r).log10().sign_mantissa_exponent(); + // print("{Sign::POS," if (s == -1) else "{Sign::NEG,", e, ",", + // format_hex(m), "},"); + /* .step_4 = */ + { + {Sign::NEG, -151, 0xe1d54641'22cf95a4'e471a82b'bedbe0ae_u128}, + {Sign::NEG, -151, 0xde5bd6ec'7f7bc110'af6e93be'8e4c1764_u128}, + {Sign::NEG, -151, 0xdae26797'a490f80e'e44848f0'a5779499_u128}, + {Sign::NEG, -151, 0xd768f842'920f3a98'90205533'f4e70566_u128}, + {Sign::NEG, -151, 0xd3ef88ed'47f688a6'c01844ac'e3729e48_u128}, + {Sign::NEG, -151, 0xd0761997'c646e232'8151a232'4e41c7c4_u128}, + {Sign::NEG, -151, 0xccfcaa42'0d004734'e0edf74d'88cacafd_u128}, + {Sign::NEG, -151, 0xc9833aec'1c22b7a6'ec0ecc3a'5cd27e58_u128}, + {Sign::NEG, -151, 0xc609cb95'f3ae3381'afd5a7e7'0a6bf214_u128}, + {Sign::NEG, -151, 0xc2905c3f'93a2babe'39640ff4'47f81ceb_u128}, + {Sign::NEG, -151, 0xbf16ece8'fc004d55'95db88b5'422588b1_u128}, + {Sign::NEG, -151, 0xbb9d7d92'2cc6eb40'd25d952f'9beffeec_u128}, + {Sign::NEG, -151, 0xb8240e3b'25f69478'fc0bb71b'6ea03578_u128}, + {Sign::NEG, -151, 0xb4aa9ee3'e78f48f7'20076ee3'49cb7b20_u128}, + {Sign::NEG, -151, 0xb1312f8c'719108b4'4b723ba4'3353643d_u128}, + {Sign::NEG, -151, 0xadb7c034'c3fbd3a9'8b6d9b2d'a7657754_u128}, + {Sign::NEG, -151, 0xaa3e50dc'decfa9cf'ed1b0a01'987ad9b4_u128}, + {Sign::NEG, -151, 0xa6c4e184'c20c8b20'7d9c0354'6f57fc11_u128}, + {Sign::NEG, -151, 0xa34b722c'6db27794'4a12010d'0b0c4727_u128}, + {Sign::NEG, -151, 0x9fd202d3'e1c16f24'5f9e7bc4'c0f1c851_u128}, + {Sign::NEG, -151, 0x9c58937b'1e3971c9'cb62eac7'5cacde29_u128}, + {Sign::NEG, -151, 0x98df2422'231a7f7d'9a80c413'202be52a_u128}, + {Sign::NEG, -151, 0x9565b4c8'f0649838'da197c58'c3a6e445_u128}, + {Sign::NEG, -151, 0x91ec456f'8617bbf4'974e86fb'759f3988_u128}, + {Sign::NEG, -151, 0x8e72d615'e433eaa9'df415610'dadf46b3_u128}, + {Sign::NEG, -151, 0x8af966bc'0ab92451'bf135a61'0e7a1ddc_u128}, + {Sign::NEG, -151, 0x877ff761'f9a768e5'43e60366'a1cb2e09_u128}, + {Sign::NEG, -151, 0x84068807'b0feb85d'7adabf4e'9c75efce_u128}, + {Sign::NEG, -151, 0x808d18ad'30bf12b3'7112faf8'7c6591ee_u128}, + {Sign::NEG, -152, 0xfa2752a4'f1d0efc0'676043ec'6b994be5_u128}, + {Sign::NEG, -152, 0xf33473ef'12f5cfb9'9fa73d18'6649999d_u128}, + {Sign::NEG, -152, 0xec419538'c4ecc544'a53db362'aa5cc6f0_u128}, + {Sign::NEG, -152, 0xe54eb682'07b5d053'9266761d'e5e05f13_u128}, + {Sign::NEG, -152, 0xde5bd7ca'db50f0d8'81645201'b36e17ba_u128}, + {Sign::NEG, -152, 0xd768f913'3fbe26c5'8c7a112a'9a2b2a52_u128}, + {Sign::NEG, -152, 0xd0761a5b'34fd720c'cdea7b1a'0dc7ad42_u128}, + {Sign::NEG, -152, 0xc9833ba2'bb0ed2a0'5ff854b6'6e7ded1f_u128}, + {Sign::NEG, -152, 0xc2905ce9'd1f24872'5ce6604b'0911c5ed_u128}, + {Sign::NEG, -152, 0xbb9d7e30'79a7d374'def75d88'16cffc59_u128}, + {Sign::NEG, -152, 0xb4aa9f76'b22f739a'006e0982'bd8d96ef_u128}, + {Sign::NEG, -152, 0xadb7c0bc'7b8928d3'db8d1eb5'0fa7375c_u128}, + {Sign::NEG, -152, 0xa6c4e201'd5b4f314'8a9754fe'0c0073a7_u128}, + {Sign::NEG, -152, 0x9fd20346'c0b2d24e'27cf61a1'9e032f69_u128}, + {Sign::NEG, -152, 0x98df248b'3c82c672'cd77f748'9d9ef50b_u128}, + {Sign::NEG, -152, 0x91ec45cf'4924cf74'95d3c600'cf484f03_u128}, + {Sign::NEG, -152, 0x8af96712'e698ed45'9b257b3c'e3f82109_u128}, + {Sign::NEG, -152, 0x84068856'14df1fd7'f7afc1d4'792b015a_u128}, + {Sign::NEG, -153, 0xfa275331'a7eece3b'8b6a8408'31c123d8_u128}, + {Sign::NEG, -153, 0xec4195b6'47c38612'3ef142da'7335b35a_u128}, + {Sign::NEG, -153, 0xde5bd83a'093c6718'3e79062c'7cbb3b7d_u128}, + {Sign::NEG, -153, 0xd0761abc'ec597131'be870ed4'ed5b755b_u128}, + {Sign::NEG, -153, 0xc2905d3e'f11aa442'f3a09874'3d20fb64_u128}, + {Sign::NEG, -153, 0xb4aa9fc0'17800030'124ad974'bd15fbca_u128}, + {Sign::NEG, -153, 0xa6c4e240'5f8984dd'4f0b030a'9742eb00_u128}, + {Sign::NEG, -153, 0x98df24bf'c937322e'de664133'cead362d_u128}, + {Sign::NEG, -153, 0x8af9673e'54890808'f4e1bab8'3f55f5a1_u128}, + {Sign::NEG, -154, 0xfa275378'02fe0c9f'8e052253'3c713e98_u128}, + {Sign::NEG, -154, 0xde5bd871'a03259cf'129bc1c6'f293726e_u128}, + {Sign::NEG, -154, 0xc2905d69'80aef768'e0918216'6eeb17eb_u128}, + {Sign::NEG, -154, 0xa6c4e25f'a473e535'60f08720'313daa3f_u128}, + {Sign::NEG, -154, 0x8af96754'0b8122fc'fcc2ea56'6b3af38b_u128}, + {Sign::NEG, -155, 0xde5bd88d'6bad6110'3a25757e'00f4e3a0_u128}, + {Sign::NEG, -155, 0xa6c4e26f'46e91b3e'55d3f9e7'0cf177b8_u128}, + {Sign::NEG, -156, 0xde5bd89b'516ae82a'3d4aac85'125398d0_u128}, + {Sign::NEG, -157, 0xde5bd8a2'4449ac95'9ab5a849'a06f400d_u128}, + {Sign::POS, 0, 0_u128}, + {Sign::POS, -157, 0xde5bd8b0'2a073729'0d3cc88f'd4ef34c2_u128}, + {Sign::POS, -156, 0xde5bd8b7'1ce5fd51'225916c2'b3f33c90_u128}, + {Sign::POS, -155, 0xa6c4e28e'8bd3930a'17847f98'acf08d54_u128}, + {Sign::POS, -155, 0xde5bd8c5'02a38b5e'04439783'0931fddd_u128}, + {Sign::POS, -154, 0x8af9677f'79717409'c2ab3859'13176984_u128}, + {Sign::POS, -154, 0xa6c4e29e'2e48d4cc'e454dec8'2bde52e5_u128}, + {Sign::POS, -154, 0xc2905dbe'9fd7e82f'fe1522b0'470d7d7f_u128}, + {Sign::POS, -154, 0xde5bd8e0'ce1eae6a'a6e2721f'2afc3cce_u128}, + {Sign::POS, -154, 0xfa275404'b91d27b4'75b3458e'ec3c106c_u128}, + {Sign::POS, -153, 0x8af96795'3069aa22'80bf0ff2'f6cd9f93_u128}, + {Sign::POS, -153, 0x98df2528'e2a09a29'f09cc73b'7013b906_u128}, + {Sign::POS, -153, 0xa6c4e2bd'7333640c'55ee1480'619827c4_u128}, + {Sign::POS, -153, 0xb4aaa052'e22207e5'7c2e48d7'72250b3c_u128}, + {Sign::POS, -153, 0xc2905de9'2f6c85d1'2ed8ba8c'6fa81c98_u128}, + {Sign::POS, -153, 0xd0761b80'5b12ddeb'3968c521'4f33fc4f_u128}, + {Sign::POS, -153, 0xde5bd918'6515104f'6759c94e'2d017fad_u128}, + {Sign::POS, -153, 0xec4196b1'4d731d19'84272d01'4c70fe58_u128}, + {Sign::POS, -153, 0xfa27544b'142d0465'5b4c5b5f'180b9fe1_u128}, + {Sign::POS, -152, 0x840688f2'dca16327'5c226261'10c254a4_u128}, + {Sign::POS, -152, 0x8af967c0'9e5a3178'b345ef5d'90dd6545_u128}, + {Sign::POS, -152, 0x91ec468e'cf40ed34'98ce9208'7c5cb614_u128}, + {Sign::POS, -152, 0x98df255d'6f559668'f27a0a60'56dcfe57_u128}, + {Sign::POS, -152, 0x9fd2042c'7e982d23'a6061afe'b7929f24_u128}, + {Sign::POS, -152, 0xa6c4e2fb'fd08b172'99308918'494a4a20_u128}, + {Sign::POS, -152, 0xadb7c1cb'eaa72363'b1b71c7c'ca69a844_u128}, + {Sign::POS, -152, 0xb4aaa09c'47738304'd5579f97'0cf000a9_u128}, + {Sign::POS, -152, 0xbb9d7f6d'136dd063'e9cfdf6c'f676df42_u128}, + {Sign::POS, -152, 0xc2905e3e'4e960b8e'd4ddab9f'8032bbab_u128}, + {Sign::POS, -152, 0xc9833d0f'f8ec3493'7c3ed66a'b6f39fe9_u128}, + {Sign::POS, -152, 0xd0761be2'12704b7f'c5b134a5'bb25cf2e_u128}, + {Sign::POS, -152, 0xd768fab4'9b225061'96f29dc2'c0d26ca0_u128}, + {Sign::POS, -152, 0xde5bd987'93024346'd5c0ebcf'0fa0221e_u128}, + {Sign::POS, -152, 0xe54eb85a'fa10243d'67d9fb73'02d3c705_u128}, + {Sign::POS, -152, 0xec41972e'd04bf353'32fbabf2'095106f1_u128}, + {Sign::POS, -152, 0xf3347603'15b5b096'1ce3df2a'a59b0889_u128}, + {Sign::POS, -152, 0xfa2754d7'ca4d5c14'0b507996'6dd5143e_u128}, + {Sign::POS, -151, 0x808d19d6'77097aed'71ffb125'05e19d89_u128}, + {Sign::POS, -151, 0x84068941'40833efc'4657417a'9e657eae_u128}, + {Sign::POS, -151, 0x877ff8ac'4193fa3d'758de3f1'68f9f8c9_u128}, + {Sign::POS, -151, 0x8af96817'7a3bacb7'f2828ffc'57f43581_u128}, + {Sign::POS, -151, 0x8e72d782'ea7a5672'b0143e5b'e77b1053_u128}, + {Sign::POS, -151, 0x91ec46ee'924ff774'a121e91e'1d8769ef_u128}, + {Sign::POS, -151, 0x9565b65a'71bc8fc4'b88a8b9e'89e47b9c_u128}, + {Sign::POS, -151, 0x98df25c6'88c01f69'e92d2286'46302a9c_u128}, + {Sign::POS, -151, 0x9c589532'd75aa66b'25e8abcb'f5db5b8c_u128}, + {Sign::POS, -151, 0x9fd2049f'5d8c24cf'619c26b3'c62a45c8_u128}, + {Sign::POS, -151, 0xa34b740c'1b549a9d'8f2693cf'6e34c6cc_u128}, + {Sign::POS, -151, 0xa6c4e379'10b407dc'a166f4fe'2ee6b59a_u128}, + {Sign::POS, -151, 0xaa3e52e6'3daa6c93'8b3c4d6c'd3003616_u128}, + {Sign::POS, -151, 0xadb7c253'a237c8c9'3f85a195'af160c71_u128}, + {Sign::POS, -151, 0xb13131c1'3e5c1c84'b121f740'a191f084_u128}, + {Sign::POS, -151, 0xb4aaa12f'121767cc'd2f05583'12b2e136_u128}, + {Sign::POS, -151, 0xb824109d'1d69aaa8'97cfc4bf'f48d77de_u128}, + {Sign::POS, -151, 0xbb9d800b'6052e51e'f29f4ea7'c30c3ba5_u128}, + {Sign::POS, -151, 0xbf16ef79'dad31736'd63dfe38'83eff4e9_u128}, + {Sign::POS, -151, 0xc2905ee8'8cea40f7'358adfbd'c6d0009f_u128}, + {Sign::POS, -151, 0xc609ce57'76986267'036500d0'a51aa3b6_u128}, + {Sign::POS, -151, 0xc9833dc6'97dd7b8d'32ab7057'c2155e78_u128}, + {Sign::POS, -151, 0xccfcad35'f0b98c70'b63d3e87'4add3ff0_u128}, + {Sign::POS, -151, 0xd0761ca5'812c9518'80f97ce0'f6673948_u128}, + {Sign::POS, -151, 0xd3ef8c15'4936958b'85bf3e34'0580712d_u128}, + {Sign::POS, -151, 0xd768fb85'48d78dd0'b76d969d'42ce9734_u128}, + {Sign::POS, -151, 0xdae26af5'800f7def'08e39b87'02d0373a_u128}, + {Sign::POS, -151, 0xde5bda65'eede65ed'6d0063a9'23dd0cc6_u128}, + }}; + +// > P = fpminimax(log10(1 + x)/x, 3, [|128...|], [-0x1.0002143p-29 , 0x1p-29]); +// > P; +// > dirtyinfnorm(log10(1 + x)/x - P, [-0x1.0002143p-29 , 0x1p-29]); +// 0x1.64fb8...p-123 +LIBC_INLINE_VAR constexpr Float128 BIG_COEFFS[4]{ + {Sign::NEG, -131, 0xde5bd8a9'373f89a7'6903c4ce'1582517d_u128}, + {Sign::POS, -130, 0x943d3b1b'7a1af679'b8a21791'624e2e8a_u128}, + {Sign::NEG, -130, 0xde5bd8a9'37287195'355baaaf'abc25990_u128}, + {Sign::POS, -129, 0xde5bd8a9'37287195'355baaaf'ad33dbd9_u128}, +}; + +// Reuse the output of the fast pass range reduction. +// -2^-8 <= m_x < 2^-7 +LIBC_INLINE static double log10_accurate(int e_x, int index, double m_x) { + + Float128 e_x_f128(static_cast<float>(e_x)); + Float128 sum = fputil::quick_mul(LOG10_2, e_x_f128); + sum = fputil::quick_add(sum, LOG10_TABLE.step_1[index]); + + Float128 v_f128 = log_range_reduction(m_x, LOG10_TABLE, sum); + + // Polynomial approximation + Float128 p = fputil::quick_mul(v_f128, BIG_COEFFS[0]); + p = fputil::quick_mul(v_f128, fputil::quick_add(p, BIG_COEFFS[1])); + p = fputil::quick_mul(v_f128, fputil::quick_add(p, BIG_COEFFS[2])); + p = fputil::quick_mul(v_f128, fputil::quick_add(p, BIG_COEFFS[3])); + + Float128 r = fputil::quick_add(sum, p); + + return static_cast<double>(r); +} +#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS + +} // namespace log10_internal + +LIBC_INLINE static double log10(double x) { + using namespace log10_internal; + using namespace common_constants_internal; + using FPBits_t = typename fputil::FPBits<double>; + + FPBits_t xbits(x); + uint64_t x_u = xbits.uintval(); + + int x_e = -FPBits_t::EXP_BIAS; + + if (LIBC_UNLIKELY(xbits == FPBits_t::one())) { + // log10(1.0) = +0.0 + return 0.0; + } + + if (LIBC_UNLIKELY(xbits.uintval() < FPBits_t::min_normal().uintval() || + xbits.uintval() > FPBits_t::max_normal().uintval())) { + if (x == 0.0) { + // return -Inf and raise FE_DIVBYZERO. + fputil::set_errno_if_required(ERANGE); + fputil::raise_except_if_required(FE_DIVBYZERO); + return FPBits_t::inf(Sign::NEG).get_val(); + } + if (xbits.is_neg() && !xbits.is_nan()) { + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_INVALID); + return FPBits_t::quiet_nan().get_val(); + } + if (xbits.is_inf_or_nan()) { + return x; + } + // Normalize denormal inputs. + xbits = FPBits_t(x * 0x1.0p52); + x_e -= 52; + x_u = xbits.uintval(); + } + + // log10(x) = log10(2^x_e * x_m) + // = x_e * log10(2) + log10(x_m) + + // Range reduction for log10(x_m): + // For each x_m, we would like to find r such that: + // -2^-8 <= r * x_m - 1 < 2^-7 + int shifted = static_cast<int>(x_u >> 45); + int index = shifted & 0x7F; + double r = RD[index]; + + // Add unbiased exponent. Add an extra 1 if the 8 leading fractional bits are + // all 1's. + x_e += static_cast<int>((x_u + (1ULL << 45)) >> 52); + double e_x = static_cast<double>(x_e); + + // hi is exact + double hi = fputil::multiply_add(e_x, LOG_2_HI, LOG_R_DD[index].hi); + // lo errors ~ e_x * LSB(LOG_2_LO) + LSB(LOG_R[index].lo) + rounding err + // <= 2 * (e_x * LSB(LOG_2_LO) + LSB(LOG_R[index].lo)) + double lo = fputil::multiply_add(e_x, LOG_2_LO, LOG_R_DD[index].lo); + + // Set m = 1.mantissa. + uint64_t x_m = (x_u & 0x000F'FFFF'FFFF'FFFFULL) | 0x3FF0'0000'0000'0000ULL; + double m = FPBits_t(x_m).get_val(); + + fputil::DoubleDouble r1; + + // Perform exact range reduction +#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE + double u = fputil::multiply_add(r, m, -1.0); // exact +#else + uint64_t c_m = x_m & 0x3FFF'E000'0000'0000ULL; + double c = FPBits_t(c_m).get_val(); + double u = fputil::multiply_add(r, m - c, CD[index]); // exact +#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE + + // Error of u_sq = ulp(u^2); + double u_sq = u * u; + // Degree-7 minimax polynomial + double p0 = fputil::multiply_add(u, LOG_COEFFS[1], LOG_COEFFS[0]); + double p1 = fputil::multiply_add(u, LOG_COEFFS[3], LOG_COEFFS[2]); + double p2 = fputil::multiply_add(u, LOG_COEFFS[5], LOG_COEFFS[4]); + double p = fputil::polyeval(u_sq, lo, p0, p1, p2); + + // Exact sum: + // r1.hi + r1.lo = e_x * log(2)_hi - log(r)_hi + u + r1 = fputil::exact_add(hi, u); + r1.lo += p; + + // Quick double-double multiplication: + // r2.hi + r2.lo ~ r1 * log10(e), + // with error bounded by: + // 4*ulp( ulp(r2.hi) ) + fputil::DoubleDouble r2 = fputil::quick_mult(r1, LOG10_E); + +#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + return r2.hi + r2.lo; +#else + // Technicallly error of r1.lo is bounded by: + // |hi|*ulp(log(2)_lo) + C*ulp(u^2) + // To simplify the error computation a bit, we replace |hi|*ulp(log(2)_lo) + // with the upper bound: 2^11 * ulp(log(2)_lo) = 2^-85. + // Total error is bounded by ~ C * ulp(u^2) + 2^-85. + double err = fputil::multiply_add(u_sq, P_ERR, HI_ERR); + + // Lower bound from the result + double left = r2.hi + (r2.lo - err); + // Upper bound from the result + double right = r2.hi + (r2.lo + err); + + // Ziv's test if fast pass is accurate enough. + if (left == right) + return left; + + // Exact cases: + if (LIBC_UNLIKELY((x_u & 0x3FFFFF) == 0)) { + switch (x_u) { + case 0x4024000000000000: // x = 10.0 + return 1.0; + case 0x4059000000000000: // x = 10^2 + return 2.0; + case 0x408f400000000000: // x = 10^3 + return 3.0; + case 0x40c3880000000000: // x = 10^4 + return 4.0; + case 0x40f86a0000000000: // x = 10^5 + return 5.0; + case 0x412e848000000000: // x = 10^6 + return 6.0; + case 0x416312d000000000: // x = 10^7 + return 7.0; + case 0x4197d78400000000: // x = 10^8 + return 8.0; + case 0x41cdcd6500000000: // x = 10^9 + return 9.0; + case 0x4202a05f20000000: // x = 10^10 + return 10.0; + case 0x42374876e8000000: // x = 10^11 + return 11.0; + case 0x426d1a94a2000000: // x = 10^12 + return 12.0; + case 0x42a2309ce5400000: // x = 10^13 + return 13.0; + } + } else { + switch (x_u) { + case 0x42d6bcc41e900000: // x = 10^14 + return 14.0; + case 0x430c6bf526340000: // x = 10^15 + return 15.0; + case 0x4341c37937e08000: // x = 10^16 + return 16.0; + case 0x4376345785d8a000: // x = 10^17 + return 17.0; + case 0x43abc16d674ec800: // x = 10^18 + return 18.0; + case 0x43e158e460913d00: // x = 10^19 + return 19.0; + case 0x4415af1d78b58c40: // x = 10^20 + return 20.0; + case 0x444b1ae4d6e2ef50: // x = 10^21 + return 21.0; + case 0x4480f0cf064dd592: // x = 10^22 + return 22.0; + } + } + + return log10_accurate(x_e, index, u); +#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_LOG10_H diff --git a/libc/src/__support/math/log1p.h b/libc/src/__support/math/log1p.h new file mode 100644 index 0000000..9950161 --- /dev/null +++ b/libc/src/__support/math/log1p.h @@ -0,0 +1,1070 @@ +//===-- Double-precision log1p(x) function --------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_LOG1P_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_LOG1P_H + +#include "common_constants.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/PolyEval.h" +#include "src/__support/FPUtil/double_double.h" +#include "src/__support/FPUtil/dyadic_float.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/common.h" +#include "src/__support/integer_literals.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY + +namespace LIBC_NAMESPACE_DECL { + +namespace math { +namespace log1p_internal { +// 128-bit precision dyadic floating point numbers. +using Float128 = typename fputil::DyadicFloat<128>; + +using LIBC_NAMESPACE::operator""_u128; + +using namespace common_constants_internal; + +// R1[i] = 2^-8 * nearestint( 2^8 / (1 + i * 2^-7) ) +LIBC_INLINE_VAR constexpr double R1[129] = { + 0x1p0, 0x1.fcp-1, 0x1.f8p-1, 0x1.f4p-1, 0x1.fp-1, 0x1.ecp-1, 0x1.eap-1, + 0x1.e6p-1, 0x1.e2p-1, 0x1.dep-1, 0x1.dap-1, 0x1.d8p-1, 0x1.d4p-1, 0x1.dp-1, + 0x1.cep-1, 0x1.cap-1, 0x1.c8p-1, 0x1.c4p-1, 0x1.cp-1, 0x1.bep-1, 0x1.bap-1, + 0x1.b8p-1, 0x1.b4p-1, 0x1.b2p-1, 0x1.bp-1, 0x1.acp-1, 0x1.aap-1, 0x1.a6p-1, + 0x1.a4p-1, 0x1.a2p-1, 0x1.9ep-1, 0x1.9cp-1, 0x1.9ap-1, 0x1.98p-1, 0x1.94p-1, + 0x1.92p-1, 0x1.9p-1, 0x1.8ep-1, 0x1.8ap-1, 0x1.88p-1, 0x1.86p-1, 0x1.84p-1, + 0x1.82p-1, 0x1.8p-1, 0x1.7ep-1, 0x1.7ap-1, 0x1.78p-1, 0x1.76p-1, 0x1.74p-1, + 0x1.72p-1, 0x1.7p-1, 0x1.6ep-1, 0x1.6cp-1, 0x1.6ap-1, 0x1.68p-1, 0x1.66p-1, + 0x1.64p-1, 0x1.62p-1, 0x1.6p-1, 0x1.5ep-1, 0x1.5cp-1, 0x1.5ap-1, 0x1.58p-1, + 0x1.58p-1, 0x1.56p-1, 0x1.54p-1, 0x1.52p-1, 0x1.5p-1, 0x1.4ep-1, 0x1.4cp-1, + 0x1.4ap-1, 0x1.4ap-1, 0x1.48p-1, 0x1.46p-1, 0x1.44p-1, 0x1.42p-1, 0x1.42p-1, + 0x1.4p-1, 0x1.3ep-1, 0x1.3cp-1, 0x1.3cp-1, 0x1.3ap-1, 0x1.38p-1, 0x1.36p-1, + 0x1.36p-1, 0x1.34p-1, 0x1.32p-1, 0x1.3p-1, 0x1.3p-1, 0x1.2ep-1, 0x1.2cp-1, + 0x1.2cp-1, 0x1.2ap-1, 0x1.28p-1, 0x1.28p-1, 0x1.26p-1, 0x1.24p-1, 0x1.24p-1, + 0x1.22p-1, 0x1.2p-1, 0x1.2p-1, 0x1.1ep-1, 0x1.1cp-1, 0x1.1cp-1, 0x1.1ap-1, + 0x1.1ap-1, 0x1.18p-1, 0x1.16p-1, 0x1.16p-1, 0x1.14p-1, 0x1.14p-1, 0x1.12p-1, + 0x1.12p-1, 0x1.1p-1, 0x1.0ep-1, 0x1.0ep-1, 0x1.0cp-1, 0x1.0cp-1, 0x1.0ap-1, + 0x1.0ap-1, 0x1.08p-1, 0x1.08p-1, 0x1.06p-1, 0x1.06p-1, 0x1.04p-1, 0x1.04p-1, + 0x1.02p-1, 0x1.02p-1, 0x1p-1, +}; + +// Extra constants for exact range reduction when FMA instructions are not +// available: +// r * c - 1 for r = 2^-8 * nearestint( 2^8 / (1 + i * 2^-7)) +// and c = 1 + i * 2^-7 +// with i = 0..128. +[[maybe_unused]] LIBC_INLINE_VAR constexpr double RCM1[129] = { + 0.0, -0x1p-14, -0x1p-12, -0x1.2p-11, -0x1p-10, -0x1.9p-10, + 0x1.fp-10, 0x1.28p-10, 0x1p-12, -0x1.9p-11, -0x1.fp-10, 0x1.2p-10, + -0x1p-12, -0x1.cp-10, 0x1.1p-10, -0x1.5p-11, 0x1p-9, 0x1p-14, + -0x1p-9, 0x1.ap-12, -0x1.ep-10, 0x1.8p-12, -0x1.1p-9, -0x1p-15, + 0x1p-9, -0x1.ap-11, 0x1.1p-10, -0x1.f8p-10, -0x1p-12, 0x1.68p-10, + -0x1.fp-10, -0x1.cp-12, 0x1p-10, 0x1.3p-9, -0x1.6p-10, -0x1.4p-13, + 0x1p-10, 0x1.0cp-9, -0x1.08p-9, -0x1.2p-10, -0x1p-12, 0x1.2p-11, + 0x1.5p-10, 0x1p-9, 0x1.5p-9, -0x1.1cp-9, -0x1.cp-10, -0x1.58p-10, + -0x1p-10, -0x1.7p-11, -0x1p-11, -0x1.6p-12, -0x1p-12, -0x1.cp-13, + -0x1p-12, -0x1.6p-12, -0x1p-11, -0x1.7p-11, -0x1p-10, -0x1.58p-10, + -0x1.cp-10, -0x1.1cp-9, -0x1.6p-9, 0x1.5p-9, 0x1p-9, 0x1.5p-10, + 0x1.2p-11, -0x1p-12, -0x1.2p-10, -0x1.08p-9, -0x1.88p-9, 0x1.0cp-9, + 0x1p-10, -0x1.4p-13, -0x1.6p-10, -0x1.54p-9, 0x1.3p-9, 0x1p-10, + -0x1.cp-12, -0x1.fp-10, 0x1.8p-9, 0x1.68p-10, -0x1p-12, -0x1.f8p-10, + 0x1.7p-9, 0x1.1p-10, -0x1.ap-11, -0x1.6p-9, 0x1p-9, -0x1p-15, + -0x1.1p-9, 0x1.48p-9, 0x1.8p-12, -0x1.ep-10, 0x1.6p-9, 0x1.ap-12, + -0x1p-9, 0x1.48p-9, 0x1p-14, -0x1.4p-9, 0x1p-9, -0x1.5p-11, + -0x1.bp-9, 0x1.1p-10, -0x1.cp-10, 0x1.54p-9, -0x1p-12, -0x1.9cp-9, + 0x1.2p-10, -0x1.fp-10, 0x1.3p-9, -0x1.9p-11, 0x1.cp-9, 0x1p-12, + -0x1.88p-9, 0x1.28p-10, -0x1.2p-9, 0x1.fp-10, -0x1.9p-10, 0x1.4cp-9, + -0x1p-10, 0x1.9p-9, -0x1.2p-11, 0x1.c4p-9, -0x1p-12, 0x1.e8p-9, + -0x1p-14, 0x1.fcp-9, 0.0, +}; + +// Generated by Sollya with: +// for i from 0 to 128 do { +// r = 2^-8 * nearestint( 2^8 / (1 + i*2^-7) ); +// b = nearestint(log(r)*2^43) * 2^-43; +// c = round(log(r) - b, D, RN); +// print("{", -c, ",", -b, "},"); +// }; +// We replace LOG_R1_DD[128] with log(1.0) == 0.0 +alignas(16) LIBC_INLINE_VAR constexpr fputil::DoubleDouble LOG_R1_DD[129] = { + {0.0, 0.0}, + {-0x1.0c76b999d2be8p-46, 0x1.010157589p-7}, + {-0x1.3dc5b06e2f7d2p-45, 0x1.0205658938p-6}, + {-0x1.aa0ba325a0c34p-45, 0x1.8492528c9p-6}, + {0x1.111c05cf1d753p-47, 0x1.0415d89e74p-5}, + {-0x1.c167375bdfd28p-45, 0x1.466aed42ep-5}, + {-0x1.29efbec19afa2p-47, 0x1.67c94f2d4cp-5}, + {0x1.0fc1a353bb42ep-45, 0x1.aaef2d0fbp-5}, + {-0x1.e113e4fc93b7bp-47, 0x1.eea31c006cp-5}, + {-0x1.5325d560d9e9bp-45, 0x1.1973bd1466p-4}, + {0x1.cc85ea5db4ed7p-45, 0x1.3bdf5a7d1ep-4}, + {-0x1.53a2582f4e1efp-48, 0x1.4d3115d208p-4}, + {0x1.c1e8da99ded32p-49, 0x1.700d30aeacp-4}, + {0x1.3115c3abd47dap-45, 0x1.9335e5d594p-4}, + {-0x1.e42b6b94407c8p-47, 0x1.a4e7640b1cp-4}, + {0x1.646d1c65aacd3p-45, 0x1.c885801bc4p-4}, + {0x1.a89401fa71733p-46, 0x1.da72763844p-4}, + {-0x1.534d64fa10afdp-45, 0x1.fe89139dbep-4}, + {0x1.1ef78ce2d07f2p-45, 0x1.1178e8227ep-3}, + {0x1.ca78e44389934p-45, 0x1.1aa2b7e23fp-3}, + {0x1.39d6ccb81b4a1p-47, 0x1.2d1610c868p-3}, + {0x1.62fa8234b7289p-51, 0x1.365fcb0159p-3}, + {0x1.5837954fdb678p-45, 0x1.4913d8333bp-3}, + {0x1.633e8e5697dc7p-45, 0x1.527e5e4a1bp-3}, + {-0x1.27023eb68981cp-46, 0x1.5bf406b544p-3}, + {-0x1.5118de59c21e1p-45, 0x1.6f0128b757p-3}, + {-0x1.c661070914305p-46, 0x1.7898d85445p-3}, + {-0x1.73d54aae92cd1p-47, 0x1.8beafeb39p-3}, + {0x1.7f22858a0ff6fp-47, 0x1.95a5adcf7p-3}, + {0x1.9904d6865817ap-45, 0x1.9f6c407089p-3}, + {-0x1.c358d4eace1aap-47, 0x1.b31d8575bdp-3}, + {-0x1.d4bc4595412b6p-45, 0x1.bd087383bep-3}, + {-0x1.1ec72c5962bd2p-48, 0x1.c6ffbc6f01p-3}, + {-0x1.84a7e75b6f6e4p-47, 0x1.d1037f2656p-3}, + {0x1.212276041f43p-51, 0x1.e530effe71p-3}, + {-0x1.a211565bb8e11p-51, 0x1.ef5ade4ddp-3}, + {0x1.bcbecca0cdf3p-46, 0x1.f991c6cb3bp-3}, + {-0x1.6f08c1485e94ap-46, 0x1.01eae5626c8p-2}, + {0x1.7188b163ceae9p-45, 0x1.0c42d67616p-2}, + {-0x1.c210e63a5f01cp-45, 0x1.1178e8227e8p-2}, + {0x1.b9acdf7a51681p-45, 0x1.16b5ccbacf8p-2}, + {0x1.ca6ed5147bdb7p-45, 0x1.1bf99635a68p-2}, + {0x1.a87deba46baeap-47, 0x1.214456d0eb8p-2}, + {0x1.c93c1df5bb3b6p-45, 0x1.269621134d8p-2}, + {0x1.a9cfa4a5004f4p-45, 0x1.2bef07cdc9p-2}, + {0x1.16ecdb0f177c8p-46, 0x1.36b6776be1p-2}, + {0x1.83b54b606bd5cp-46, 0x1.3c25277333p-2}, + {0x1.8e436ec90e09dp-47, 0x1.419b423d5e8p-2}, + {-0x1.f27ce0967d675p-45, 0x1.4718dc271c8p-2}, + {-0x1.e20891b0ad8a4p-45, 0x1.4c9e09e173p-2}, + {0x1.ebe708164c759p-45, 0x1.522ae0738ap-2}, + {0x1.fadedee5d40efp-46, 0x1.57bf753c8dp-2}, + {-0x1.a0b2a08a465dcp-47, 0x1.5d5bddf596p-2}, + {-0x1.db623e731aep-45, 0x1.630030b3abp-2}, + {0x1.0a0d32756ebap-45, 0x1.68ac83e9c68p-2}, + {0x1.721657c222d87p-46, 0x1.6e60ee6af18p-2}, + {0x1.d8b0949dc60b3p-45, 0x1.741d876c678p-2}, + {0x1.9ec7d2efd1778p-45, 0x1.79e26687cf8p-2}, + {-0x1.72090c812566ap-45, 0x1.7fafa3bd818p-2}, + {0x1.fd56f3333778ap-45, 0x1.85855776dc8p-2}, + {-0x1.05ae1e5e7047p-45, 0x1.8b639a88b3p-2}, + {-0x1.766b52ee6307dp-46, 0x1.914a8635bf8p-2}, + {-0x1.52313a502d9fp-46, 0x1.973a3431358p-2}, + {-0x1.52313a502d9fp-46, 0x1.973a3431358p-2}, + {-0x1.6279e10d0c0bp-45, 0x1.9d32bea15fp-2}, + {0x1.3c6457f9d79f5p-45, 0x1.a33440224f8p-2}, + {0x1.e36f2bea77a5dp-46, 0x1.a93ed3c8ad8p-2}, + {-0x1.17cc552774458p-45, 0x1.af5295248dp-2}, + {0x1.095252d841995p-46, 0x1.b56fa044628p-2}, + {0x1.7d85bf40a666dp-45, 0x1.bb9611b80ep-2}, + {0x1.cec807fe8e18p-45, 0x1.c1c60693fap-2}, + {0x1.cec807fe8e18p-45, 0x1.c1c60693fap-2}, + {-0x1.9b6ddc15249aep-45, 0x1.c7ff9c74558p-2}, + {-0x1.797c33ec7a6bp-47, 0x1.ce42f180648p-2}, + {0x1.35bafe9a767a8p-45, 0x1.d490246def8p-2}, + {-0x1.ea42d60dc616ap-46, 0x1.dae75484c98p-2}, + {-0x1.ea42d60dc616ap-46, 0x1.dae75484c98p-2}, + {-0x1.326b207322938p-46, 0x1.e148a1a2728p-2}, + {-0x1.465505372bd08p-45, 0x1.e7b42c3ddbp-2}, + {0x1.f27f45a470251p-45, 0x1.ee2a156b41p-2}, + {0x1.f27f45a470251p-45, 0x1.ee2a156b41p-2}, + {0x1.2cde56f014a8bp-46, 0x1.f4aa7ee0318p-2}, + {0x1.085fa3c164935p-47, 0x1.fb358af7a48p-2}, + {-0x1.53ba3b1727b1cp-47, 0x1.00e5ae5b208p-1}, + {-0x1.53ba3b1727b1cp-47, 0x1.00e5ae5b208p-1}, + {-0x1.4c45fe79539ep-47, 0x1.04360be7604p-1}, + {0x1.6812241edf5fdp-45, 0x1.078bf0533c4p-1}, + {0x1.f486b887e7e27p-46, 0x1.0ae76e2d054p-1}, + {0x1.f486b887e7e27p-46, 0x1.0ae76e2d054p-1}, + {0x1.c299807801742p-46, 0x1.0e4898611ccp-1}, + {-0x1.58647bb9ddcb2p-45, 0x1.11af823c75cp-1}, + {-0x1.58647bb9ddcb2p-45, 0x1.11af823c75cp-1}, + {-0x1.edd97a293ae49p-45, 0x1.151c3f6f298p-1}, + {0x1.4cc4ef8ab465p-46, 0x1.188ee40f23cp-1}, + {0x1.4cc4ef8ab465p-46, 0x1.188ee40f23cp-1}, + {0x1.cacdeed70e667p-51, 0x1.1c07849ae6p-1}, + {-0x1.a7242c9fe81d3p-45, 0x1.1f8635fc618p-1}, + {-0x1.a7242c9fe81d3p-45, 0x1.1f8635fc618p-1}, + {0x1.2fc066e48667bp-46, 0x1.230b0d8bebcp-1}, + {-0x1.b61f10522625p-47, 0x1.269621134dcp-1}, + {-0x1.b61f10522625p-47, 0x1.269621134dcp-1}, + {0x1.06d2be797882dp-45, 0x1.2a2786d0ecp-1}, + {-0x1.7a6e507b9dc11p-46, 0x1.2dbf557b0ep-1}, + {-0x1.7a6e507b9dc11p-46, 0x1.2dbf557b0ep-1}, + {-0x1.74e93c5a0ed9cp-45, 0x1.315da443408p-1}, + {-0x1.74e93c5a0ed9cp-45, 0x1.315da443408p-1}, + {0x1.0b83f9527e6acp-46, 0x1.35028ad9d8cp-1}, + {-0x1.18b7abb5569a4p-45, 0x1.38ae2171978p-1}, + {-0x1.18b7abb5569a4p-45, 0x1.38ae2171978p-1}, + {-0x1.2b7367cfe13c2p-47, 0x1.3c6080c36cp-1}, + {-0x1.2b7367cfe13c2p-47, 0x1.3c6080c36cp-1}, + {-0x1.6ce7930f0c74cp-45, 0x1.4019c2125ccp-1}, + {-0x1.6ce7930f0c74cp-45, 0x1.4019c2125ccp-1}, + {-0x1.d984f481051f7p-48, 0x1.43d9ff2f924p-1}, + {-0x1.2cb6af94d60aap-45, 0x1.47a1527e8a4p-1}, + {-0x1.2cb6af94d60aap-45, 0x1.47a1527e8a4p-1}, + {0x1.f7115ed4c541cp-49, 0x1.4b6fd6f970cp-1}, + {0x1.f7115ed4c541cp-49, 0x1.4b6fd6f970cp-1}, + {-0x1.e6c516d93b8fbp-45, 0x1.4f45a835a5p-1}, + {-0x1.e6c516d93b8fbp-45, 0x1.4f45a835a5p-1}, + {0x1.5ccc45d257531p-47, 0x1.5322e268678p-1}, + {0x1.5ccc45d257531p-47, 0x1.5322e268678p-1}, + {0x1.9980bff3303ddp-47, 0x1.5707a26bb8cp-1}, + {0x1.9980bff3303ddp-47, 0x1.5707a26bb8cp-1}, + {0x1.dfa63ac10c9fbp-45, 0x1.5af405c3648p-1}, + {0x1.dfa63ac10c9fbp-45, 0x1.5af405c3648p-1}, + {0x1.202380cda46bep-45, 0x1.5ee82aa2418p-1}, + {0x1.202380cda46bep-45, 0x1.5ee82aa2418p-1}, + {0.0, 0.0}, +}; + +// Degree-7 minimax polynomial log(1 + v) ~ v - v^2 / 2 + ... +// generated by Sollya with: +// > P = fpminimax(log(1 + x)/x, 6, [|1, 1, D...|], +// [-0x1.69000000000edp-8, 0x1.7f00000000081p-8]); +LIBC_INLINE_VAR constexpr double P_COEFFS[6] = {-0x1p-1, + 0x1.5555555555166p-2, + -0x1.fffffffdb7746p-3, + 0x1.99999a8718a6p-3, + -0x1.555874ce8ce22p-3, + 0x1.24335555ddbe5p-3}; + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS +// Extra errors from P is from using x^2 to reduce evaluation latency and +// directional rounding. +LIBC_INLINE_VAR constexpr double P_ERR = 0x1.0p-49; + +// log(2) with 128-bit precision generated by SageMath with: +// def format_hex(value): +// l = hex(value)[2:] +// n = 8 +// x = [l[i:i + n] for i in range(0, len(l), n)] +// return "0x" + "'".join(x) + "_u128" +// (s, m, e) = RealField(128)(2).log().sign_mantissa_exponent(); +// print(format_hex(m)); +LIBC_INLINE_VAR constexpr Float128 + LOG_2(Sign::POS, + /*exponent=*/-128, /*mantissa=*/ + 0xb17217f7'd1cf79ab'c9e3b398'03f2f6af_u128); + +// -log(r1) with 128-bit precision generated by SageMath with: +// +// for i in range(129): +// r = 2^-8 * round( 2^8 / (1 + i*2^(-7)) ); +// s, m, e = RealField(128)(r).log().sign_mantissa_exponent(); +// print("{Sign::POS,", e, ", format_hex(m), "},"); +LIBC_INLINE_VAR constexpr Float128 LOG_R1[129] = { + {Sign::POS, 0, 0_u128}, + {Sign::POS, -134, 0x8080abac'46f38946'662d417c'ed007a46_u128}, + {Sign::POS, -133, 0x8102b2c4'9ac23a4f'91d082dc'e3ddcd38_u128}, + {Sign::POS, -133, 0xc2492946'4655f45c'da5f3cc0'b3251dbd_u128}, + {Sign::POS, -132, 0x820aec4f'3a222380'b9e3aea6'c444ef07_u128}, + {Sign::POS, -132, 0xa33576a1'6f1f4c64'521016bd'904dc968_u128}, + {Sign::POS, -132, 0xb3e4a796'a5dac208'27cca0bc'c06c2f92_u128}, + {Sign::POS, -132, 0xd5779687'd887e0d1'a9dda170'56e45ed5_u128}, + {Sign::POS, -132, 0xf7518e00'35c3dd83'606d8909'3278a939_u128}, + {Sign::POS, -131, 0x8cb9de8a'32ab368a'a7c98595'30a45153_u128}, + {Sign::POS, -131, 0x9defad3e'8f73217a'976d3b5b'45f6ca0b_u128}, + {Sign::POS, -131, 0xa6988ae9'03f562ed'3e858f08'597b3a69_u128}, + {Sign::POS, -131, 0xb8069857'560707a3'6a677b4c'8bec22e1_u128}, + {Sign::POS, -131, 0xc99af2ea'ca4c4570'eaf51f66'692844ba_u128}, + {Sign::POS, -131, 0xd273b205'8de1bd49'46bbf837'b4d320c6_u128}, + {Sign::POS, -131, 0xe442c00d'e2591b47'196ab34c'e0bccd12_u128}, + {Sign::POS, -131, 0xed393b1c'22351280'3f4e2e66'0317d55f_u128}, + {Sign::POS, -131, 0xff4489ce'deab2ca6'c17bd40d'8d9291ec_u128}, + {Sign::POS, -130, 0x88bc7411'3f23def1'9c5a0fe3'96f40f1e_u128}, + {Sign::POS, -130, 0x8d515bf1'1fb94f1c'88713268'840cbcc0_u128}, + {Sign::POS, -130, 0x968b0864'3409ceb6'65c0da50'6a088484_u128}, + {Sign::POS, -130, 0x9b2fe580'ac80b17d'411a5b94'4aca8708_u128}, + {Sign::POS, -130, 0xa489ec19'9dab06f2'a9fb6cf0'ecb411b7_u128}, + {Sign::POS, -130, 0xa93f2f25'0dac67d1'cad2fb8d'48054ae0_u128}, + {Sign::POS, -130, 0xadfa035a'a1ed8fdc'149767e4'10316d2c_u128}, + {Sign::POS, -130, 0xb780945b'ab55dce4'34c7bc3d'32750fde_u128}, + {Sign::POS, -130, 0xbc4c6c2a'226399ef'8f6ebcfb'2016a439_u128}, + {Sign::POS, -130, 0xc5f57f59'c7f46155'aa8b6997'a402bf30_u128}, + {Sign::POS, -130, 0xcad2d6e7'b80bf914'2c507fb7'a3d0bf6a_u128}, + {Sign::POS, -130, 0xcfb62038'44b3209a'd0cb02f3'3f79c16c_u128}, + {Sign::POS, -130, 0xd98ec2ba'de71e539'58a98f2a'd65bee9b_u128}, + {Sign::POS, -130, 0xde8439c1'dec56877'4d57da94'5b5d0aaa_u128}, + {Sign::POS, -130, 0xe37fde37'807b84e3'4e9a750b'6b68781d_u128}, + {Sign::POS, -130, 0xe881bf93'2af3dac0'c524848e'3443e040_u128}, + {Sign::POS, -130, 0xf29877ff'38809091'3b020fa1'820c9492_u128}, + {Sign::POS, -130, 0xf7ad6f26'e7ff2ef7'54d2238f'75f969b1_u128}, + {Sign::POS, -130, 0xfcc8e365'9d9bcbec'ca0cdf30'1431b60f_u128}, + {Sign::POS, -129, 0x80f572b1'363487b9'f5bd0b5b'3479d5f4_u128}, + {Sign::POS, -129, 0x86216b3b'0b17188b'163ceae8'8f720f1e_u128}, + {Sign::POS, -129, 0x88bc7411'3f23def1'9c5a0fe3'96f40f1e_u128}, + {Sign::POS, -129, 0x8b5ae65d'67db9acd'f7a51681'26a58b9a_u128}, + {Sign::POS, -129, 0x8dfccb1a'd35ca6ed'5147bdb6'ddcaf59c_u128}, + {Sign::POS, -129, 0x90a22b68'75c6a1f7'ae91aeba'609c8877_u128}, + {Sign::POS, -129, 0x934b1089'a6dc93c1'df5bb3b6'0554e152_u128}, + {Sign::POS, -129, 0x95f783e6'e49a9cfa'4a5004f3'ef063313_u128}, + {Sign::POS, -129, 0x9b5b3bb5'f088b766'd878bbe3'd392be25_u128}, + {Sign::POS, -129, 0x9e1293b9'998c1daa'5b035eae'273a855f_u128}, + {Sign::POS, -129, 0xa0cda11e'af46390d'bb243827'3918db7e_u128}, + {Sign::POS, -129, 0xa38c6e13'8e20d831'f698298a'dddd7f32_u128}, + {Sign::POS, -129, 0xa64f04f0'b961df76'e4f5275c'2d15c21f_u128}, + {Sign::POS, -129, 0xa9157039'c51ebe70'8164c759'686a2209_u128}, + {Sign::POS, -129, 0xabdfba9e'468fd6f6'f72ea077'49ce6bd3_u128}, + {Sign::POS, -129, 0xaeadeefa'caf97d35'7dd6e688'ebb13b03_u128}, + {Sign::POS, -129, 0xb1801859'd56249dc'18ce51ff'f99479cd_u128}, + {Sign::POS, -129, 0xb45641f4'e350a0d3'2756eba0'0bc33978_u128}, + {Sign::POS, -129, 0xb7307735'78cb90b2'be1116c3'466beb6d_u128}, + {Sign::POS, -129, 0xba0ec3b6'33dd8b09'49dc60b2'b059a60b_u128}, + {Sign::POS, -129, 0xbcf13343'e7d9ec7d'2efd1778'1bb3afec_u128}, + {Sign::POS, -129, 0xbfd7d1de'c0a8df6f'37eda996'244bccb0_u128}, + {Sign::POS, -129, 0xc2c2abbb'6e5fd56f'33337789'd592e296_u128}, + {Sign::POS, -129, 0xc5b1cd44'596fa51e'1a18fb8f'9f9ef280_u128}, + {Sign::POS, -129, 0xc8a5431a'dfb44ca5'688ce7c1'a75e341a_u128}, + {Sign::POS, -129, 0xcb9d1a18'9ab56e76'2d7e9307'c70c0668_u128}, + {Sign::POS, -129, 0xcb9d1a18'9ab56e76'2d7e9307'c70c0668_u128}, + {Sign::POS, -129, 0xce995f50'af69d861'ef2f3f4f'861ad6a9_u128}, + {Sign::POS, -129, 0xd19a2011'27d3c645'7f9d79f5'1dcc7301_u128}, + {Sign::POS, -129, 0xd49f69e4'56cf1b79'5f53bd2e'406e66e7_u128}, + {Sign::POS, -129, 0xd7a94a92'466e833a'ad88bba7'd0cee8e0_u128}, + {Sign::POS, -129, 0xdab7d022'31484a92'96c20cca'6efe2ac5_u128}, + {Sign::POS, -129, 0xddcb08dc'0717d85b'f40a666c'87842843_u128}, + {Sign::POS, -129, 0xe0e30349'fd1cec80'7fe8e180'2aba24d6_u128}, + {Sign::POS, -129, 0xe0e30349'fd1cec80'7fe8e180'2aba24d6_u128}, + {Sign::POS, -129, 0xe3ffce3a'2aa64922'3eadb651'b49ac53a_u128}, + {Sign::POS, -129, 0xe72178c0'323a1a0f'304e1653'e71d9973_u128}, + {Sign::POS, -129, 0xea481236'f7d35baf'e9a767a8'0d6d97e8_u128}, + {Sign::POS, -129, 0xed73aa42'64b0ade9'4f91cf4b'33e42998_u128}, + {Sign::POS, -129, 0xed73aa42'64b0ade9'4f91cf4b'33e42998_u128}, + {Sign::POS, -129, 0xf0a450d1'39366ca6'fc66eb64'08ff6433_u128}, + {Sign::POS, -129, 0xf3da161e'ed6b9aaf'ac8d42f7'8d3e65d3_u128}, + {Sign::POS, -129, 0xf7150ab5'a09f27f4'5a470250'd40ebe90_u128}, + {Sign::POS, -129, 0xf7150ab5'a09f27f4'5a470250'd40ebe90_u128}, + {Sign::POS, -129, 0xfa553f70'18c966f2'b780a545'a1b54dcf_u128}, + {Sign::POS, -129, 0xfd9ac57b'd244217e'8f05924d'258c14c5_u128}, + {Sign::POS, -128, 0x8072d72d'903d588b'89d1b09c'70c4010a_u128}, + {Sign::POS, -128, 0x8072d72d'903d588b'89d1b09c'70c4010a_u128}, + {Sign::POS, -128, 0x821b05f3'b01d6774'030d58c3'f7e2ea1f_u128}, + {Sign::POS, -128, 0x83c5f829'9e2b4091'20f6fafe'8fbb68b9_u128}, + {Sign::POS, -128, 0x8573b716'82a7d21a'e21f9f89'c1ab80b2_u128}, + {Sign::POS, -128, 0x8573b716'82a7d21a'e21f9f89'c1ab80b2_u128}, + {Sign::POS, -128, 0x87244c30'8e670a66'01e005d0'6dbfa8f8_u128}, + {Sign::POS, -128, 0x88d7c11e'3ad53cdc'223111a7'07b6de2c_u128}, + {Sign::POS, -128, 0x88d7c11e'3ad53cdc'223111a7'07b6de2c_u128}, + {Sign::POS, -128, 0x8a8e1fb7'94b09134'2eb628db'a173c82d_u128}, + {Sign::POS, -128, 0x8c477207'91e53313'be2ad194'15fe25a5_u128}, + {Sign::POS, -128, 0x8c477207'91e53313'be2ad194'15fe25a5_u128}, + {Sign::POS, -128, 0x8e03c24d'73003959'bddae1cc'ce247838_u128}, + {Sign::POS, -128, 0x8fc31afe'30b2c6de'9b00bf16'7e95da67_u128}, + {Sign::POS, -128, 0x8fc31afe'30b2c6de'9b00bf16'7e95da67_u128}, + {Sign::POS, -128, 0x918586c5'f5e4bf01'9b92199e'd1a4bab1_u128}, + {Sign::POS, -128, 0x934b1089'a6dc93c1'df5bb3b6'0554e152_u128}, + {Sign::POS, -128, 0x934b1089'a6dc93c1'df5bb3b6'0554e152_u128}, + {Sign::POS, -128, 0x9513c368'76083695'f3cbc416'a2418012_u128}, + {Sign::POS, -128, 0x96dfaabd'86fa1646'be1188fb'c94e2f15_u128}, + {Sign::POS, -128, 0x96dfaabd'86fa1646'be1188fb'c94e2f15_u128}, + {Sign::POS, -128, 0x98aed221'a03458b6'1d2f8932'1647b358_u128}, + {Sign::POS, -128, 0x98aed221'a03458b6'1d2f8932'1647b358_u128}, + {Sign::POS, -128, 0x9a81456c'ec642e0f'e549f9aa'ea3cb5e1_u128}, + {Sign::POS, -128, 0x9c5710b8'cbb73a42'a2554b2d'd4619e63_u128}, + {Sign::POS, -128, 0x9c5710b8'cbb73a42'a2554b2d'd4619e63_u128}, + {Sign::POS, -128, 0x9e304061'b5fda919'30603d87'b6df81ad_u128}, + {Sign::POS, -128, 0x9e304061'b5fda919'30603d87'b6df81ad_u128}, + {Sign::POS, -128, 0xa00ce109'2e5498c3'67879c5a'30cd1242_u128}, + {Sign::POS, -128, 0xa00ce109'2e5498c3'67879c5a'30cd1242_u128}, + {Sign::POS, -128, 0xa1ecff97'c91e267b'0b7efae0'8e597e16_u128}, + {Sign::POS, -128, 0xa3d0a93f'45169a4a'83594fab'088c0d65_u128}, + {Sign::POS, -128, 0xa3d0a93f'45169a4a'83594fab'088c0d65_u128}, + {Sign::POS, -128, 0xa5b7eb7c'b860fb88'af6a62a0'dec6e073_u128}, + {Sign::POS, -128, 0xa5b7eb7c'b860fb88'af6a62a0'dec6e073_u128}, + {Sign::POS, -128, 0xa7a2d41a'd270c9d7'49362382'a768847a_u128}, + {Sign::POS, -128, 0xa7a2d41a'd270c9d7'49362382'a768847a_u128}, + {Sign::POS, -128, 0xa9917134'33c2b998'8ba4aea6'14d05701_u128}, + {Sign::POS, -128, 0xa9917134'33c2b998'8ba4aea6'14d05701_u128}, + {Sign::POS, -128, 0xab83d135'dc633301'7fe6607b'a902ef3c_u128}, + {Sign::POS, -128, 0xab83d135'dc633301'7fe6607b'a902ef3c_u128}, + {Sign::POS, -128, 0xad7a02e1'b24efd31'd60864fd'949b4bd3_u128}, + {Sign::POS, -128, 0xad7a02e1'b24efd31'd60864fd'949b4bd3_u128}, + {Sign::POS, -128, 0xaf741551'20c9011c'066d235e'e63073dd_u128}, + {Sign::POS, -128, 0xaf741551'20c9011c'066d235e'e63073dd_u128}, + {Sign::POS, 0, 0_u128}, +}; + +// Logarithm range reduction - Step 2: +// s(k) = 2^-18 round( 2^18 / (1 + k*2^-14) ) - 1 for k = -91 .. 96 +// Output range: +// [-0x1.1037c00000040271p-15 , 0x1.108480000008096cp-15] +LIBC_INLINE_VAR constexpr double S2[198] = { + 0x1.6ep-8, 0x1.6ap-8, 0x1.66p-8, 0x1.62p-8, 0x1.5dcp-8, + 0x1.59cp-8, 0x1.55cp-8, 0x1.51cp-8, 0x1.4dcp-8, 0x1.49cp-8, + 0x1.458p-8, 0x1.418p-8, 0x1.3d8p-8, 0x1.398p-8, 0x1.358p-8, + 0x1.318p-8, 0x1.2d8p-8, 0x1.294p-8, 0x1.254p-8, 0x1.214p-8, + 0x1.1d4p-8, 0x1.194p-8, 0x1.154p-8, 0x1.114p-8, 0x1.0dp-8, + 0x1.09p-8, 0x1.05p-8, 0x1.01p-8, 0x1.fap-9, 0x1.f2p-9, + 0x1.eap-9, 0x1.e2p-9, 0x1.d98p-9, 0x1.d18p-9, 0x1.c98p-9, + 0x1.c18p-9, 0x1.b98p-9, 0x1.b18p-9, 0x1.a98p-9, 0x1.a18p-9, + 0x1.998p-9, 0x1.91p-9, 0x1.89p-9, 0x1.81p-9, 0x1.79p-9, + 0x1.71p-9, 0x1.69p-9, 0x1.61p-9, 0x1.59p-9, 0x1.51p-9, + 0x1.49p-9, 0x1.41p-9, 0x1.388p-9, 0x1.308p-9, 0x1.288p-9, + 0x1.208p-9, 0x1.188p-9, 0x1.108p-9, 0x1.088p-9, 0x1.008p-9, + 0x1.f1p-10, 0x1.e1p-10, 0x1.d1p-10, 0x1.c1p-10, 0x1.b1p-10, + 0x1.a1p-10, 0x1.91p-10, 0x1.81p-10, 0x1.71p-10, 0x1.6p-10, + 0x1.5p-10, 0x1.4p-10, 0x1.3p-10, 0x1.2p-10, 0x1.1p-10, + 0x1p-10, 0x1.ep-11, 0x1.cp-11, 0x1.ap-11, 0x1.8p-11, + 0x1.6p-11, 0x1.4p-11, 0x1.2p-11, 0x1p-11, 0x1.cp-12, + 0x1.8p-12, 0x1.4p-12, 0x1p-12, 0x1.8p-13, 0x1p-13, + 0x1p-14, 0.0, -0x1p-14, -0x1p-13, -0x1.8p-13, + -0x1p-12, -0x1.4p-12, -0x1.8p-12, -0x1.cp-12, -0x1p-11, + -0x1.2p-11, -0x1.4p-11, -0x1.6p-11, -0x1.8p-11, -0x1.ap-11, + -0x1.cp-11, -0x1.ep-11, -0x1p-10, -0x1.1p-10, -0x1.2p-10, + -0x1.3p-10, -0x1.4p-10, -0x1.5p-10, -0x1.6p-10, -0x1.6fp-10, + -0x1.7fp-10, -0x1.8fp-10, -0x1.9fp-10, -0x1.afp-10, -0x1.bfp-10, + -0x1.cfp-10, -0x1.dfp-10, -0x1.efp-10, -0x1.ffp-10, -0x1.078p-9, + -0x1.0f8p-9, -0x1.178p-9, -0x1.1f8p-9, -0x1.278p-9, -0x1.2f8p-9, + -0x1.378p-9, -0x1.3fp-9, -0x1.47p-9, -0x1.4fp-9, -0x1.57p-9, + -0x1.5fp-9, -0x1.67p-9, -0x1.6fp-9, -0x1.77p-9, -0x1.7fp-9, + -0x1.87p-9, -0x1.8fp-9, -0x1.968p-9, -0x1.9e8p-9, -0x1.a68p-9, + -0x1.ae8p-9, -0x1.b68p-9, -0x1.be8p-9, -0x1.c68p-9, -0x1.ce8p-9, + -0x1.d68p-9, -0x1.dep-9, -0x1.e6p-9, -0x1.eep-9, -0x1.f6p-9, + -0x1.fep-9, -0x1.03p-8, -0x1.07p-8, -0x1.0bp-8, -0x1.0fp-8, + -0x1.12cp-8, -0x1.16cp-8, -0x1.1acp-8, -0x1.1ecp-8, -0x1.22cp-8, + -0x1.26cp-8, -0x1.2acp-8, -0x1.2e8p-8, -0x1.328p-8, -0x1.368p-8, + -0x1.3a8p-8, -0x1.3e8p-8, -0x1.428p-8, -0x1.464p-8, -0x1.4a4p-8, + -0x1.4e4p-8, -0x1.524p-8, -0x1.564p-8, -0x1.5a4p-8, -0x1.5ep-8, + -0x1.62p-8, -0x1.66p-8, -0x1.6ap-8, -0x1.6ep-8, -0x1.72p-8, + -0x1.75cp-8, -0x1.79cp-8, -0x1.7dcp-8, +}; + +// -log(r) for the second step, generated by SageMath with: +// +// for i in range(-91, 97): +// r = 2^-18 * round( 2^18 / (1 + i*2^(-14)) ); +// s, m, e = RealField(128)(r).log().sign_mantissa_exponent(); +// print("{Sign::POS," if (s == -1) else "{Sign::NEG,", e, ", +// format_hex(m), "},"); +LIBC_INLINE_VAR constexpr Float128 LOG_R2[198] = { + {Sign::NEG, -135, 0xb67dab2a'1a5742a4'a0e061c5'f7431c5e_u128}, + {Sign::NEG, -135, 0xb4807f24'af682939'5d5bfe7b'969ed6ec_u128}, + {Sign::NEG, -135, 0xb2834b35'b4d54d5f'4d08702d'dfabc23f_u128}, + {Sign::NEG, -135, 0xb0860f5c'eba9be95'd4d36650'8b9953df_u128}, + {Sign::NEG, -135, 0xae68f71a'a09e8847'ac18a289'f8f214a9_u128}, + {Sign::NEG, -135, 0xac6baaee'd676e8f1'd5b42054'abb88c45_u128}, + {Sign::NEG, -135, 0xaa6e56d8'7cd632d6'09809d58'ee484964_u128}, + {Sign::NEG, -135, 0xa870fad7'54bb8791'b9e6fc7c'72f06d73_u128}, + {Sign::NEG, -135, 0xa67396eb'1f231892'6f78d6d0'105c00e2_u128}, + {Sign::NEG, -135, 0xa4762b13'9d0626e7'028f7126'29209148_u128}, + {Sign::NEG, -135, 0xa258dfd1'0aedaa67'c98d898e'f172df02_u128}, + {Sign::NEG, -135, 0xa05b63a3'73e60a83'fcc37c3c'3062bfa1_u128}, + {Sign::NEG, -135, 0x9e5ddf89'cf42f501'3eb450db'05763c36_u128}, + {Sign::NEG, -135, 0x9c605383'ddf1b88c'7146a86f'd458b775_u128}, + {Sign::NEG, -135, 0x9a62bf91'60dcb286'c20a0c92'81474436_u128}, + {Sign::NEG, -135, 0x986523b2'18eb4ed6'cdc57316'ec4aebc3_u128}, + {Sign::NEG, -135, 0x96677fe5'c70207b9'c060dad7'4cef4273_u128}, + {Sign::NEG, -135, 0x9449f92d'2ff44633'ed8def1a'3e433499_u128}, + {Sign::NEG, -135, 0x924c4507'3220b5e0'3ce7a1f8'5c27b4fc_u128}, + {Sign::NEG, -135, 0x904e88f3'68fea63f'f2ca8934'49f7f2cb_u128}, + {Sign::NEG, -135, 0x8e50c4f1'956699ed'8d77d9fa'bd2853cf_u128}, + {Sign::NEG, -135, 0x8c52f901'782e20ec'93e828d7'5b58ded4_u128}, + {Sign::NEG, -135, 0x8a552522'd227d87a'9f9605b0'53c5acf0_u128}, + {Sign::NEG, -135, 0x88574955'64236ae0'62a14939'3bca7241_u128}, + {Sign::NEG, -135, 0x86398719'b66bac7c'aea6b56c'e89203d4_u128}, + {Sign::NEG, -135, 0x843b9aef'044e4dcc'0242bd86'd00609b2_u128}, + {Sign::NEG, -135, 0x823da6d4'c89c6927'daabf927'74bac84e_u128}, + {Sign::NEG, -135, 0x803faaca'c419abf2'a1c6f3fc'242ef8d0_u128}, + {Sign::NEG, -136, 0xfc834da1'6f0d9f57'a225ebc0'2e6d9dd4_u128}, + {Sign::NEG, -136, 0xf88735cc'c7433381'c33f6ad3'40ae18a9_u128}, + {Sign::NEG, -136, 0xf48b0e17'1249b6bc'70b2a4d3'8a242244_u128}, + {Sign::NEG, -136, 0xf08ed67f'd190e280'1d548190'48b811b0_u128}, + {Sign::NEG, -136, 0xec52ca07'ed95f236'9c21b650'afe9ede0_u128}, + {Sign::NEG, -136, 0xe85671ad'ecd28aac'935519c9'6d30e463_u128}, + {Sign::NEG, -136, 0xe45a0970'dc912ca7'ba88f6f2'e2672cfe_u128}, + {Sign::NEG, -136, 0xe05d9150'3e298bc8'0b1a8b84'657ae069_u128}, + {Sign::NEG, -136, 0xdc61094b'92ed70ef'ea3bff8d'197b20a1_u128}, + {Sign::NEG, -136, 0xd8647162'5c28b9e5'cdbb931d'6fecc249_u128}, + {Sign::NEG, -136, 0xd467c994'1b2158f5'd971d560'd5f00820_u128}, + {Sign::NEG, -136, 0xd06b11e0'51175493'75563561'244c090b_u128}, + {Sign::NEG, -136, 0xcc6e4a46'7f44c6fa'dc393c9a'3f3b380f_u128}, + {Sign::NEG, -136, 0xc831a4c6'f6fa709d'e6abe6e9'e4ee2096_u128}, + {Sign::NEG, -136, 0xc434bc61'24a0f16e'3ce3c822'8583a66e_u128}, + {Sign::NEG, -136, 0xc037c413'c61bfd93'b96a79f5'c5a4963a_u128}, + {Sign::NEG, -136, 0xbc3abbde'5c8d9bde'aaef2733'7008679f_u128}, + {Sign::NEG, -136, 0xb83da3c0'6911e509'a49a3fca'ddc8bc5a_u128}, + {Sign::NEG, -136, 0xb4407bb9'6cbf035a'e0254feb'785362fa_u128}, + {Sign::NEG, -136, 0xb04343c8'e8a53245'9893a4e2'5ab9dc95_u128}, + {Sign::NEG, -136, 0xac45fbee'5dcebe0b'5d8b0f40'a3708915_u128}, + {Sign::NEG, -136, 0xa848a429'4d40035d'5f4c11c2'c7a58c69_u128}, + {Sign::NEG, -136, 0xa44b3c79'37f76efd'b348cc5d'f706ffba_u128}, + {Sign::NEG, -136, 0xa04dc4dd'9eed7d60'9159f2c5'5a18befd_u128}, + {Sign::NEG, -136, 0x9c106456'3058bef3'bdfdee41'fe6a5a02_u128}, + {Sign::NEG, -136, 0x9812cbe3'46475a24'4580ddf8'9853254d_u128}, + {Sign::NEG, -136, 0x94152383'53489ffb'ac75e10d'61fc3ee8_u128}, + {Sign::NEG, -136, 0x90176b35'd83ce8e2'cad9b30b'29736155_u128}, + {Sign::NEG, -136, 0x8c19a2fa'55fe9b14'6f881deb'98fc45f3_u128}, + {Sign::NEG, -136, 0x881bcad0'4d622a3e'70a04b63'b7248c96_u128}, + {Sign::NEG, -136, 0x841de2b7'3f361722'b4823fb4'8035eddd_u128}, + {Sign::NEG, -136, 0x801feaae'ac42ef38'3364ccb5'b13cd47f_u128}, + {Sign::NEG, -137, 0xf843c56c'2a969897'e306977b'049f0ad5_u128}, + {Sign::NEG, -137, 0xf0479599'f617a843'e3c4d9e9'619bc045_u128}, + {Sign::NEG, -137, 0xe84b45e5'bc76702c'4356d525'b5e6432d_u128}, + {Sign::NEG, -137, 0xe04ed64e'7f14697a'7839dcd7'989339ab_u128}, + {Sign::NEG, -137, 0xd85246d3'3f47230b'4e21f045'ecb76f23_u128}, + {Sign::NEG, -137, 0xd0559772'fe5840b0'902e248d'd4ba9b28_u128}, + {Sign::NEG, -137, 0xc858c82c'bd857a72'a4444906'7ef92e01_u128}, + {Sign::NEG, -137, 0xc05bd8ff'7e009bd2'17926207'cc22e4e6_u128}, + {Sign::NEG, -137, 0xb85ec9ea'40ef8309'1c349622'f3fa5d82_u128}, + {Sign::NEG, -137, 0xafe1c6ec'e1a058dd'97fa2fd0'c9dc723e_u128}, + {Sign::NEG, -137, 0xa7e47606'048b1a65'983e8089'7cf1e60f_u128}, + {Sign::NEG, -137, 0x9fe70534'1d236102'7199cd06'ae5d39b3_u128}, + {Sign::NEG, -137, 0x97e97476'2c5e8f58'43cd18a7'2a051a96_u128}, + {Sign::NEG, -137, 0x8febc3cb'332616ff'7b6d1248'c3e1fd40_u128}, + {Sign::NEG, -137, 0x87edf332'325777c5'f5572a88'14c703af_u128}, + {Sign::NEG, -138, 0xffe00554'55887de0'26828c92'649a3a39_u128}, + {Sign::NEG, -138, 0xefe3e464'3a640cf3'82c550bd'1216d82a_u128}, + {Sign::NEG, -138, 0xdfe78392'14b4e8ae'da6959f7'f0e01bf0_u128}, + {Sign::NEG, -138, 0xcfeae2db'e5d6736d'da93e2fa'85a8f214_u128}, + {Sign::NEG, -138, 0xbfee023f'af0c2480'b47505bf'a5a03b06_u128}, + {Sign::NEG, -138, 0xaff0e1bb'718186ad'b1475a51'80a43520_u128}, + {Sign::NEG, -138, 0x9ff3814d'2e4a36b2'a8740b91'c95df537_u128}, + {Sign::NEG, -138, 0x8ff5e0f2'e661e1c6'57d895d3'5921b59c_u128}, + {Sign::NEG, -139, 0xfff00155'35588833'3c56c598'c659c2a3_u128}, + {Sign::NEG, -139, 0xdff3c0e4'97ea4eb1'2ef8ec33'ed9d782a_u128}, + {Sign::NEG, -139, 0xbff7008f'f5e0c257'379eba7e'6465ff63_u128}, + {Sign::NEG, -139, 0x9ff9c053'5073a370'3f972b78'3fcab757_u128}, + {Sign::NEG, -140, 0xfff80055'51558885'de026e27'1ee0549d_u128}, + {Sign::NEG, -140, 0xbffb8023'febc0c25'eceb47ea'01f6c632_u128}, + {Sign::NEG, -141, 0xfffc0015'54d55888'7333c578'57e1ed52_u128}, + {Sign::NEG, -142, 0xfffe0005'55455588'87dde026'fa704374_u128}, + {Sign::POS, 0, 0_u128}, + {Sign::POS, -141, 0x80010002'aab2aac4'44999abe'2fe2cc65_u128}, + {Sign::POS, -140, 0x8002000a'aaeaac44'4eef3815'81464ccb_u128}, + {Sign::POS, -140, 0xc0048024'01440c26'dfeb4850'85f6f454_u128}, + {Sign::POS, -139, 0x8004002a'acaac445'99abe3be'3a1c6e93_u128}, + {Sign::POS, -139, 0xa0064053'5a37a37a'6bc1e20e'ac8448b4_u128}, + {Sign::POS, -139, 0xc0090090'0a20c275'979eedc0'64c242fd_u128}, + {Sign::POS, -139, 0xe00c40e4'bd6e4efd'c72446cc'1bf728bd_u128}, + {Sign::POS, -138, 0x800800aa'baac446e'f381b821'bbb569e5_u128}, + {Sign::POS, -138, 0x900a20f3'19a3e273'569b26aa'a485ea5c_u128}, + {Sign::POS, -138, 0xa00c814d'7c6a37f8'2dcf56c8'3c80b028_u128}, + {Sign::POS, -138, 0xb00f21bb'e3e388ee'5f697682'84463b9b_u128}, + {Sign::POS, -138, 0xc0120240'510c284c'b48ea6c0'5e2773a1_u128}, + {Sign::POS, -138, 0xd01522dc'c4f87991'14d9d761'96d8043a_u128}, + {Sign::POS, -138, 0xe0188393'40d4f241'e016a611'a4415d72_u128}, + {Sign::POS, -138, 0xf01c2465'c5e61b6f'661e135f'49a47c40_u128}, + {Sign::POS, -137, 0x801002ab'2ac4499a'be6bf0fa'435e8383_u128}, + {Sign::POS, -137, 0x88121333'7898871e'9a31ba0c'bc030353_u128}, + {Sign::POS, -137, 0x901443cc'cd362c9f'54b57dfe'0c4c840f_u128}, + {Sign::POS, -137, 0x98169478'296fad41'7ad1e9c3'15328f7e_u128}, + {Sign::POS, -137, 0xa0190536'8e2389b3'1f3f686c'f3d6be22_u128}, + {Sign::POS, -137, 0xa81b9608'fc3c50ec'f105b66e'c4703ede_u128}, + {Sign::POS, -137, 0xb01e46f0'74b0a0f3'610848c6'8df4d233_u128}, + {Sign::POS, -137, 0xb7a0e9ed'7613acb0'2e0efddf'33a20464_u128}, + {Sign::POS, -137, 0xbfa3d900'8e042ffb'c2cdb3c7'50f127b4_u128}, + {Sign::POS, -137, 0xc7a6e82b'a36a7073'bd953378'6d3f4c49_u128}, + {Sign::POS, -137, 0xcfaa176f'b76c8eb1'82e237c9'a4d450e3_u128}, + {Sign::POS, -137, 0xd7ad66cd'cb3cbe14'c00b46a4'd0e3dfd0_u128}, + {Sign::POS, -137, 0xdfb0d646'e0194584'ea999c0d'f8546710_u128}, + {Sign::POS, -137, 0xe7b465db'f74c8032'cec6c2a9'ad974f4f_u128}, + {Sign::POS, -137, 0xefb8158e'122cde5a'2d2045da'1570a07c_u128}, + {Sign::POS, -137, 0xf7bbe55e'321ce603'6752e9b2'381e3edc_u128}, + {Sign::POS, -137, 0xffbfd54d'588b33c5'3c1ed527'28e00e40_u128}, + {Sign::POS, -136, 0x83e1f2ae'43793dc3'493b0d87'3fb9a340_u128}, + {Sign::POS, -136, 0x87e40ac6'5f6cc4a0'29e38750'c9d26893_u128}, + {Sign::POS, -136, 0x8be632ef'80e9a0df'aab9e832'7258ac3f_u128}, + {Sign::POS, -136, 0x8fe86b2a'28bf51b3'28bc403d'8a5f3c63_u128}, + {Sign::POS, -136, 0x93eab376'd7c36377'f720c1c9'7227fcdc_u128}, + {Sign::POS, -136, 0x97ed0bd6'0ed17018'6ad9a3e3'd11b66c1_u128}, + {Sign::POS, -136, 0x9bef7448'4ecb1f6c'edb27b79'c90b4019_u128}, + {Sign::POS, -136, 0x9fb1c4cd'27012e19'a092a0d7'ab21722a_u128}, + {Sign::POS, -136, 0xa3b44c65'b71c2d85'535d52f0'939a4d02_u128}, + {Sign::POS, -136, 0xa7b6e412'cadcb3dc'90a57e11'edc1864e_u128}, + {Sign::POS, -136, 0xabb98bd4'e33c4381'68e9c901'60031159_u128}, + {Sign::POS, -136, 0xafbc43ac'813a6ea3'bf60594f'929adeb8_u128}, + {Sign::POS, -136, 0xb3bf0b9a'25dcd7a2'8a421588'86775205_u128}, + {Sign::POS, -136, 0xb7c1e39e'522f316d'1ab45417'663dee9e_u128}, + {Sign::POS, -136, 0xbbc4cbb9'87433fe4'6c51ae3c'e1aea68a_u128}, + {Sign::POS, -136, 0xbfc7c3ec'4630d83c'7c52ae8b'40ebabb7_u128}, + {Sign::POS, -136, 0xc3cacc37'1015e15d'a857126f'7cfaaa67_u128}, + {Sign::POS, -136, 0xc7cde49a'66165446'14d05662'cd29464a_u128}, + {Sign::POS, -136, 0xcb90da16'44d29bb7'8379db06'ef3cd6bb_u128}, + {Sign::POS, -136, 0xcf9411aa'99ddb7de'9025f4c6'7dd38bb6_u128}, + {Sign::POS, -136, 0xd3975958'f681086d'd6f8a61c'892032ee_u128}, + {Sign::POS, -136, 0xd79ab121'dbf8714c'9a2f20b4'e2332d47_u128}, + {Sign::POS, -136, 0xdb9e1905'cb85ea59'3c767d61'f51d375b_u128}, + {Sign::POS, -136, 0xdfa19105'46717fca'd4b2bd65'bb25493c_u128}, + {Sign::POS, -136, 0xe3a51920'ce095292'c96c1254'a30ef91f_u128}, + {Sign::POS, -136, 0xe7a8b158'e3a198be'73e324ce'0946b214_u128}, + {Sign::POS, -136, 0xebac59ae'08949dd8'cacd125a'12bac62c_u128}, + {Sign::POS, -136, 0xef6fd620'b2b7a503'cafdc272'27b71eaa_u128}, + {Sign::POS, -136, 0xf3739daf'959aaafc'688d4282'f6026aa3_u128}, + {Sign::POS, -136, 0xf777755d'03f4e0b6'e54e9e38'04464cdd_u128}, + {Sign::POS, -136, 0xfb7b5d29'7f388a12'cb78b383'f4b59dce_u128}, + {Sign::POS, -136, 0xff7f5515'88de024f'ee055fc5'15062c04_u128}, + {Sign::POS, -135, 0x81c1ae90'd131de38'207812b4'3382acdd_u128}, + {Sign::POS, -135, 0x83c3baa7'26a721cc'dc90c4c4'b61f3a87_u128}, + {Sign::POS, -135, 0x85c5cece'05941dbc'1a03f13f'b2c978b1_u128}, + {Sign::POS, -135, 0x87c7eb05'aec1304f'b36f282e'83a7dc36_u128}, + {Sign::POS, -135, 0x89a9eccd'56a980c0'd82a4661'6d4c393f_u128}, + {Sign::POS, -135, 0x8bac18a6'40185360'bc6ff847'13c9babd_u128}, + {Sign::POS, -135, 0x8dae4c90'b22574f4'9f7942a5'16fc2d8a_u128}, + {Sign::POS, -135, 0x8fb0888c'eda546ab'15e50cfd'9b29b427_u128}, + {Sign::POS, -135, 0x91b2cc9b'336f3718'9f465296'ae7dd49a_u128}, + {Sign::POS, -135, 0x93b518bb'c45dc268'b49c1eb9'b348e6e4_u128}, + {Sign::POS, -135, 0x95b76cee'e14e728e'daa320cd'64c9d9c7_u128}, + {Sign::POS, -135, 0x9799a333'de49b963'75a91950'ffe1e3b5_u128}, + {Sign::POS, -135, 0x999c070b'a32068cd'5c6abcbf'43f03f14_u128}, + {Sign::POS, -135, 0x9b9e72f6'b295ad4f'5a9e7f26'5d1ed157_u128}, + {Sign::POS, -135, 0x9da0e6f5'4d9318fd'efeb98d0'2a195c17_u128}, + {Sign::POS, -135, 0x9fa36307'b5054ca8'2aa503a3'110ab5a7_u128}, + {Sign::POS, -135, 0xa1a5e72e'29dbf808'd0fe7e05'869eb825_u128}, + {Sign::POS, -135, 0xa3884a68'a750cb10'e80a28f4'e1e500d2_u128}, + {Sign::POS, -135, 0xa58ade36'aeef9f0b'53106415'1ca6e30b_u128}, + {Sign::POS, -135, 0xa78d7a19'82c4b08f'27c01ffa'8e2e3c4b_u128}, + {Sign::POS, -135, 0xa9901e11'63cbbbf5'7ba9408d'c857d568_u128}, + {Sign::POS, -135, 0xab92ca1e'93038d76'104d1e33'31d3b4fa_u128}, + {Sign::POS, -135, 0xad957e41'516e0158'9343c846'fcdf9137_u128}, + {Sign::POS, -135, 0xaf780e79'b2514889'3977e89a'ec59bfa2_u128}, + {Sign::POS, -135, 0xb17ad246'ef3713bc'913d4e3d'c55c3e6e_u128}, + {Sign::POS, -135, 0xb37d9e2a'7a56b09d'777b52a9'e70d8bcc_u128}, + {Sign::POS, -135, 0xb5807224'94be0c91'55de916f'd30591de_u128}, + {Sign::POS, -135, 0xb7834e35'7f7e2600'e79cfb37'be2861e4_u128}, + {Sign::POS, -135, 0xb986325d'7bab0c89'90983104'd3805389_u128}, + {Sign::POS, -135, 0xbb68ef9c'254aa378'59e3b2ec'71ce64f4_u128}, + {Sign::POS, -135, 0xbd6be371'8c77636f'e83183bf'3dd612ef_u128}, + {Sign::POS, -135, 0xbf6edf5e'c44d9d35'c4e3b0ac'2fd52b7f_u128}, +}; + +// Logarithm range reduction - Step 3: +// s(k) = 2^-21 round( 2^21 / (1 + k*2^-21) ) - 1 for k = -69 .. 69 +// Output range: +// [-0x1.012bb800000800114p-22, 0x1p-22 ] +LIBC_INLINE_VAR constexpr double S3[139] = { + 0x1.14p-15, 0x1.1p-15, 0x1.0cp-15, 0x1.08p-15, 0x1.04p-15, 0x1p-15, + 0x1.f8p-16, 0x1.fp-16, 0x1.e8p-16, 0x1.ep-16, 0x1.d8p-16, 0x1.dp-16, + 0x1.c8p-16, 0x1.cp-16, 0x1.b8p-16, 0x1.bp-16, 0x1.a8p-16, 0x1.ap-16, + 0x1.98p-16, 0x1.9p-16, 0x1.88p-16, 0x1.8p-16, 0x1.78p-16, 0x1.7p-16, + 0x1.68p-16, 0x1.6p-16, 0x1.58p-16, 0x1.5p-16, 0x1.48p-16, 0x1.4p-16, + 0x1.38p-16, 0x1.3p-16, 0x1.28p-16, 0x1.2p-16, 0x1.18p-16, 0x1.1p-16, + 0x1.08p-16, 0x1p-16, 0x1.fp-17, 0x1.ep-17, 0x1.dp-17, 0x1.cp-17, + 0x1.bp-17, 0x1.ap-17, 0x1.9p-17, 0x1.8p-17, 0x1.7p-17, 0x1.6p-17, + 0x1.5p-17, 0x1.4p-17, 0x1.3p-17, 0x1.2p-17, 0x1.1p-17, 0x1p-17, + 0x1.ep-18, 0x1.cp-18, 0x1.ap-18, 0x1.8p-18, 0x1.6p-18, 0x1.4p-18, + 0x1.2p-18, 0x1p-18, 0x1.cp-19, 0x1.8p-19, 0x1.4p-19, 0x1p-19, + 0x1.8p-20, 0x1p-20, 0x1p-21, 0.0, -0x1p-21, -0x1p-20, + -0x1.8p-20, -0x1p-19, -0x1.4p-19, -0x1.8p-19, -0x1.cp-19, -0x1p-18, + -0x1.2p-18, -0x1.4p-18, -0x1.6p-18, -0x1.8p-18, -0x1.ap-18, -0x1.cp-18, + -0x1.ep-18, -0x1p-17, -0x1.1p-17, -0x1.2p-17, -0x1.3p-17, -0x1.4p-17, + -0x1.5p-17, -0x1.6p-17, -0x1.7p-17, -0x1.8p-17, -0x1.9p-17, -0x1.ap-17, + -0x1.bp-17, -0x1.cp-17, -0x1.dp-17, -0x1.ep-17, -0x1.fp-17, -0x1p-16, + -0x1.08p-16, -0x1.1p-16, -0x1.18p-16, -0x1.2p-16, -0x1.28p-16, -0x1.3p-16, + -0x1.38p-16, -0x1.4p-16, -0x1.48p-16, -0x1.5p-16, -0x1.58p-16, -0x1.6p-16, + -0x1.68p-16, -0x1.7p-16, -0x1.78p-16, -0x1.8p-16, -0x1.88p-16, -0x1.9p-16, + -0x1.98p-16, -0x1.ap-16, -0x1.a8p-16, -0x1.bp-16, -0x1.b8p-16, -0x1.cp-16, + -0x1.c8p-16, -0x1.dp-16, -0x1.d8p-16, -0x1.ep-16, -0x1.e8p-16, -0x1.fp-16, + -0x1.f8p-16, -0x1p-15, -0x1.04p-15, -0x1.08p-15, -0x1.0cp-15, -0x1.1p-15, + -0x1.14p-15, +}; + +// -log(r) for the third step, generated by SageMath with: +// +// for i in range(-69, 70): +// r = 2^-21 * round( 2^21 / (1 + i*2^(-21)) ); +// s, m, e = RealField(128)(r).log().sign_mantissa_exponent(); +// print("{Sign::POS," if (s == -1) else "{Sign::NEG,", e, ", +// format_hex(m), "},"); +LIBC_INLINE_VAR constexpr Float128 LOG_R3[139] = { + {Sign::NEG, -142, 0x89ff6b38'd5de2622'e39d3faf'42340ed7_u128}, + {Sign::NEG, -142, 0x87ff6f80'ccb40f16'7ff33266'82c02485_u128}, + {Sign::NEG, -142, 0x85ff73b8'c3cdf731'5caf4fbe'343cf928_u128}, + {Sign::NEG, -142, 0x83ff77e0'bb2ade79'cdb6e554'348f7fe8_u128}, + {Sign::NEG, -142, 0x81ff7bf8'b2c9c4f6'0ef009c2'457de25d_u128}, + {Sign::NEG, -143, 0xffff0001'55535558'8883333c'57b57c74_u128}, + {Sign::NEG, -143, 0xfbff07f1'45931f44'f32668f3'9c70d183_u128}, + {Sign::NEG, -143, 0xf7ff0fc1'3650e7bd'459a73c6'a6486fe3_u128}, + {Sign::NEG, -143, 0xf3ff1771'278aaecd'37b18cca'7dd3a29f_u128}, + {Sign::NEG, -143, 0xefff1f01'193e7480'513f610d'21bcfc78_u128}, + {Sign::NEG, -143, 0xebff2671'0b6a38e1'ea190b95'c0690b7b_u128}, + {Sign::NEG, -143, 0xe7ff2dc0'fe0bfbfd'2a150f64'f0ad1743_u128}, + {Sign::NEG, -143, 0xe3ff34f0'f121bddd'090b5174'e995e9d1_u128}, + {Sign::NEG, -143, 0xdfff3c00'e4a97e8c'4ed512b9'b93ea2bf_u128}, + {Sign::NEG, -143, 0xdbff42f0'd8a13e15'934cea21'7ab794a2_u128}, + {Sign::NEG, -143, 0xd7ff49c0'cd06fc83'3e4ebe94'8afd2c76_u128}, + {Sign::NEG, -143, 0xd3ff5070'c1d8b9df'87b7c0f5'bcfee2e1_u128}, + {Sign::NEG, -143, 0xcfff5700'b7147634'77666622'8cb6371b_u128}, + {Sign::NEG, -143, 0xcbff5d70'acb8318b'e53a60f3'514db358_u128}, + {Sign::NEG, -143, 0xc7ff63c0'a2c1ebef'79149c3b'6e57fa86_u128}, + {Sign::NEG, -143, 0xc3ff69f0'992fa568'aad734c9'8416df2a_u128}, + {Sign::NEG, -143, 0xbfff7000'8fff5e00'c2657367'9ed28334_u128}, + {Sign::NEG, -143, 0xbbff75f0'872f15c0'd7a3c6db'6540809f_u128}, + {Sign::NEG, -143, 0xb7ff7bc0'7ebcccb1'd277bde6'45fb1aad_u128}, + {Sign::NEG, -143, 0xb3ff8170'76a682dc'6ac80145'a4087793_u128}, + {Sign::NEG, -143, 0xafff8700'6eea3849'287c4db3'0271e265_u128}, + {Sign::NEG, -143, 0xabff8c70'6785ed00'637d6de4'2eeb151e_u128}, + {Sign::NEG, -143, 0xa7ff91c0'6077a10a'43b5348b'6b898a8c_u128}, + {Sign::NEG, -143, 0xa3ff96f0'59bd546e'c10e7657'978bd7f6_u128}, + {Sign::NEG, -143, 0x9fff9c00'53550735'a37503f4'57310e59_u128}, + {Sign::NEG, -143, 0x9bffa0f0'4d3cb966'82d5a40a'3aa022ff_u128}, + {Sign::NEG, -143, 0x97ffa5c0'47726b08'c71e0d3e'e3df5f4d_u128}, + {Sign::NEG, -143, 0x93ffaa70'41f41c23'a83ce035'2bdbd79b_u128}, + {Sign::NEG, -143, 0x8fffaf00'3cbfccbe'2e21a18d'4680e8e4_u128}, + {Sign::NEG, -143, 0x8bffb370'37d37cdf'30bcb3e4'e5dfbd28_u128}, + {Sign::NEG, -143, 0x87ffb7c0'332d2c8d'57ff51d7'5c66d64a_u128}, + {Sign::NEG, -143, 0x83ffbbf0'2ecadbcf'1bdb87fd'be299f43_u128}, + {Sign::NEG, -144, 0xffff8000'55551555'88885dde'02700703_u128}, + {Sign::NEG, -144, 0xf7ff87e0'4d94724c'd259ca80'3a0c1870_u128}, + {Sign::NEG, -144, 0xefff8f80'464fce8f'e5141308'51c7070a_u128}, + {Sign::NEG, -144, 0xe7ff96e0'3f832a2a'30a16898'f3073a64_u128}, + {Sign::NEG, -144, 0xdfff9e00'392a8526'c4ed6451'7b2949ce_u128}, + {Sign::NEG, -144, 0xd7ffa4e0'3341df90'51e4fb4e'32cf6350_u128}, + {Sign::NEG, -144, 0xcfffab80'2dc53971'277672a8'8350bcce_u128}, + {Sign::NEG, -144, 0xc7ffb1e0'28b092d3'35915377'2a490f06_u128}, + {Sign::NEG, -144, 0xbfffb800'23ffebc0'0c265ece'6b481a0e_u128}, + {Sign::NEG, -144, 0xb7ffbde0'1faf4440'db2781c0'3fa132f6_u128}, + {Sign::NEG, -144, 0xafffc380'1bba9c5e'7287c95c'845ada33_u128}, + {Sign::NEG, -144, 0xa7ffc8e0'181df421'423b56b1'263e5a77_u128}, + {Sign::NEG, -144, 0x9fffce00'14d54b91'5a3752ca'4c076fa3_u128}, + {Sign::NEG, -144, 0x97ffd2e0'11dca2b6'6a71e2b2'7eb3f573_u128}, + {Sign::NEG, -144, 0x8fffd780'0f2ff997'c2e21b72'cff39d8f_u128}, + {Sign::NEG, -144, 0x87ffdbe0'0ccb503c'537ff612'feb7ac9e_u128}, + {Sign::NEG, -145, 0xffffc000'15554d55'58888733'33c57c18_u128}, + {Sign::NEG, -145, 0xefffc7c0'1193f9d1'fa514218'42311c42_u128}, + {Sign::NEG, -145, 0xdfffcf00'0e4aa5fa'2c4ed6de'475b942c_u128}, + {Sign::NEG, -145, 0xcfffd5c0'0b7151d8'ce77678c'bb6fcb88_u128}, + {Sign::NEG, -145, 0xbfffdc00'08fffd78'00c26629'a679ed3b_u128}, + {Sign::NEG, -145, 0xafffe1c0'06eea8e1'23287cb9'd3072728_u128}, + {Sign::NEG, -145, 0x9fffe700'0535541c'd5a37540'fd057315_u128}, + {Sign::NEG, -145, 0x8fffebc0'03cbff32'f82e21c1'fce36810_u128}, + {Sign::NEG, -146, 0xffffe000'05555455'5588887d'dde02702_u128}, + {Sign::NEG, -146, 0xdfffe780'0392aa14'9ac4ed72'adf5b295_u128}, + {Sign::NEG, -146, 0xbfffee00'023fffaf'000c2664'8066b482_u128}, + {Sign::NEG, -146, 0x9ffff380'014d552e'455a3754'b292c077_u128}, + {Sign::NEG, -147, 0xfffff000'01555535'55588888'33333c58_u128}, + {Sign::NEG, -147, 0xbffff700'008ffff5'e000c266'5736679f_u128}, + {Sign::NEG, -148, 0xfffff800'00555551'55558888'85ddde02_u128}, + {Sign::NEG, -149, 0xfffffc00'00155554'd5555888'88733334_u128}, + {Sign::POS, 0, 0_u128}, + {Sign::POS, -148, 0x80000200'000aaaaa'eaaaac44'444eeeef_u128}, + {Sign::POS, -147, 0x80000400'002aaaac'aaaac444'459999ac_u128}, + {Sign::POS, -147, 0xc0000900'0090000a'2000c266'7596679f_u128}, + {Sign::POS, -146, 0x80000800'00aaaaba'aaac4444'6eeef381_u128}, + {Sign::POS, -146, 0xa0000c80'014d557c'655a3755'f81815cc_u128}, + {Sign::POS, -146, 0xc0001200'02400051'000c2668'4c66b482_u128}, + {Sign::POS, -146, 0xe0001880'0392ab40'bac4ed7c'40fb07eb_u128}, + {Sign::POS, -145, 0x80001000'02aaab2a'aac44449'999abe2c_u128}, + {Sign::POS, -145, 0x90001440'03cc00cd'082e21d7'9cbb6812_u128}, + {Sign::POS, -145, 0xa0001900'0535568d'd5a37569'adb01dc3_u128}, + {Sign::POS, -145, 0xb0001e40'06eeac74'33287d01'e8c9d1d9_u128}, + {Sign::POS, -145, 0xc0002400'09000288'00c266a3'2679ed48_u128}, + {Sign::POS, -145, 0xd0002a40'0b7158d1'de776851'22b2764b_u128}, + {Sign::POS, -145, 0xe0003100'0e4aaf5b'2c4ed810'a8063f03_u128}, + {Sign::POS, -145, 0xf0003840'1194062e'0a5143e7'be891c8f_u128}, + {Sign::POS, -144, 0x80002000'0aaaaeaa'ac4444ee'ef3813a1_u128}, + {Sign::POS, -144, 0x88002420'0ccb5a6e'5b7ff7fe'1339025b_u128}, + {Sign::POS, -144, 0x90002880'0f300668'42e21e26'caf39e33_u128}, + {Sign::POS, -144, 0x98002d20'11dcb29e'f271e66f'a5554bc6_u128}, + {Sign::POS, -144, 0xa0003200'14d55f19'5a3757e0'615cc676_u128}, + {Sign::POS, -144, 0xa8003720'181e0bde'ca3b5d82'10ca5cab_u128}, + {Sign::POS, -144, 0xb0003c80'1bbab8f6'f287d25f'3cb032bb_u128}, + {Sign::POS, -144, 0xb8004220'1faf6669'e3278d84'0be28cdb_u128}, + {Sign::POS, -144, 0xc0004800'24001440'0c266dfe'6b482076_u128}, + {Sign::POS, -144, 0xc8004e20'28b0c282'3d9166de'380a6d3d_u128}, + {Sign::POS, -144, 0xd0005480'2dc57139'a7768b35'6ba61e4b_u128}, + {Sign::POS, -144, 0xd8005b20'3342206f'd9e51a18'49db73c1_u128}, + {Sign::POS, -144, 0xe0006200'392ad02e'c4ed8a9d'907eb521_u128}, + {Sign::POS, -144, 0xe8006920'3f838080'b8a197de'a928acd7_u128}, + {Sign::POS, -144, 0xf0007080'46503170'65144cf7'dcc72d3b_u128}, + {Sign::POS, -144, 0xf8007820'4d94e308'da5a1108'890d9f6a_u128}, + {Sign::POS, -143, 0x80004000'2aaacaaa'c4445999'abe2ce2c_u128}, + {Sign::POS, -143, 0x84004410'2ecb2431'1fdbbb4f'3bffc832_u128}, + {Sign::POS, -143, 0x88004840'332d7e1d'97ff8f39'ec91b4ee_u128}, + {Sign::POS, -143, 0x8c004c90'37d3d876'74bcfcf0'b3f0a95d_u128}, + {Sign::POS, -143, 0x90005100'3cc03342'2e21f80c'a6813aff_u128}, + {Sign::POS, -143, 0x94005590'41f48e87'6c3d4629'170ce87f_u128}, + {Sign::POS, -143, 0x98005a40'4772ea4d'071e84e3'b80a8881_u128}, + {Sign::POS, -143, 0x9c005f10'4d3d469a'06d62fdc'bdd6bec3_u128}, + {Sign::POS, -143, 0xa0006400'5355a375'a375a6b7'01dc77c0_u128}, + {Sign::POS, -143, 0xa4006910'59be00e7'450f3318'26ad6b05_u128}, + {Sign::POS, -143, 0xa8006e40'60785ef6'83b60ea8'bd0aa459_u128}, + {Sign::POS, -143, 0xac007390'6786bdab'277e6914'69dd13f5_u128}, + {Sign::POS, -143, 0xb0007900'6eeb1d0d'287d6e0a'0d1e25eb_u128}, + {Sign::POS, -143, 0xb4007e90'76a77d24'aec94b3b'e9b060f5_u128}, + {Sign::POS, -143, 0xb8008440'7ebdddfa'1279365f'ce280cce_u128}, + {Sign::POS, -143, 0xbc008a10'87303f95'dba5732f'3e83e04a_u128}, + {Sign::POS, -143, 0xc0009000'9000a200'c2675967'9ed5b754_u128}, + {Sign::POS, -143, 0xc4009610'99310543'aed95aca'5edb5109_u128}, + {Sign::POS, -143, 0xc8009c40'a2c36967'b917091d'2687160f_u128}, + {Sign::POS, -143, 0xcc00a290'acb9ce76'293d1c2a'0378e75d_u128}, + {Sign::POS, -143, 0xd000a900'b7163478'776977bf'9766f5a7_u128}, + {Sign::POS, -143, 0xd400af90'c1da9b78'4bbb31b1'4776a18b_u128}, + {Sign::POS, -143, 0xd800b640'cd09037f'7e5297d7'6c8564ba_u128}, + {Sign::POS, -143, 0xdc00bd10'd8a36c98'1751360f'8461c447_u128}, + {Sign::POS, -143, 0xe000c400'e4abd6cc'4ed9dc3c'63f44c41_u128}, + {Sign::POS, -143, 0xe400cb10'f1244226'8d10a446'6a5894d5_u128}, + {Sign::POS, -143, 0xe800d240'fe0eaeb1'6a1af81b'b4e6510e_u128}, + {Sign::POS, -143, 0xec00d991'0b6d1c77'ae1f97b0'542a677a_u128}, + {Sign::POS, -143, 0xf000e101'19418b84'51469efe'81d014cc_u128}, + {Sign::POS, -143, 0xf400e891'278dfbe2'7bb98c06'd77a18b4_u128}, + {Sign::POS, -143, 0xf800f041'36546d9d'85a344d0'868bed17_u128}, + {Sign::POS, -143, 0xfc00f811'4596e0c0'f7301d69'90e307cc_u128}, + {Sign::POS, -142, 0x80008000'aaabaaac'4446eef3'8140138f_u128}, + {Sign::POS, -142, 0x82008408'b2cbe5b8'10f5e432'96105497_u128}, + {Sign::POS, -142, 0x84008820'bb2d2189'edbd4f83'ef63f730_u128}, + {Sign::POS, -142, 0x86008c48'c3d05e27'feb654fd'541c638e_u128}, + {Sign::POS, -142, 0x88009080'ccb69b98'7ffadeb8'882f7674_u128}, + {Sign::POS, -142, 0x8a0094c8'd5e0d9e1'c5a59fd3'6bd44397_u128}, +}; + +// Minimax polynomial generated by Sollya with: +// > P = fpminimax((log(1 + x) - x)/x^2, 3, [|1, 128...|], +// [-0x1.01928p-22 , 0x1p-22]); +// > P; +// > dirtyinfnorm(log(1 + x)/x - 1 - x*P, [-0x1.01928p-22 , 0x1p-22]); +// 0x1.ce1e...p-116 +LIBC_INLINE_VAR constexpr Float128 BIG_COEFFS[4]{ + {Sign::POS, -130, 0xccccccd7'4818e397'7ed78465'd460315b_u128}, + {Sign::NEG, -129, 0x80000000'000478b0'c6388a23'871ce156_u128}, + {Sign::POS, -129, 0xaaaaaaaa'aaaaaaaa'aa807bd8'67763262_u128}, + {Sign::NEG, -128, 0x80000000'00000000'00000000'00000000_u128}, +}; + +[[maybe_unused]] LIBC_INLINE static double +log1p_accurate(int e_x, int index, fputil::DoubleDouble m_x) { + Float128 e_x_f128(static_cast<float>(e_x)); + Float128 sum = fputil::quick_mul(LOG_2, e_x_f128); + sum = fputil::quick_add(sum, LOG_R1[index]); + + // fputil::DoubleDouble v4; + Float128 v = fputil::quick_add(Float128(m_x.hi), Float128(m_x.lo)); + + // Skip 2nd range reduction step if |m_x| <= 2^-15. + if (m_x.hi > 0x1p-15 || m_x.hi < -0x1p-15) { + // Range reduction - Step 2. + // For k such that: k * 2^-14 - 2^-15 <= m_x.hi < k * 2^-14 + 2^-15, + // Let s_k = 2^-18 * round( 2^18 / (1 + k*2^-14) ) - 1 + // Then the 2nd reduced argument is: + // (1 + s_k) * (1 + m_x) - 1 = + // = s_k + m_x + s_k * m_x + // Output range: + // -0x1.1037c00000040271p-15 <= v2.hi + v2.lo <= 0x1.108480000008096cp-15 + int idx2 = static_cast<int>(0x1p14 * (m_x.hi + (91 * 0x1p-14 + 0x1p-15))); + sum = fputil::quick_add(sum, LOG_R2[idx2]); + Float128 s2 = Float128(S2[idx2]); + v = fputil::quick_add(fputil::quick_add(v, s2), fputil::quick_mul(v, s2)); + } + + // Skip 3rd range reduction step if |v| <= 2^-22. + if (v.exponent > -150) { + // Range reduction - Step 3. + // For k such that: k * 2^-21 - 2^-22 <= v2.hi < k * 2^-21 + 2^-22, + // Let s_k = 2^-21 * round( 2^21 / (1 + k*2^-21) ) - 1 + // Then the 3rd reduced argument is: + // v3.hi + v3.lo ~ (1 + s_k) * (1 + v2.hi + v2.lo) - 1 + // Output range: + // -0x1.012bb800000800114p-22 <= v3.hi + v3.lo <= 0x1p-22 + int idx3 = + static_cast<int>(0x1p21 * (double(v) + (69 * 0x1p-21 + 0x1p-22))); + sum = fputil::quick_add(sum, LOG_R3[idx3]); + Float128 s3 = Float128(S3[idx3]); + v = fputil::quick_add(fputil::quick_add(v, s3), fputil::quick_mul(v, s3)); + } + + // Polynomial approximation + Float128 p = fputil::quick_mul(v, BIG_COEFFS[0]); + p = fputil::quick_mul(v, fputil::quick_add(p, BIG_COEFFS[1])); + p = fputil::quick_mul(v, fputil::quick_add(p, BIG_COEFFS[2])); + p = fputil::quick_mul(v, fputil::quick_add(p, BIG_COEFFS[3])); + p = fputil::quick_add(v, fputil::quick_mul(v, p)); + + Float128 r = fputil::quick_add(sum, p); + + return static_cast<double>(r); +} +#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS + +} // namespace log1p_internal + +LIBC_INLINE static double log1p(double x) { + using namespace log1p_internal; + using FPBits_t = typename fputil::FPBits<double>; + + constexpr int EXP_BIAS = FPBits_t::EXP_BIAS; + constexpr int FRACTION_LEN = FPBits_t::FRACTION_LEN; + FPBits_t xbits(x); + uint64_t x_u = xbits.uintval(); + + fputil::DoubleDouble x_dd{0.0, 0.0}; + + uint16_t x_exp = xbits.get_biased_exponent(); + + if (x_exp >= EXP_BIAS) { + // |x| >= 1 + if (LIBC_UNLIKELY(x_u >= 0x4650'0000'0000'0000ULL)) { + // x >= 2^102 or x is negative, inf, or NaN + if (LIBC_UNLIKELY(x_u > FPBits_t::max_normal().uintval())) { + // x <= -1.0 or x is Inf or NaN + if (x_u == 0xbff0'0000'0000'0000ULL) { + // x = -1.0 + fputil::set_errno_if_required(ERANGE); + fputil::raise_except_if_required(FE_DIVBYZERO); + return FPBits_t::inf(Sign::NEG).get_val(); + } + if (xbits.is_neg() && !xbits.is_nan()) { + // x < -1.0 + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_INVALID); + return FPBits_t::quiet_nan().get_val(); + } + // x is +Inf or NaN + if (xbits.is_inf() && xbits.is_pos()) + return x; + + if (xbits.is_signaling_nan()) + fputil::raise_except_if_required(FE_INVALID); + return FPBits_t::quiet_nan().get_val(); + } + x_dd.hi = x; + } else { + x_dd = fputil::exact_add(x, 1.0); + } + } else { + // |x| < 1 + if (LIBC_UNLIKELY(xbits.get_biased_exponent() < + EXP_BIAS - FRACTION_LEN - 1)) { + // Quick return when |x| < 2^-53. + // Since log(1 + x) = x - x^2/2 + x^3/3 - ..., + // for |x| < 2^-53, + // x > log(1 + x) > x - x^2 > x(1 - 2^-54) > x - ulp(x)/2 + // Thus, + // log(1 + x) = nextafter(x, -inf) for FE_DOWNWARD, or + // FE_TOWARDZERO and x > 0, + // = x otherwise. + if (x + x == 0.0) + return x + x; // Handle FTZ/DAZ correctly. + + volatile float tp = 1.0f; + volatile float tn = -1.0f; + bool rdp = (tp - 0x1p-25f != tp); + bool rdn = (tn - 0x1p-24f != tn); + + if (x > 0 && rdp) { + return FPBits_t(x_u - 1).get_val(); + } + + if (x < 0 && rdn) { + return FPBits_t(x_u + 1).get_val(); + } + + return x; + } + x_dd = fputil::exact_add(1.0, x); + } + + // At this point, x_dd is the exact sum of 1 + x: + // x_dd.hi + x_dd.lo = x + 1.0 exactly. + // |x_dd.hi| >= 2^-54 + // |x_dd.lo| < ulp(x_dd.hi) + + FPBits_t xhi_bits(x_dd.hi); + uint64_t xhi_frac = xhi_bits.get_mantissa(); + x_u = xhi_bits.uintval(); + // Range reduction: + // Find k such that |x_hi - k * 2^-7| <= 2^-8. + int idx = static_cast<int>((xhi_frac + (1ULL << (FRACTION_LEN - 8))) >> + (FRACTION_LEN - 7)); + int x_e = xhi_bits.get_exponent() + (idx >> 7); + double e_x = static_cast<double>(x_e); + + // hi is exact + // ulp(hi) = ulp(LOG_2_HI) = ulp(LOG_R1_DD[idx].hi) = 2^-43 + double hi = fputil::multiply_add(e_x, LOG_2_HI, LOG_R1_DD[idx].hi); + // lo errors < |e_x| * ulp(LOG_2_LO) + ulp(LOG_R1[idx].lo) + // <= 2^11 * 2^(-43-53) = 2^-85 + double lo = fputil::multiply_add(e_x, LOG_2_LO, LOG_R1_DD[idx].lo); + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + // Error bound of e_x * log(2) - log(r1) + constexpr double ERR_HI[2] = {0x1.0p-85, 0.0}; + double err_hi = ERR_HI[hi == 0.0]; +#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS + + // Scale x_dd by 2^(-xh_bits.get_exponent()). + int64_t s_u = static_cast<int64_t>(x_u & FPBits_t::EXP_MASK) - + (static_cast<int64_t>(EXP_BIAS) << FRACTION_LEN); + // Normalize arguments: + // 1 <= m_dd.hi < 2 + // |m_dd.lo| < 2^-52. + // This is exact. + uint64_t m_hi = FPBits_t::one().uintval() | xhi_frac; + + uint64_t m_lo = + FPBits_t(x_dd.lo).abs().get_val() > x_dd.hi * 0x1.0p-127 + ? static_cast<uint64_t>(cpp::bit_cast<int64_t>(x_dd.lo) - s_u) + : 0; + + fputil::DoubleDouble m_dd{FPBits_t(m_lo).get_val(), FPBits_t(m_hi).get_val()}; + + // Perform range reduction: + // r * m - 1 = r * (m_dd.hi + m_dd.lo) - 1 + // = (r * m_dd.hi - 1) + r * m_dd.lo + // = v_hi + (v_lo.hi + v_lo.lo) + // where: + // v_hi = r * m_dd.hi - 1 (exact) + // v_lo.hi + v_lo.lo = r * m_dd.lo (exact) + // Bounds on the values: + // -0x1.69000000000edp-8 < r * m - 1 < 0x1.7f00000000081p-8 + // |v_lo.hi| <= |r| * |m_dd.lo| < 2^-52 + // |v_lo.lo| < ulp(v_lo.hi) <= 2^(-52 - 53) = 2^(-105) + double r = R1[idx]; + fputil::DoubleDouble v_lo = fputil::exact_mult(m_dd.lo, r); + + // Perform exact range reduction +#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE + double v_hi = fputil::multiply_add(r, m_dd.hi, -1.0); // Exact. +#else + // c = 1 + idx * 2^-7. + double c = FPBits_t((static_cast<uint64_t>(idx) << (FRACTION_LEN - 7)) + + uint64_t(0x3FF0'0000'0000'0000ULL)) + .get_val(); + double v_hi = fputil::multiply_add(r, m_dd.hi - c, RCM1[idx]); // Exact +#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE + + // Range reduction output: + // -0x1.69000000000edp-8 < v_hi + v_lo < 0x1.7f00000000081p-8 + // |v_dd.lo| < ulp(v_dd.hi) <= 2^(-7 - 53) = 2^-60 + fputil::DoubleDouble v_dd = fputil::exact_add(v_hi, v_lo.hi); + v_dd.lo += v_lo.lo; + + // Exact sum: + // r1.hi + r1.lo = e_x * log(2)_hi - log(r)_hi + u + fputil::DoubleDouble r1 = fputil::exact_add(hi, v_dd.hi); + + // Overall error is bounded by: + // C * ulp(v_sq) + err_hi + double v_sq = v_dd.hi * v_dd.hi; + double p0 = fputil::multiply_add(v_dd.hi, P_COEFFS[1], P_COEFFS[0]); + double p1 = fputil::multiply_add(v_dd.hi, P_COEFFS[3], P_COEFFS[2]); + double p2 = fputil::multiply_add(v_dd.hi, P_COEFFS[5], P_COEFFS[4]); + double p = fputil::polyeval(v_sq, (v_dd.lo + r1.lo) + lo, p0, p1, p2); + +#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + return r1.hi + p; +#else + double err = fputil::multiply_add(v_sq, P_ERR, err_hi); + + double left = r1.hi + (p - err); + double right = r1.hi + (p + err); + + // Ziv's test to see if fast pass is accurate enough. + if (left == right) + return left; + + return log1p_accurate(x_e, idx, v_dd); +#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_LOG1P_H diff --git a/libc/src/__support/math/log2.h b/libc/src/__support/math/log2.h new file mode 100644 index 0000000..79ec907 --- /dev/null +++ b/libc/src/__support/math/log2.h @@ -0,0 +1,978 @@ +//===-- Double-precision log2(x) function ---------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_LOG2_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_LOG2_H + +#include "common_constants.h" +#include "log_range_reduction.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/PolyEval.h" +#include "src/__support/FPUtil/double_double.h" +#include "src/__support/FPUtil/dyadic_float.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/common.h" +#include "src/__support/integer_literals.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY + +namespace LIBC_NAMESPACE_DECL { + +namespace math { +namespace log2_internal { +// 128-bit precision dyadic floating point numbers. +using Float128 = typename fputil::DyadicFloat<128>; + +using LIBC_NAMESPACE::operator""_u128; + +using namespace common_constants_internal; +using namespace math::log_range_reduction_internal; + +LIBC_INLINE_VAR constexpr fputil::DoubleDouble LOG2_E = {0x1.777d0ffda0d24p-56, + 0x1.71547652b82fep0}; + +alignas(16) LIBC_INLINE_VAR const fputil::DoubleDouble LOG_R1[128] = { + {0.0, 0.0}, + {0x1.46662d417cedp-62, 0x1.010157588de71p-7}, + {0x1.27c8e8416e71fp-60, 0x1.0205658935847p-6}, + {-0x1.d192d0619fa67p-60, 0x1.8492528c8cabfp-6}, + {0x1.c05cf1d753622p-59, 0x1.0415d89e74444p-5}, + {-0x1.cdd6f7f4a137ep-59, 0x1.466aed42de3eap-5}, + {0x1.a8be97660a23dp-60, 0x1.894aa149fb343p-5}, + {-0x1.e48fb0500efd4p-59, 0x1.ccb73cdddb2ccp-5}, + {-0x1.dd7009902bf32p-58, 0x1.08598b59e3a07p-4}, + {-0x1.7558367a6acf6p-59, 0x1.1973bd1465567p-4}, + {0x1.7a976d3b5b45fp-59, 0x1.3bdf5a7d1ee64p-4}, + {0x1.f38745c5c450ap-58, 0x1.5e95a4d9791cbp-4}, + {-0x1.72566212cdd05p-61, 0x1.700d30aeac0e1p-4}, + {-0x1.478a85704ccb7p-58, 0x1.9335e5d594989p-4}, + {-0x1.0057eed1ca59fp-59, 0x1.b6ac88dad5b1cp-4}, + {0x1.a38cb559a6706p-58, 0x1.c885801bc4b23p-4}, + {-0x1.a2bf991780d3fp-59, 0x1.ec739830a112p-4}, + {-0x1.ac9f4215f9393p-58, 0x1.fe89139dbd566p-4}, + {-0x1.0e63a5f01c691p-58, 0x1.1178e8227e47cp-3}, + {-0x1.c6ef1d9b2ef7ep-59, 0x1.1aa2b7e23f72ap-3}, + {-0x1.499a3f25af95fp-58, 0x1.2d1610c86813ap-3}, + {0x1.7d411a5b944adp-58, 0x1.365fcb0159016p-3}, + {-0x1.0d5604930f135p-58, 0x1.4913d8333b561p-3}, + {-0x1.71a9682395bfdp-61, 0x1.527e5e4a1b58dp-3}, + {-0x1.d34f0f4621bedp-60, 0x1.6574ebe8c133ap-3}, + {-0x1.8de59c21e166cp-57, 0x1.6f0128b756abcp-3}, + {-0x1.1232ce70be781p-57, 0x1.823c16551a3c2p-3}, + {0x1.55aa8b6997a4p-58, 0x1.8beafeb38fe8cp-3}, + {0x1.142c507fb7a3dp-58, 0x1.95a5adcf7017fp-3}, + {0x1.bcafa9de97203p-57, 0x1.a93ed3c8ad9e3p-3}, + {-0x1.6353ab386a94dp-57, 0x1.b31d8575bce3dp-3}, + {0x1.dd355f6a516d7p-60, 0x1.bd087383bd8adp-3}, + {0x1.60629242471a2p-57, 0x1.d1037f2655e7bp-3}, + {0x1.aa11d49f96cb9p-58, 0x1.db13db0d4894p-3}, + {0x1.2276041f43042p-59, 0x1.e530effe71012p-3}, + {-0x1.08ab2ddc708ap-58, 0x1.ef5ade4dcffe6p-3}, + {0x1.f665066f980a2p-57, 0x1.f991c6cb3b379p-3}, + {0x1.cdb16ed4e9138p-56, 0x1.07138604d5862p-2}, + {0x1.162c79d5d11eep-58, 0x1.0c42d676162e3p-2}, + {-0x1.0e63a5f01c691p-57, 0x1.1178e8227e47cp-2}, + {0x1.66fbd28b40935p-56, 0x1.16b5ccbacfb73p-2}, + {-0x1.12aeb84249223p-57, 0x1.1bf99635a6b95p-2}, + {0x1.e0efadd9db02bp-56, 0x1.269621134db92p-2}, + {-0x1.82dad7fd86088p-56, 0x1.2bef07cdc9354p-2}, + {-0x1.3d69909e5c3dcp-56, 0x1.314f1e1d35ce4p-2}, + {-0x1.324f0e883858ep-58, 0x1.36b6776be1117p-2}, + {-0x1.2ad27e50a8ec6p-56, 0x1.3c25277333184p-2}, + {0x1.0dbb243827392p-57, 0x1.419b423d5e8c7p-2}, + {0x1.8fb4c14c56eefp-60, 0x1.4718dc271c41bp-2}, + {-0x1.123615b147a5dp-58, 0x1.4c9e09e172c3cp-2}, + {-0x1.8f7e9b38a6979p-57, 0x1.522ae0738a3d8p-2}, + {-0x1.0908d15f88b63p-57, 0x1.57bf753c8d1fbp-2}, + {-0x1.6541148cbb8a2p-56, 0x1.5d5bddf595f3p-2}, + {0x1.dc18ce51fff99p-57, 0x1.630030b3aac49p-2}, + {0x1.a64eadd740178p-58, 0x1.68ac83e9c6a14p-2}, + {0x1.657c222d868cdp-58, 0x1.6e60ee6af1972p-2}, + {0x1.84a4ee3059583p-56, 0x1.741d876c67bb1p-2}, + {-0x1.c168817443f22p-56, 0x1.79e26687cfb3ep-2}, + {-0x1.219024acd3b77p-58, 0x1.7fafa3bd8151cp-2}, + {-0x1.486666443b153p-56, 0x1.85855776dcbfbp-2}, + {-0x1.70f2f38238303p-56, 0x1.8b639a88b2df5p-2}, + {-0x1.ad4bb98c1f2c5p-56, 0x1.914a8635bf68ap-2}, + {-0x1.89d2816cf838fp-57, 0x1.973a3431356aep-2}, + {0x1.87bcbcfd3e187p-59, 0x1.9d32bea15ed3bp-2}, + {-0x1.ba8062860ae23p-57, 0x1.a33440224fa79p-2}, + {-0x1.ba8062860ae23p-57, 0x1.a33440224fa79p-2}, + {0x1.bcafa9de97203p-56, 0x1.a93ed3c8ad9e3p-2}, + {0x1.9d56c45dd3e86p-56, 0x1.af5295248cddp-2}, + {0x1.494b610665378p-56, 0x1.b56fa04462909p-2}, + {0x1.6fd02999b21e1p-59, 0x1.bb9611b80e2fbp-2}, + {-0x1.bfc00b8f3feaap-56, 0x1.c1c60693fa39ep-2}, + {-0x1.bfc00b8f3feaap-56, 0x1.c1c60693fa39ep-2}, + {0x1.223eadb651b4ap-57, 0x1.c7ff9c74554c9p-2}, + {0x1.0798270b29f39p-56, 0x1.ce42f18064743p-2}, + {0x1.d7f4d3b3d406bp-56, 0x1.d490246defa6bp-2}, + {-0x1.0b5837185a661p-56, 0x1.dae75484c9616p-2}, + {-0x1.ac81cc8a4dfb8p-56, 0x1.e148a1a2726cep-2}, + {-0x1.ac81cc8a4dfb8p-56, 0x1.e148a1a2726cep-2}, + {0x1.57d646a17bc6ap-56, 0x1.e7b42c3ddad73p-2}, + {-0x1.74b71fb5e57e3p-62, 0x1.ee2a156b413e5p-2}, + {-0x1.0d487f5aba5e5p-57, 0x1.f4aa7ee03192dp-2}, + {-0x1.0d487f5aba5e5p-57, 0x1.f4aa7ee03192dp-2}, + {0x1.7e8f05924d259p-57, 0x1.fb358af7a4884p-2}, + {0x1.1713a36138e19p-57, 0x1.00e5ae5b207abp-1}, + {-0x1.17f9e54e78104p-57, 0x1.04360be7603adp-1}, + {-0x1.17f9e54e78104p-57, 0x1.04360be7603adp-1}, + {0x1.2241edf5fd1f7p-57, 0x1.078bf0533c568p-1}, + {0x1.0d710fcfc4e0dp-55, 0x1.0ae76e2d054fap-1}, + {0x1.0d710fcfc4e0dp-55, 0x1.0ae76e2d054fap-1}, + {0x1.3300f002e836ep-55, 0x1.0e4898611cce1p-1}, + {-0x1.91eee7772c7c2p-55, 0x1.11af823c75aa8p-1}, + {-0x1.91eee7772c7c2p-55, 0x1.11af823c75aa8p-1}, + {0x1.342eb628dba17p-56, 0x1.151c3f6f29612p-1}, + {0x1.89df1568ca0bp-55, 0x1.188ee40f23ca6p-1}, + {0x1.89df1568ca0bp-55, 0x1.188ee40f23ca6p-1}, + {0x1.59bddae1ccce2p-56, 0x1.1c07849ae6007p-1}, + {-0x1.2164ff40e9817p-56, 0x1.1f8635fc61659p-1}, + {-0x1.2164ff40e9817p-56, 0x1.1f8635fc61659p-1}, + {-0x1.fcc8dbccc25cbp-57, 0x1.230b0d8bebc98p-1}, + {0x1.e0efadd9db02bp-55, 0x1.269621134db92p-1}, + {0x1.e0efadd9db02bp-55, 0x1.269621134db92p-1}, + {-0x1.6a0c343be95dcp-56, 0x1.2a2786d0ec107p-1}, + {-0x1.b941ee770436bp-56, 0x1.2dbf557b0df43p-1}, + {-0x1.b941ee770436bp-56, 0x1.2dbf557b0df43p-1}, + {0x1.6c3a5f12642c9p-57, 0x1.315da4434068bp-1}, + {0x1.6c3a5f12642c9p-57, 0x1.315da4434068bp-1}, + {-0x1.f01ab6065515cp-56, 0x1.35028ad9d8c86p-1}, + {0x1.21512aa596ea3p-55, 0x1.38ae2171976e7p-1}, + {0x1.21512aa596ea3p-55, 0x1.38ae2171976e7p-1}, + {0x1.1930603d87b6ep-56, 0x1.3c6080c36bfb5p-1}, + {0x1.1930603d87b6ep-56, 0x1.3c6080c36bfb5p-1}, + {0x1.86cf0f38b461ap-57, 0x1.4019c2125ca93p-1}, + {-0x1.84f481051f71ap-56, 0x1.43d9ff2f923c5p-1}, + {-0x1.84f481051f71ap-56, 0x1.43d9ff2f923c5p-1}, + {0x1.2541aca7d5844p-55, 0x1.47a1527e8a2d3p-1}, + {0x1.2541aca7d5844p-55, 0x1.47a1527e8a2d3p-1}, + {0x1.c457b531506f6p-55, 0x1.4b6fd6f970c1fp-1}, + {0x1.c457b531506f6p-55, 0x1.4b6fd6f970c1fp-1}, + {0x1.d749362382a77p-56, 0x1.4f45a835a4e19p-1}, + {0x1.d749362382a77p-56, 0x1.4f45a835a4e19p-1}, + {0x1.988ba4aea614dp-56, 0x1.5322e26867857p-1}, + {0x1.988ba4aea614dp-56, 0x1.5322e26867857p-1}, + {0x1.80bff3303dd48p-55, 0x1.5707a26bb8c66p-1}, + {0x1.80bff3303dd48p-55, 0x1.5707a26bb8c66p-1}, + {-0x1.6714fbcd8135bp-55, 0x1.5af405c3649ep-1}, + {-0x1.6714fbcd8135bp-55, 0x1.5af405c3649ep-1}, + {0x1.1c066d235ee63p-56, 0x1.5ee82aa24192p-1}, + {0.0, 0.0}, +}; + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS +// Extra errors from P is from using x^2 to reduce evaluation latency. +LIBC_INLINE_VAR constexpr double P_ERR = 0x1.0p-49; + +alignas(16) LIBC_INLINE_VAR constexpr LogRR LOG2_TABLE = { + // -log2(r) with 128-bit precision generated by SageMath with: + // def format_hex(value): + // l = hex(value)[2:] + // n = 8 + // x = [l[i:i + n] for i in range(0, len(l), n)] + // return "0x" + "'".join(x) + "_u128" + // for i in range(1, 127): + // r = 2^-8 * ceil( 2^8 * (1 - 2^(-8)) / (1 + i*2^(-7)) ); + // s, m, e = RealField(128)(r).log2().sign_mantissa_exponent(); + // print("{Sign::POS,", e, ", format_hex(m), "},"); + /* .step_1 = */ { + {Sign::POS, 0, 0_u128}, + {Sign::POS, -134, 0xb963dd10'7b993ada'e8c25163'0adb856a_u128}, + {Sign::POS, -133, 0xba1f7430'f9aab1b2'a41b08fb'e05f82d0_u128}, + {Sign::POS, -132, 0x8c25c726'2b57c149'1f06c085'bc1b865d_u128}, + {Sign::POS, -132, 0xbb9ca64e'cac6aaef'2e1c07f0'438ebac0_u128}, + {Sign::POS, -132, 0xeb75e8f8'ff5ff022'aacc0e21'd6541224_u128}, + {Sign::POS, -131, 0x8dd99530'02a4e866'31514aef'39ce6303_u128}, + {Sign::POS, -131, 0xa62b07f3'457c4070'50799bea'aab2940c_u128}, + {Sign::POS, -131, 0xbeb024b6'7dda6339'da288fc6'15a727dc_u128}, + {Sign::POS, -131, 0xcb0657cd'5dbe4f6f'22dbbace'd44516ce_u128}, + {Sign::POS, -131, 0xe3da945b'878e27d0'd939dcee'cdd9ce05_u128}, + {Sign::POS, -131, 0xfce4aee0'e88b2749'9596a8e2'e84c8f45_u128}, + {Sign::POS, -130, 0x84bf1c67'3032495d'243efd93'25954cfe_u128}, + {Sign::POS, -130, 0x916d6e15'59a4b696'91d79938'e7226384_u128}, + {Sign::POS, -130, 0x9e37db28'66f2850b'22563c9e'd9462091_u128}, + {Sign::POS, -130, 0xa4a7c31d'c6f9a5d5'3a53ca11'81015ada_u128}, + {Sign::POS, -130, 0xb19d45fa'1be70855'3eb8023e'ed65d601_u128}, + {Sign::POS, -130, 0xb823018e'3cfc25f0'ce5cabbd'2d753d9b_u128}, + {Sign::POS, -130, 0xc544c055'fde99333'54dbf16f'b0695ee3_u128}, + {Sign::POS, -130, 0xcbe0e589'e3f6042d'5196a85a'067c6739_u128}, + {Sign::POS, -130, 0xd930124b'ea9a2c66'f349845e'48955078_u128}, + {Sign::POS, -130, 0xdfe33d3f'ffa66037'815ef705'cfaef035_u128}, + {Sign::POS, -130, 0xed61169f'220e97f2'2ba704dc'aa76f41d_u128}, + {Sign::POS, -130, 0xf42be9e9'b09b3def'2062f36b'c14d0d93_u128}, + {Sign::POS, -129, 0x80ecdde7'd30ea2ed'13288019'4144b02b_u128}, + {Sign::POS, -129, 0x845e706c'afd1bf61'54880de6'3812fd49_u128}, + {Sign::POS, -129, 0x8b4e029b'1f8ac391'a87c02ea'f36e2c29_u128}, + {Sign::POS, -129, 0x8ecc164e'a93841ae'9804237e'c8d9431d_u128}, + {Sign::POS, -129, 0x924e6958'9e6b6268'20f81ca9'5d9e7968_u128}, + {Sign::POS, -129, 0x995ff71b'8773432d'124bc6f1'acf95dc4_u128}, + {Sign::POS, -129, 0x9cef470a'acfb7bf9'5a5e8e21'bff3336b_u128}, + {Sign::POS, -129, 0xa08300be'1f651473'4e53fa33'29f65894_u128}, + {Sign::POS, -129, 0xa7b7dd96'762cc3c7'2742d729'6a39eed6_u128}, + {Sign::POS, -129, 0xab591735'abc724e4'f359c554'4bc5e134_u128}, + {Sign::POS, -129, 0xaefee78f'75707221'6b6c874d'd96e1d75_u128}, + {Sign::POS, -129, 0xb2a95a4c'c313bb59'21006678'c0a5c390_u128}, + {Sign::POS, -129, 0xb6587b43'2e47501b'6d40900b'25024b32_u128}, + {Sign::POS, -129, 0xbdc4f816'7955698f'89e2eb55'3b279b3d_u128}, + {Sign::POS, -129, 0xc1826c86'08fe9951'd58525aa'd392ca50_u128}, + {Sign::POS, -129, 0xc544c055'fde99333'54dbf16f'b0695ee3_u128}, + {Sign::POS, -129, 0xc90c0049'26e9dbfb'88d5eae3'326327bb_u128}, + {Sign::POS, -129, 0xccd83954'b6359379'46dfa05b'ddfded8c_u128}, + {Sign::POS, -129, 0xd47fcb8c'0852f0c0'bfe9dbeb'f2e8a45e_u128}, + {Sign::POS, -129, 0xd85b3fa7'a3407fa8'7b11f1c5'160c515c_u128}, + {Sign::POS, -129, 0xdc3be2bd'8d837f7f'1339e567'7ec44dd0_u128}, + {Sign::POS, -129, 0xe021c2cf'17ed9bdb'ea2b8c7b'b0ee9c8b_u128}, + {Sign::POS, -129, 0xe40cee16'a2ff21c4'aec56233'2791fe38_u128}, + {Sign::POS, -129, 0xe7fd7308'd6895b14'71682eba'cca79cfa_u128}, + {Sign::POS, -129, 0xebf36055'e1abc61e'a5ad5ce9'fb5a7bb6_u128}, + {Sign::POS, -129, 0xefeec4ea'c371584e'32251905'31a852c5_u128}, + {Sign::POS, -129, 0xf3efaff2'9c559a77'da8ad649'da21eab0_u128}, + {Sign::POS, -129, 0xf7f630d8'08fc2ada'4c3e2ea7'c15c3d1e_u128}, + {Sign::POS, -129, 0xfc025746'86680cc6'bcb9bfa9'852e0d35_u128}, + {Sign::POS, -128, 0x800a1995'f0019518'ce032f41'd1e774e8_u128}, + {Sign::POS, -128, 0x8215ea5c'd3e4c4c7'9b39ffee'bc29372a_u128}, + {Sign::POS, -128, 0x8424a633'5c777e0b'87f95f1b'efb6f806_u128}, + {Sign::POS, -128, 0x86365578'62acb7ce'b987b42e'3bb332a1_u128}, + {Sign::POS, -128, 0x884b00ae'f726cec5'139a7ba8'3bf2d136_u128}, + {Sign::POS, -128, 0x8a62b07f'3457c407'050799be'aaab2941_u128}, + {Sign::POS, -128, 0x8c7d6db7'169e0cda'8bd74461'7e9b7d52_u128}, + {Sign::POS, -128, 0x8e9b414b'5a92a606'046ad444'333ceb10_u128}, + {Sign::POS, -128, 0x90bc3458'61bf3d52'ef4c737f'ba4f5d66_u128}, + {Sign::POS, -128, 0x92e05023'1df57d6f'ae441c09'd761c549_u128}, + {Sign::POS, -128, 0x95079e1a'0382dc79'6e36aa9c'e90a3879_u128}, + {Sign::POS, -128, 0x973227d6'027ebd8a'0efca1a1'84e93809_u128}, + {Sign::POS, -128, 0x973227d6'027ebd8a'0efca1a1'84e93809_u128}, + {Sign::POS, -128, 0x995ff71b'8773432d'124bc6f1'acf95dc4_u128}, + {Sign::POS, -128, 0x9b9115db'83a3dd2d'352bea51'e58ea9e8_u128}, + {Sign::POS, -128, 0x9dc58e34'7d37696d'266d6cdc'959153bc_u128}, + {Sign::POS, -128, 0x9ffd6a73'a78eaf35'4527d82c'8214ddca_u128}, + {Sign::POS, -128, 0xa238b516'0413106e'404cabb7'6d600e3c_u128}, + {Sign::POS, -128, 0xa238b516'0413106e'404cabb7'6d600e3c_u128}, + {Sign::POS, -128, 0xa47778c9'8bcc86a1'cab7d2ec'23f0eef3_u128}, + {Sign::POS, -128, 0xa6b9c06e'6211646b'761c48dd'859de2d3_u128}, + {Sign::POS, -128, 0xa8ff9718'10a5e181'7fd3b7d7'e5d148bb_u128}, + {Sign::POS, -128, 0xab49080e'cda53208'c27c6780'd92b4d11_u128}, + {Sign::POS, -128, 0xad961ed0'cb91d406'db502402'c94092cd_u128}, + {Sign::POS, -128, 0xad961ed0'cb91d406'db502402'c94092cd_u128}, + {Sign::POS, -128, 0xafe6e713'93eeda29'3432ef6b'732b6843_u128}, + {Sign::POS, -128, 0xb23b6cc5'6cc84c99'bb324da7'e046e792_u128}, + {Sign::POS, -128, 0xb493bc0e'c9954243'b21709ce'430c8e24_u128}, + {Sign::POS, -128, 0xb493bc0e'c9954243'b21709ce'430c8e24_u128}, + {Sign::POS, -128, 0xb6efe153'c7e319f6'e91ad16e'cff10111_u128}, + {Sign::POS, -128, 0xb94fe935'b83e3eb5'ce31e481'cd797e79_u128}, + {Sign::POS, -128, 0xbbb3e094'b3d228d3'da3e961a'96c580fa_u128}, + {Sign::POS, -128, 0xbbb3e094'b3d228d3'da3e961a'96c580fa_u128}, + {Sign::POS, -128, 0xbe1bd491'3f3fda43'f396598a'ae91499a_u128}, + {Sign::POS, -128, 0xc087d28d'fb2febb8'ae4cceb0'f621941b_u128}, + {Sign::POS, -128, 0xc087d28d'fb2febb8'ae4cceb0'f621941b_u128}, + {Sign::POS, -128, 0xc2f7e831'632b6670'6c1855c4'2078f81b_u128}, + {Sign::POS, -128, 0xc56c2367'9b4d206e'169535fb'8bf577c8_u128}, + {Sign::POS, -128, 0xc56c2367'9b4d206e'169535fb'8bf577c8_u128}, + {Sign::POS, -128, 0xc7e49264'4d64237e'3b24cecc'60217942_u128}, + {Sign::POS, -128, 0xca6143a4'9626d820'3dc2687f'cf939696_u128}, + {Sign::POS, -128, 0xca6143a4'9626d820'3dc2687f'cf939696_u128}, + {Sign::POS, -128, 0xcce245f1'031e41fa'0a62e6ad'd1a901a0_u128}, + {Sign::POS, -128, 0xcf67a85f'a1f89a04'5bb6e231'38ad51e1_u128}, + {Sign::POS, -128, 0xcf67a85f'a1f89a04'5bb6e231'38ad51e1_u128}, + {Sign::POS, -128, 0xd1f17a56'21fb01ac'7fc60a51'03092bae_u128}, + {Sign::POS, -128, 0xd47fcb8c'0852f0c0'bfe9dbeb'f2e8a45e_u128}, + {Sign::POS, -128, 0xd47fcb8c'0852f0c0'bfe9dbeb'f2e8a45e_u128}, + {Sign::POS, -128, 0xd712ac0c'f811659d'8e2d7d37'8127d823_u128}, + {Sign::POS, -128, 0xd9aa2c3b'0ea3cbc1'5c1a7f14'b168b365_u128}, + {Sign::POS, -128, 0xd9aa2c3b'0ea3cbc1'5c1a7f14'b168b365_u128}, + {Sign::POS, -128, 0xdc465cd1'55a90942'b7579f0f'8d3d514b_u128}, + {Sign::POS, -128, 0xdc465cd1'55a90942'b7579f0f'8d3d514b_u128}, + {Sign::POS, -128, 0xdee74ee6'4b0c38d3'b087205e'b55aea85_u128}, + {Sign::POS, -128, 0xe18d13ee'805a4de3'424a2623'd60dfb16_u128}, + {Sign::POS, -128, 0xe18d13ee'805a4de3'424a2623'd60dfb16_u128}, + {Sign::POS, -128, 0xe437bdbf'5254459c'4d3a591a'e6854787_u128}, + {Sign::POS, -128, 0xe437bdbf'5254459c'4d3a591a'e6854787_u128}, + {Sign::POS, -128, 0xe6e75e91'b9cca551'8dcdb6b2'4c5c5cdf_u128}, + {Sign::POS, -128, 0xe99c0905'36ece983'33ac7d9e'bba8a53c_u128}, + {Sign::POS, -128, 0xe99c0905'36ece983'33ac7d9e'bba8a53c_u128}, + {Sign::POS, -128, 0xec55d022'd80e3d27'fb2eede4'b59d8959_u128}, + {Sign::POS, -128, 0xec55d022'd80e3d27'fb2eede4'b59d8959_u128}, + {Sign::POS, -128, 0xef14c760'5d60654c'308b4546'66de8f99_u128}, + {Sign::POS, -128, 0xef14c760'5d60654c'308b4546'66de8f99_u128}, + {Sign::POS, -128, 0xf1d902a3'7aaa5085'8383cb0c'e23bebd4_u128}, + {Sign::POS, -128, 0xf1d902a3'7aaa5085'8383cb0c'e23bebd4_u128}, + {Sign::POS, -128, 0xf4a29645'38813c67'64fc87b4'a41f7b70_u128}, + {Sign::POS, -128, 0xf4a29645'38813c67'64fc87b4'a41f7b70_u128}, + {Sign::POS, -128, 0xf7719715'7665f689'3f5d7d82'b65c5686_u128}, + {Sign::POS, -128, 0xf7719715'7665f689'3f5d7d82'b65c5686_u128}, + {Sign::POS, -128, 0xfa461a5e'8f4b759d'6476077b'9fbd41ae_u128}, + {Sign::POS, -128, 0xfa461a5e'8f4b759d'6476077b'9fbd41ae_u128}, + {Sign::POS, -128, 0xfd2035e9'221ef5d0'0e3909ff'd0d61778_u128}, + {Sign::POS, 0, 0_u128}, + }, + // -log2(r) for the second step, generated by SageMath with: + // + // for i in range(-2^6, 2^7 + 1): + // r = 2^-16 * round( 2^16 / (1 + i*2^(-14)) ); + // s, m, e = RealField(128)(r).log2().sign_mantissa_exponent(); + // print("{Sign::NEG," if s == 1 else "{Sign::POS,", e, ", + // format_hex(m), "},"); + /* .step_2 = */ + { + {Sign::NEG, -135, 0xb9061559'18954401'b5cfed58'337e848a_u128}, + {Sign::NEG, -135, 0xb6264958'a3c7fa2b'ffaf2ac1'b1d20910_u128}, + {Sign::NEG, -135, 0xb34671e4'39aa448e'52521a39'50ea2ed8_u128}, + {Sign::NEG, -135, 0xb0668efb'7ef48ab7'f87e1abd'ee10fd95_u128}, + {Sign::NEG, -135, 0xad86a09e'185af0e8'fbd43bbc'c24c5e43_u128}, + {Sign::NEG, -135, 0xaaa6a6cb'aa8d57ce'2f4f5d48'f9796742_u128}, + {Sign::NEG, -135, 0xa7c6a183'da375c3d'3477fd67'c1cab6b3_u128}, + {Sign::NEG, -135, 0xa4e690c6'4c0056f0'7b4d33eb'381fe558_u128}, + {Sign::NEG, -135, 0xa2067492'a48b5c43'3ce25e48'cb498dea_u128}, + {Sign::NEG, -135, 0x9f264ce8'88773bed'70b0fcc9'e4330983_u128}, + {Sign::NEG, -135, 0x9c4619c7'9c5e80bf'bc9e4267'd3189b22_u128}, + {Sign::NEG, -135, 0x9965db2f'84d7705f'5fb3d896'326615c4_u128}, + {Sign::NEG, -135, 0x9685911f'e6740b02'178b5831'1e96d323_u128}, + {Sign::NEG, -135, 0x93a53b98'65c20b2a'006bf8b6'cf73d847_u128}, + {Sign::NEG, -135, 0x90c4da98'a74ae561'7019f6e6'4a580a02_u128}, + {Sign::NEG, -135, 0x8de46e20'4f93c7f6'cb5733cf'0eb4191d_u128}, + {Sign::NEG, -135, 0x8b03f62f'031d9ab8'56148d4f'c5e415b6_u128}, + {Sign::NEG, -135, 0x882372c4'6664feaf'fe5370f4'25872623_u128}, + {Sign::NEG, -135, 0x8542e3e0'1de24ddf'21b72a14'57ee70d6_u128}, + {Sign::NEG, -135, 0x81aa211f'1e332fcf'abff4f89'968bed0b_u128}, + {Sign::NEG, -136, 0xfd92f0cf'88d75f24'86410a67'6480a5a7_u128}, + {Sign::NEG, -136, 0xf7d1886b'2a876289'44280889'021970e4_u128}, + {Sign::NEG, -136, 0xf2100910'6a42bc14'32eb139d'9812090d_u128}, + {Sign::NEG, -136, 0xec4e72be'90cd2d2d'bef9dd41'e8e42810_u128}, + {Sign::NEG, -136, 0xe68cc574'e6e1e5d7'689d08ca'6c7c3eb1_u128}, + {Sign::NEG, -136, 0xe0cb0132'b5338423'01ef259a'7f69821d_u128}, + {Sign::NEG, -136, 0xdb0925f7'446c13a9'e22cea71'b7bb8467_u128}, + {Sign::NEG, -136, 0xd54733c1'dd2d0d04'0e5bb273'03f542fe_u128}, + {Sign::NEG, -136, 0xcf852a91'c80f553f'57453c8d'5dc64ce1_u128}, + {Sign::NEG, -136, 0xc9c30a66'4da33d56'6cc7add1'fc09ef92_u128}, + {Sign::NEG, -136, 0xc400d33e'b67081a7'e678d728'0de1c07f_u128}, + {Sign::NEG, -136, 0xbe3e851a'4af6496d'419bbeb2'239bdc39_u128}, + {Sign::NEG, -136, 0xb87c1ff8'53ab2631'd4676d1d'81755809_u128}, + {Sign::NEG, -136, 0xb2b9a3d8'18fd1349'b69dfef7'ac2e2890_u128}, + {Sign::NEG, -136, 0xacf710b8'e3517548'9f72fa0a'8fccabc0_u128}, + {Sign::NEG, -136, 0xa7346699'fb051978'b8bfe6a3'addb988e_u128}, + {Sign::NEG, -136, 0xa171a57a'a86c3551'67862c8e'c9dcd60d_u128}, + {Sign::NEG, -136, 0x9baecd5a'33d265ee'09bd3370'909e28a6_u128}, + {Sign::NEG, -136, 0x95ebde37'e57aaf84'a96bc611'b991419b_u128}, + {Sign::NEG, -136, 0x9028d813'059f7cdc'a50bb80f'203f0d62_u128}, + {Sign::NEG, -136, 0x8a65baea'dc729ec5'4d36cd47'4f65a317_u128}, + {Sign::NEG, -136, 0x84a286be'b21d4b8c'779be241'ef4874a3_u128}, + {Sign::NEG, -137, 0xfdbe771b'9d803cea'0e76a962'fa65ace3_u128}, + {Sign::NEG, -137, 0xf237b2ae'f4e62e5a'd3d35627'464a5267_u128}, + {Sign::NEG, -137, 0xe6b0c035'fa8b328c'162ef4b0'e838c363_u128}, + {Sign::NEG, -137, 0xdb299faf'3e7cd74f'77bb10b9'76b3b9ca_u128}, + {Sign::NEG, -137, 0xcfa25119'50b77014'209853ce'e70bc58b_u128}, + {Sign::NEG, -137, 0xc41ad472'c12614d3'63f9b57c'baf2e58d_u128}, + {Sign::NEG, -137, 0xb89329ba'1fa2a0fd'4fca1c93'1bd6e6d6_u128}, + {Sign::NEG, -137, 0xad0b50ed'fbf5b265'26d26e43'4a53490a_u128}, + {Sign::NEG, -137, 0xa1834a0c'e5d6a82d'c55e0790'78dc86a0_u128}, + {Sign::NEG, -137, 0x95fb1515'6ceba1b5'f05b9d5b'd28f540b_u128}, + {Sign::NEG, -137, 0x8a72b206'20c97d84'8ef87f1a'11cdb727_u128}, + {Sign::NEG, -138, 0xfdd441bb'21e7b069'9d687011'4c1183cf_u128}, + {Sign::NEG, -138, 0xe6c2c334'99ba16c4'63d514ff'f97e86f3_u128}, + {Sign::NEG, -138, 0xcfb0e875'c7cc5929'11a38190'1eadd883_u128}, + {Sign::NEG, -138, 0xb89eb17b'cabe1857'a9d69d37'bc0a5bac_u128}, + {Sign::NEG, -138, 0xa18c1e43'c10c6898'2dc97c9f'fefd2497_u128}, + {Sign::NEG, -138, 0x8a792eca'c911cf92'0dcdc8af'cb2ac09a_u128}, + {Sign::NEG, -139, 0xe6cbc61c'020c8446'dd454eb3'a1489470_u128}, + {Sign::NEG, -139, 0xb8a47615'0dfe4470'87803586'4d84b319_u128}, + {Sign::NEG, -139, 0x8a7c6d7a'f1de7942'7ce595cc'53b8342c_u128}, + {Sign::NEG, -140, 0xb8a7588f'd29b1baa'4710b590'49899141_u128}, + {Sign::NEG, -141, 0xb8a8c9d8'be9ae994'5957f633'309d74e3_u128}, + {Sign::POS, 0, 0_u128}, + {Sign::POS, -141, 0xb8abac81'ab576f3b'8268aba0'30b1adf6_u128}, + {Sign::POS, -140, 0xb8ad1de1'ac9ea6a5'1511cba2'fb213a10_u128}, + {Sign::POS, -139, 0x8a82eb77'08262500'6379fb9f'd9bc6235_u128}, + {Sign::POS, -139, 0xb8b000b8'c65957cc'b6fe1bf6'01ee27d5_u128}, + {Sign::POS, -139, 0xe6ddcebb'd72d3f7f'8c6e6069'3a14e6d0_u128}, + {Sign::POS, -138, 0x8a862ac3'0095c084'e9bcfd0c'62eaa2ca_u128}, + {Sign::POS, -138, 0xa19dca8e'85918b6d'73b21420'9a5234a7_u128}, + {Sign::POS, -138, 0xb8b5c6c3'5e142a9b'347d4ca3'109fe4db_u128}, + {Sign::POS, -138, 0xcfce1f64'6dca7745'37a62c48'783bb066_u128}, + {Sign::POS, -138, 0xe6e6d474'9883fbe3'0794b643'7fb56344_u128}, + {Sign::POS, -138, 0xfdffe5f6'c232f658'1cb9a45e'd90318e6_u128}, + {Sign::POS, -137, 0x8a8ca9f6'e7762d0f'bc118e5d'bbef7dbc_u128}, + {Sign::POS, -137, 0x96198f2e'5173e93b'b4c0fb95'35907cf8_u128}, + {Sign::POS, -137, 0xa1a6a2a3'113fe246'c051d2c5'f00a9bb9_u128}, + {Sign::POS, -137, 0xad33e456'9918a8d5'55326987'8c1e5110_u128}, + {Sign::POS, -137, 0xb8c1544a'5b4e2caf'bc906750'b0ce372c_u128}, + {Sign::POS, -137, 0xc44ef27f'ca41bdd8'4c50eaa6'3be294b6_u128}, + {Sign::POS, -137, 0xcfdcbef8'58660da1'b6cb28db'8c065b44_u128}, + {Sign::POS, -137, 0xdb6ab9b5'783f2fc5'70479336'830ceb05_u128}, + {Sign::POS, -137, 0xe6f8e2b8'9c629b7a'2a458c83'1f6aeb49_u128}, + {Sign::POS, -137, 0xf2873a03'37772c8a'6489ba5b'd391e206_u128}, + {Sign::POS, -137, 0xfe15bf96'bc35246b'13f6fda5'10aeec3b_u128}, + {Sign::POS, -136, 0x84d239ba'4eb315a9'2f9a0ef9'e8250836_u128}, + {Sign::POS, -136, 0x8a99aacf'26f2a8a7'389019e8'22b70f1e_u128}, + {Sign::POS, -136, 0x9061330a'a04f87ae'308beeff'a12cf669_u128}, + {Sign::POS, -136, 0x9628d26d'7448a43f'9886a71b'25a2085d_u128}, + {Sign::POS, -136, 0x9bf088f8'5c65a56b'70ba9ceb'e0b969c3_u128}, + {Sign::POS, -136, 0xa1b856ac'1236e85b'cd855dc7'05ea2bea_u128}, + {Sign::POS, -136, 0xa7803b89'4f5580e0'7736196b'11afb331_u128}, + {Sign::POS, -136, 0xad483790'cd6339fa'94c99761'b8eab3d8_u128}, + {Sign::POS, -136, 0xb3104ac3'460a9668'6194b8c0'40814736_u128}, + {Sign::POS, -136, 0xb8d87521'72fed130'edde8d24'c7a999cc_u128}, + {Sign::POS, -136, 0xbea0b6ac'0dfbde2f'ea6b01eb'de42f1d0_u128}, + {Sign::POS, -136, 0xc4690f63'd0c66aa1'7ef732b6'9334cf50_u128}, + {Sign::POS, -136, 0xca317f49'752bddae'2ba86275'fcfc2d72_u128}, + {Sign::POS, -136, 0xcffa065d'b50258f6'b56ea44e'185bf99f_u128}, + {Sign::POS, -136, 0xd5c2a4a1'4a28b920'1d5c3bbe'b6902bfe_u128}, + {Sign::POS, -136, 0xdb8b5a14'ee86965f'a2f2bb9e'156b0f37_u128}, + {Sign::POS, -136, 0xe15426b9'5c0c4506'd166eb8d'a06ab5ef_u128}, + {Sign::POS, -136, 0xe71d0a8f'4cb2d60f'97dc7bae'4219de0f_u128}, + {Sign::POS, -136, 0xece60597'7a7c17a8'6c9a8e76'98f416c4_u128}, + {Sign::POS, -136, 0xf2af17d2'9f7295c0'7b3a20aa'5289695e_u128}, + {Sign::POS, -136, 0xf8784141'75a99a93'ddcf578e'e2c2897b_u128}, + {Sign::POS, -136, 0xfe4181e4'b73d2f37'e10ebd96'c3ec30ec_u128}, + {Sign::POS, -135, 0x82056cde'8f290e13'a9b7baec'b34ba577_u128}, + {Sign::POS, -135, 0x8430f56d'5e1edfd1'2da910dc'61c182da_u128}, + {Sign::POS, -135, 0x8715b5a8'f27bed90'faca09dc'7e0ba8b5_u128}, + {Sign::POS, -135, 0x89fa8180'19a2cace'0d723876'173c0947_u128}, + {Sign::POS, -135, 0x8cdf58f3'30b64515'4e6651df'154e8f8c_u128}, + {Sign::POS, -135, 0x8fc43c02'94dd8af3'ee54b77d'3bc34b6d_u128}, + {Sign::POS, -135, 0x92a92aae'a3442c3d'ad07dde9'b5f92cce_u128}, + {Sign::POS, -135, 0x958e24f7'b91a1a53'261aacf9'44b638f0_u128}, + {Sign::POS, -135, 0x98732ade'3393a868'232f5d64'a85b219d_u128}, + {Sign::POS, -135, 0x9b583c62'6fe98bc9'f3a958bb'706093fc_u128}, + {Sign::POS, -135, 0x9e3d5984'cb58dc25'c9eaa059'e7b0333a_u128}, + {Sign::POS, -135, 0xa1228245'a32313cf'1e154029'663243c0_u128}, + {Sign::POS, -135, 0xa407b6a5'548e1006'16515200'e283d006_u128}, + {Sign::POS, -135, 0xa6ecf6a4'3ce4113d'f498168a'3337ca4f_u128}, + {Sign::POS, -135, 0xa9d24242'b973bb63'8a04a89f'0548a10f_u128}, + {Sign::POS, -135, 0xacb79981'27901623'afaad01f'25772805_u128}, + {Sign::POS, -135, 0xaf9cfc5f'e4908d31'c4f47950'543fe0b8_u128}, + {Sign::POS, -135, 0xb2826adf'4dd0f08e'338655e6'77d0d3ec_u128}, + {Sign::POS, -135, 0xb567e4ff'c0b174cc'f8ac2ce1'9d009541_u128}, + {Sign::POS, -135, 0xb84d6ac1'9a96b35c'344d5e7d'd7b2f465_u128}, + {Sign::POS, -135, 0xbb32fc25'38e9aaca'bd6a217f'b4598ec7_u128}, + {Sign::POS, -135, 0xbe18992a'f917bf0e'bc21ff36'8f562b75_u128}, + {Sign::POS, -135, 0xc0fe41d3'3892b9cc'4944139c'cbf2cb9a_u128}, + {Sign::POS, -135, 0xc3e3f61e'54d0ca9c'1369970c'8b67e6b5_u128}, + {Sign::POS, -135, 0xc6c9b60c'ab4c8752'099b370e'2d04a530_u128}, + {Sign::POS, -135, 0xc9af819e'9984ec44'0b81c3d4'8aff589f_u128}, + {Sign::POS, -135, 0xcc9558d4'7cfd5c90'9f22b809'93be311b_u128}, + {Sign::POS, -135, 0xcf7b3bae'b33da265'ac29209c'8d8985ae_u128}, + {Sign::POS, -135, 0xd2612a2d'99d1ef47'3cbb6a52'0292351d_u128}, + {Sign::POS, -135, 0xd5472451'8e4adc56'43de9ae4'0507ef24_u128}, + {Sign::POS, -135, 0xd82d2a1a'ee3d6a97'69677b90'2ea4df3a_u128}, + {Sign::POS, -135, 0xdb133b8a'17430339'db7a3aff'74967bd5_u128}, + {Sign::POS, -135, 0xddf9589f'66f977de'25990c82'a0066ac6_u128}, + {Sign::POS, -135, 0xe0df815b'3b0302dd'0d424aac'f4babf55_u128}, + {Sign::POS, -135, 0xe30c278d'9936c595'f8e3e7eb'5a7bdebb_u128}, + {Sign::POS, -135, 0xe5f264ad'b62d5810'5ef8bf5a'df5deebe_u128}, + {Sign::POS, -135, 0xe8d8ad75'590bdf92'331d1996'5368fc82_u128}, + {Sign::POS, -135, 0xebbf01e4'df85219e'901c30c4'27e358b8_u128}, + {Sign::POS, -135, 0xeea561fc'a7504dc1'aeac7e98'57253b06_u128}, + {Sign::POS, -135, 0xf18bcdbd'0e28fdd7'e2113e58'93ab5b40_u128}, + {Sign::POS, -135, 0xf4724526'71cf3654'9a4efc80'ae977826_u128}, + {Sign::POS, -135, 0xf758c839'30076689'6bf3ba83'19332c9f_u128}, + {Sign::POS, -135, 0xfa3f56f5'a69a68ed'1d732d30'2e75018b_u128}, + {Sign::POS, -135, 0xfd25f15c'33558362'ba179c5d'bcceec01_u128}, + {Sign::POS, -134, 0x80064bb6'9a0533c0'5543f53b'8ad85039_u128}, + {Sign::POS, -134, 0x8179a494'8347996b'e971a556'5b93cb67_u128}, + {Sign::POS, -134, 0x82ed0348'045f379d'5b399644'ba714691_u128}, + {Sign::POS, -134, 0x846067d1'4c3b8982'5079f1e0'ec4b8496_u128}, + {Sign::POS, -134, 0x85d3d230'89ce40b0'6aba4990'a32e8873_u128}, + {Sign::POS, -134, 0x87474265'ec0b4548'e16770c3'a404291c_u128}, + {Sign::POS, -134, 0x88bab871'a1e8b61c'1edb7ffb'1d6b3eab_u128}, + {Sign::POS, -134, 0x8a2e3453'da5ee8cd'603243e1'ba7c7865_u128}, + {Sign::POS, -134, 0x8ba1b60c'c46869f6'57ea5c03'ea4621dd_u128}, + {Sign::POS, -134, 0x8d153d9c'8f01fd4a'd3534cbf'43bd7fd8_u128}, + {Sign::POS, -134, 0x8e88cb03'692a9dbc'62c8c807'5dc91cd5_u128}, + {Sign::POS, -134, 0x8ffc5e41'81e37d9e'04bb70a5'e3db7b85_u128}, + {Sign::POS, -134, 0x916ff757'083006c7'd3875ba3'2159547a_u128}, + {Sign::POS, -134, 0x9286adfc'a91ba28d'5c94c80e'7a8f66b1_u128}, + {Sign::POS, -134, 0x93fa514b'a0517623'52d313c4'7b4f91db_u128}, + {Sign::POS, -134, 0x956dfa72'866fc57d'80829e9f'3957a4c3_u128}, + {Sign::POS, -134, 0x96e1a971'8a824be5'1cd49179'72015ae7_u128}, + {Sign::POS, -134, 0x98555e48'db96fcd2'1af23c29'ef3032da_u128}, + {Sign::POS, -134, 0x99c918f8'a8be040e'e7f7bf24'0be67b80_u128}, + {Sign::POS, -134, 0x9b3cd981'2109c5dc'2bbe3cd4'f7d868fa_u128}, + {Sign::POS, -134, 0x9cb09fe2'738edf14'8c75d6a4'c5ae460d_u128}, + {Sign::POS, -134, 0x9e246c1c'cf642550'750fb989'c9a06186_u128}, + {Sign::POS, -134, 0x9f983e30'63a2a709'de787e24'4901bdf9_u128}, + {Sign::POS, -134, 0xa10c161d'5f65abc0'1ba3205f'f729efa4_u128}, + {Sign::POS, -134, 0xa27ff3e3'f1cab41b'a864d2a0'38fb19cd_u128}, + {Sign::POS, -134, 0xa3f3d784'49f17a11'fb21f083'a5fec56d_u128}, + {Sign::POS, -134, 0xa567c0fe'96fbf109'594c5552'bcc377f5_u128}, + {Sign::POS, -134, 0xa6dbb053'080e45fc'aeb35a35'3fc5a503_u128}, + {Sign::POS, -134, 0xa84fa581'cc4edf9f'67a5c051'30c0f330_u128}, + {Sign::POS, -134, 0xa9c3a08b'12e65e81'4de5cafd'e1caf46f_u128}, + {Sign::POS, -134, 0xab37a16f'0aff9d32'686fce3d'160e88fd_u128}, + {Sign::POS, -134, 0xacaba82d'e3c7b066'de1375b3'af6749a6_u128}, + {Sign::POS, -134, 0xadc2b114'c632da56'24356904'8ac4affe_u128}, + {Sign::POS, -134, 0xaf36c213'19b80ea2'd6796227'dcd39551_u128}, + {Sign::POS, -134, 0xb0aad8ec'cfb38d51'abc92653'86172074_u128}, + {Sign::POS, -134, 0xb21ef5a2'175ac65e'0caac9f1'7896f2ce_u128}, + {Sign::POS, -134, 0xb3931833'1fe56492'1c65a3c7'f828972b_u128}, + {Sign::POS, -134, 0xb50740a0'188d4daa'abdc6644'6a4286d9_u128}, + {Sign::POS, -134, 0xb67b6ee9'308ea27b'2f3bbe8e'8d72abec_u128}, + {Sign::POS, -134, 0xb7efa30e'9727bf11'b67dbdd7'f03d168c_u128}, + }, + // -log2(r) for the third step, generated by SageMath with: + // + // for i in range(-80, 81): + // r = 2^-21 * round( 2^21 / (1 + i*2^(-21)) ); + // s, m, e = RealField(128)(r).log2().sign_mantissa_exponent(); + // print("{Sign::NEG," if (s == 1) else "{Sign::POS,", e, ", + // format_hex(m), "},"); + /* .step_3 = */ + { + {Sign::NEG, -142, 0xe6d3a96b'978fc16e'26f2c63c'0827ccbb_u128}, + {Sign::NEG, -142, 0xe3f107a9'fbfc50ca'4b56fe66'7c8ec091_u128}, + {Sign::NEG, -142, 0xe10e65d1'4b937265'647d7618'1aec10fc_u128}, + {Sign::NEG, -142, 0xde2bc3e1'8653b4f5'99e8f4d5'379eca79_u128}, + {Sign::NEG, -142, 0xdb4921da'ac3ba730'f07da899'90c20623_u128}, + {Sign::NEG, -142, 0xd8667fbc'bd49d7cd'4a812184'8531851a_u128}, + {Sign::NEG, -142, 0xd583dd87'b97cd580'679a4d85'4ae13619_u128}, + {Sign::NEG, -142, 0xd2a13b3b'a0d32eff'e4d17407'2487a514_u128}, + {Sign::NEG, -142, 0xcfbe98d8'734b7301'3c90319d'969b54be_u128}, + {Sign::NEG, -142, 0xccdbf65e'30e43039'c6a173b0'9ba301e6_u128}, + {Sign::NEG, -142, 0xc9f953cc'd99bf55e'b8317428'd7d8d06b_u128}, + {Sign::NEG, -142, 0xc716b124'6d715125'23cdb51b'cc2061cd_u128}, + {Sign::NEG, -142, 0xc4340e64'ec62d241'f964fc78'084fd515_u128}, + {Sign::NEG, -142, 0xc1516b8e'566f076a'06474fb1'5ccbb015_u128}, + {Sign::NEG, -142, 0xbe6ec8a0'ab947f51'f525ef6d'0b75b1c3_u128}, + {Sign::NEG, -142, 0xbb8c259b'ebd1c8ae'4e13532d'f7ee8da7_u128}, + {Sign::NEG, -142, 0xb8a98280'17257233'76832500'd72a9027_u128}, + {Sign::NEG, -142, 0xb5c6df4d'2d8e0a95'b14a3d28'5e592ba0_u128}, + {Sign::NEG, -142, 0xb2e43c03'2f0a2089'1e9e9dc9'711f6e20_u128}, + {Sign::NEG, -142, 0xb00198a2'1b9842c1'bc176e97'4f255fac_u128}, + {Sign::NEG, -142, 0xad1ef529'f336fff3'64acf87f'c0f648e6_u128}, + {Sign::NEG, -142, 0xaa3c519a'b5e4e6d1'd0b8a157'4433e1f8_u128}, + {Sign::NEG, -142, 0xa759adf4'63a08610'95f4e785'371c69a9_u128}, + {Sign::NEG, -142, 0xa4770a36'fc686c63'277d5db0'0363a46f_u128}, + {Sign::NEG, -142, 0xa1946662'803b287c'd5cea669'485ec36c_u128}, + {Sign::NEG, -142, 0x9eb1c276'ef174910'cec66fda'04833322_u128}, + {Sign::NEG, -142, 0x9bcf1e74'48fb5cd2'1da36f6e'be3851db_u128}, + {Sign::NEG, -142, 0x98ec7a5a'8de5f273'ab055d83'abfc0d82_u128}, + {Sign::NEG, -142, 0x9609d629'bdd598a8'3cecf110'dbda68e9_u128}, + {Sign::NEG, -142, 0x932731e1'd8c8de22'76bbdb56'5a37e84b_u128}, + {Sign::NEG, -142, 0x90448d82'debe5194'd934c388'57eee4f3_u128}, + {Sign::NEG, -142, 0x8d61e90c'cfb481b1'c27b427b'4fbfc7db_u128}, + {Sign::NEG, -142, 0x8a7f447f'aba9fd2b'6e13de50'2b142b39_u128}, + {Sign::NEG, -142, 0x879c9fdb'729d52b3'f4e40620'6614e2ba_u128}, + {Sign::NEG, -142, 0x84b9fb20'248d10fd'4d320daa'3312ea6c_u128}, + {Sign::NEG, -142, 0x81d7564d'c177c6b9'4aa528fc'9d433c1a_u128}, + {Sign::NEG, -143, 0xfde962c8'92b80533'3c8ad047'559b1622_u128}, + {Sign::NEG, -143, 0xf82418c7'7870a69f'acf765a8'fc5bcc31_u128}, + {Sign::NEG, -143, 0xf25ece98'34168f1a'be238832'edd27f20_u128}, + {Sign::NEG, -143, 0xec99843a'c5a6dc07'02644bfc'a329b708_u128}, + {Sign::NEG, -143, 0xe6d439af'2d1eaac6'c6d05a78'8e614744_u128}, + {Sign::NEG, -143, 0xe10eeef5'6a7b18bc'133fe9cc'57a8c1d0_u128}, + {Sign::NEG, -143, 0xdb49a40d'7db94348'aa4cb429'195fb5dd_u128}, + {Sign::NEG, -143, 0xd58458f7'66d647ce'0951ef23'9abbb959_u128}, + {Sign::NEG, -143, 0xcfbf0db3'25cf43ad'686c430c'89143d35_u128}, + {Sign::NEG, -143, 0xc9f9c240'baa15447'ba79c248'afd42c12_u128}, + {Sign::NEG, -143, 0xc43476a0'254996fd'ad19e0a9'2f115327_u128}, + {Sign::NEG, -143, 0xbe6f2ad1'65c5292f'a8ad6ac3'b0c99520_u128}, + {Sign::NEG, -143, 0xb8a9ded4'7c11283d'd0567d4a'9cc5e6a1_u128}, + {Sign::NEG, -143, 0xb2e492a9'682ab188'01f87c65'4b231443_u128}, + {Sign::NEG, -143, 0xad1f4650'2a0ee26d'd6380b08'358051bc_u128}, + {Sign::NEG, -143, 0xa759f9c8'c1bad84e'a07b024d'26d391f6_u128}, + {Sign::NEG, -143, 0xa194ad13'2f2bb089'6ee868cb'69e3a7d8_u128}, + {Sign::NEG, -143, 0x9bcf602f'725e887d'0a6869ef'f6682f73_u128}, + {Sign::NEG, -143, 0x960a131d'8b507d87'f6a44d55'9ccf3f61_u128}, + {Sign::NEG, -143, 0x9044c5dd'79fead08'72066e1d'30a8e210_u128}, + {Sign::NEG, -143, 0x8a7f786f'3e66345c'75ba3245'b1b856af_u128}, + {Sign::NEG, -143, 0x84ba2ad2'd88430e1'b5ac0204'73ab198f_u128}, + {Sign::NEG, -144, 0xfde9ba10'90ab7feb'41127e3a'88eb6741_u128}, + {Sign::NEG, -144, 0xf25f1e1f'1baffdea'bf807875'22aca1c4_u128}, + {Sign::NEG, -144, 0xe6d481d1'5210167b'af00688b'14fa3adc_u128}, + {Sign::NEG, -144, 0xdb49e527'33c60457'4d72837c'8ab4d1e5_u128}, + {Sign::NEG, -144, 0xcfbf4820'c0cc0236'4e38ac27'bb252090_u128}, + {Sign::NEG, -144, 0xc434aabd'f91c4ad0'da3661f9'292f59e8_u128}, + {Sign::NEG, -144, 0xb8aa0cfe'dcb118de'8fd0af9b'dfd21488_u128}, + {Sign::NEG, -144, 0xad1f6ee3'6b84a716'82ee19a9'abf0bfa5_u128}, + {Sign::NEG, -144, 0xa194d06b'a591302f'3cf68d5b'5369a251_u128}, + {Sign::NEG, -144, 0x960a3197'8ad0eede'bcd34f38'c977647e_u128}, + {Sign::NEG, -144, 0x8a7f9267'1b3e1dda'76eee9c9'605e2143_u128}, + {Sign::NEG, -145, 0xfde9e5b4'ada5efae'aa6a3887'f0c803ab_u128}, + {Sign::NEG, -145, 0xe6d4a5e2'7b136f13'6e25927e'582ac191_u128}, + {Sign::NEG, -145, 0xcfbf6557'9eb92f4a'e2ebcac2'f3a8e9eb_u128}, + {Sign::NEG, -145, 0xb8aa2414'188ba5bb'9d9acc22'd5690751_u128}, + {Sign::NEG, -145, 0xa194e217'e87f47cb'1e12604b'6d4132ef_u128}, + {Sign::NEG, -145, 0x8a7f9f63'0e888add'cf340d2a'cb9b92a9_u128}, + {Sign::NEG, -146, 0xe6d4b7eb'1537c8ae'0dc5e49f'bde3c520_u128}, + {Sign::NEG, -146, 0xb8aa2f9e'b95b9332'0c074c95'57c01188_u128}, + {Sign::NEG, -146, 0x8a7fa5e1'09656009'f0f82818'ff9b654f_u128}, + {Sign::NEG, -147, 0xb8aa3564'0a7c33eb'd4cd6120'78bbe9b0_u128}, + {Sign::NEG, -148, 0xb8aa3846'b33aaecf'f08cf68f'42e09fa0_u128}, + {Sign::POS, 0, 0_u128}, + {Sign::POS, -148, 0xb8aa3e0c'0513f9b1'68bd0fac'df0ddaaf_u128}, + {Sign::POS, -147, 0xb8aa40ee'ae2ec9b3'192af653'dd41575b_u128}, + {Sign::POS, -146, 0x8a7fb2dd'018e4892'3b5c8984'2e540a51_u128}, + {Sign::POS, -146, 0xb8aa46b4'00c0bee3'34ad8ebd'd8b2750c_u128}, + {Sign::POS, -146, 0xe6d4dbfc'54c5dd1b'70b12bd6'98e5be74_u128}, + {Sign::POS, -145, 0x8a7fb95a'feda5c46'08c7e424'efbd90e1_u128}, + {Sign::POS, -145, 0xa1950570'7dd23344'31b8eba7'74a1de77_u128}, + {Sign::POS, -145, 0xb8aa523e'a755fe32'ee400e8c'68838733_u128}, + {Sign::POS, -145, 0xcfbf9fc5'7b7147be'0e71fa0b'5603bc2f_u128}, + {Sign::POS, -145, 0xe6d4ee04'fa2f9a92'7763c919'd8ac65f1_u128}, + {Sign::POS, -145, 0xfdea3cfd'239c815e'232b270b'b6046ec1_u128}, + {Sign::POS, -144, 0x8a7fc656'fbe1c368'106f3919'7e068972_u128}, + {Sign::POS, -144, 0x960a6e8b'bb581acc'4a4a6f40'12941bd9_u128}, + {Sign::POS, -144, 0xa195171c'd0370c34'5bb34c11'20b3e54b_u128}, + {Sign::POS, -144, 0xad1fc00a'3a845cf9'6bb67313'92a3147a_u128}, + {Sign::POS, -144, 0xb8aa6953'fa45d275'2be1268d'cee3c8fc_u128}, + {Sign::POS, -144, 0xc43512fa'0f813201'd84158d5'd50251a9_u128}, + {Sign::POS, -144, 0xcfbfbcfc'7a3c40fa'3765bda1'5d0ef0fa_u128}, + {Sign::POS, -144, 0xdb4a675b'3a7cc4b9'9a5ddb55'f9cc27d9_u128}, + {Sign::POS, -144, 0xe6d51216'5048829b'dcba1c59'3d918775_u128}, + {Sign::POS, -144, 0xf25fbd2d'bba53ffd'648be060'e1e30a95_u128}, + {Sign::POS, -144, 0xfdea68a1'7c98c23b'22658dc2'f1bcf6e8_u128}, + {Sign::POS, -143, 0x84ba8a38'c9946759'48ad5162'fb4a236e_u128}, + {Sign::POS, -143, 0x8a7fe04e'ffad9560'db7fe378'9405ce3a_u128}, + {Sign::POS, -143, 0x90453693'609acde3'91b56e2e'4f2e5ed8_u128}, + {Sign::POS, -143, 0x960a8d05'ec5ef390'f8998880'c3bb4d76_u128}, + {Sign::POS, -143, 0x9bcfe3a6'a2fce918'e2b87805'2f67efee_u128}, + {Sign::POS, -143, 0xa1953a75'8477912b'67df3991'93f707c0_u128}, + {Sign::POS, -143, 0xa75a9172'90d1ce78'e51b89e4'd5d095e1_u128}, + {Sign::POS, -143, 0xad1fe89d'c80e83b1'fcbbee4e'dbf9f47d_u128}, + {Sign::POS, -143, 0xb2e53ff7'2a309387'964fbd58'b168371b_u128}, + {Sign::POS, -143, 0xb8aa977e'b73ae0aa'dea7276c'a7acd135_u128}, + {Sign::POS, -143, 0xbe6fef34'6f304dcd'47d33f7e'7afc83a6_u128}, + {Sign::POS, -143, 0xc4354718'5213bda0'892603b3'77909123_u128}, + {Sign::POS, -143, 0xc9fa9f2a'5fe812d6'9f32660a'a06239fb_u128}, + {Sign::POS, -143, 0xcfbff76a'98b03021'cbcc5504'd7407f6c_u128}, + {Sign::POS, -143, 0xd5854fd8'fc6ef834'9608c44d'06402ebe_u128}, + {Sign::POS, -143, 0xdb4aa875'8b274dc1'ca3db560'4a863477_u128}, + {Sign::POS, -143, 0xe1100140'44dc137c'7a024036'206c37d6_u128}, + {Sign::POS, -143, 0xe6d55a39'29902c17'fc2e9be8'90ff7ee3_u128}, + {Sign::POS, -143, 0xec9ab360'39467a47'ecdc275c'60da1b53_u128}, + {Sign::POS, -143, 0xf2600cb5'7401e0c0'2d6571e9'4056607f_u128}, + {Sign::POS, -143, 0xf8256638'd9c54234'e4664401'fd1ca2a7_u128}, + {Sign::POS, -143, 0xfdeabfea'6a93815a'7dbba7dc'b50b3fd7_u128}, + {Sign::POS, -142, 0x81d80ce5'1337c072'd541f90d'853c794b_u128}, + {Sign::POS, -142, 0x84bab9ec'06ae11c5'b08f6539'2ce8b75b_u128}, + {Sign::POS, -142, 0x879d670a'0fae2600'6e969a29'f8462436_u128}, + {Sign::POS, -142, 0x8a80143f'2e396e7d'cfc8cbca'a2bf130c_u128}, + {Sign::POS, -142, 0x8d62c18b'62515c98'b737e48c'19421e68_u128}, + {Sign::POS, -142, 0x90456eee'abf761ac'2a9689b9'97c50c0b_u128}, + {Sign::POS, -142, 0x93281c69'0b2cef13'52381fcc'c774d66b_u128}, + {Sign::POS, -142, 0x960ac9fa'7ff37629'7910cec1'dd92dc10_u128}, + {Sign::POS, -142, 0x98ed77a3'0a4c684a'0cb5866b'baff34cb_u128}, + {Sign::POS, -142, 0x9bd02562'aa3936d0'9d5c02c8'0c702d11_u128}, + {Sign::POS, -142, 0x9eb2d339'5fbb5318'dddad053'6b56e775_u128}, + {Sign::POS, -142, 0xa1958127'2ad42e7e'a3a9505d'7f71247a_u128}, + {Sign::POS, -142, 0xa4782f2c'0b853a5d'e6dfbd5d'210830d7_u128}, + {Sign::POS, -142, 0xa75add48'01cfe812'c2372f44'7bdcfa45_u128}, + {Sign::POS, -142, 0xaa3d8b7b'0db5a8f9'73099fd5'32c14b05_u128}, + {Sign::POS, -142, 0xad2039c5'2f37ee6e'5951eef4'83de2c37_u128}, + {Sign::POS, -142, 0xb002e826'665829cd'f7abe6ff'6da76f1e_u128}, + {Sign::POS, -142, 0xb2e5969e'b317cc74'f354411e'd47c5d7b_u128}, + {Sign::POS, -142, 0xb5c8452e'157847c0'1428a99b'a8f5911f_u128}, + {Sign::POS, -142, 0xb8aaf3d4'8d7b0d0c'44a7c433'0edff2c8_u128}, + {Sign::POS, -142, 0xbb8da292'1b218db6'91f1306a'84e4e07b_u128}, + {Sign::POS, -142, 0xbe705166'be6d3b1c'2bc58de4'0cdf7b6a_u128}, + {Sign::POS, -142, 0xc1530052'775f869a'648680b2'54df1d99_u128}, + {Sign::POS, -142, 0xc435af55'45f9e18e'b136b5ac'e0d6f74d_u128}, + {Sign::POS, -142, 0xc7185e6f'2a3dbd56'a979e6c4'34fad480_u128}, + {Sign::POS, -142, 0xc9fb0da0'242c8b50'0794df56'00c90a5a_u128}, + {Sign::POS, -142, 0xccddbce8'33c7bcd8'a86d8081'4ac18cf1_u128}, + {Sign::POS, -142, 0xcfc06c47'5910c34e'8b8ac57a'9cca2d56_u128}, + {Sign::POS, -142, 0xd2a31bbd'9409100f'd314c7e0'3140001f_u128}, + {Sign::POS, -142, 0xd585cb4a'e4b2147a'c3d4c40e'20b5ec89_u128}, + {Sign::POS, -142, 0xd8687aef'4b0d41ed'c5351d72'9060644e_u128}, + {Sign::POS, -142, 0xdb4b2aaa'c71c09c7'614162e1'e12e445d_u128}, + {Sign::POS, -142, 0xde2dda7d'58dfdd66'44a652ea'df8ede85_u128}, + {Sign::POS, -142, 0xe1108a67'005a2e29'3eb1e02a'f3e52c3c_u128}, + {Sign::POS, -142, 0xe3f33a67'bd8c6d6f'415335a2'53a82aa2_u128}, + {Sign::POS, -142, 0xe6d5ea7f'90780c97'611abb08'33305fe1_u128}, + }, + // -log2(r) for the fourth step, generated by SageMath with: + // + // for i in range(-65, 65): + // r = 2^-28 * round( 2^28 / (1 + i*2^(-28)) ); + // s, m, e = RealField(128)(r).log2().sign_mantissa_exponent(); + // print("{Sign::NEG," if (s == 1) else "{Sign::POS,", e, ", + // format_hex(m), "},"); + /* .step_4 = */ + { + {Sign::NEG, -149, 0xbb8ce299'0b5d0b90'ef1bffe5'65ce0a46_u128}, + {Sign::NEG, -149, 0xb8aa39b8'07a576e4'bea32445'60ca3d99_u128}, + {Sign::NEG, -149, 0xb5c790d6'd5c354df'8b91f71c'eefa31a2_u128}, + {Sign::NEG, -149, 0xb2e4e7f5'75b6a57b'9096e3d6'84001c0e_u128}, + {Sign::NEG, -149, 0xb0023f13'e77f68b3'086054c7'94367f36_u128}, + {Sign::NEG, -149, 0xad1f9632'2b1d9e80'2d9cb330'94afe4de_u128}, + {Sign::NEG, -149, 0xaa3ced50'409146dd'3afa673c'fb3698f3_u128}, + {Sign::NEG, -149, 0xa75a446e'27da61c4'6b27d803'3e4c6450_u128}, + {Sign::NEG, -149, 0xa4779b8b'e0f8ef2f'f8d36b84'd52a477b_u128}, + {Sign::NEG, -149, 0xa194f2a9'6becef1a'1eab86ae'37c03565_u128}, + {Sign::NEG, -149, 0x9eb249c6'c8b6617d'175e8d56'deb4ce2c_u128}, + {Sign::NEG, -149, 0x9bcfa0e3'f7554653'1d9ae241'436519da_u128}, + {Sign::NEG, -149, 0x98ecf800'f7c99d96'6c0ee71a'dfe44325_u128}, + {Sign::NEG, -149, 0x960a4f1d'ca136741'3d68fc7c'2efb522f_u128}, + {Sign::NEG, -149, 0x9327a63a'6e32a34d'cc5781e8'ac28e749_u128}, + {Sign::NEG, -149, 0x9044fd56'e42751b6'5388d5ce'd3a0f5af_u128}, + {Sign::NEG, -149, 0x8d625473'2bf17275'0dab5588'224c7e4a_u128}, + {Sign::NEG, -149, 0x8a7fab8f'45910584'356d5d59'15c94a70_u128}, + {Sign::NEG, -149, 0x879d02ab'31060ade'057d4871'2c69a6a7_u128}, + {Sign::NEG, -149, 0x84ba59c6'ee50827c'b88970ea'e5341d60_u128}, + {Sign::NEG, -149, 0x81d7b0e2'7d706c5a'89402fcb'bfe331bb_u128}, + {Sign::NEG, -150, 0xfdea0ffb'bccb90e3'649fba08'79ca348b_u128}, + {Sign::NEG, -150, 0xf824be32'22612d78'dccd9edf'bab6f777_u128}, + {Sign::NEG, -150, 0xf25f6c68'2ba1ae69'f066b9aa'4636478e_u128}, + {Sign::NEG, -150, 0xec9a1a9d'd88d13ab'14c7b3cb'21578781_u128}, + {Sign::NEG, -150, 0xe6d4c8d3'29235d30'bf4d347b'528f56e1_u128}, + {Sign::NEG, -150, 0xe10f7708'1d648aef'6553e0c9'e1b70799_u128}, + {Sign::NEG, -150, 0xdb4a253c'b5509cdb'7c385b9b'd80c1375_u128}, + {Sign::NEG, -150, 0xd584d370'f0e792e9'795745ac'402f919d_u128}, + {Sign::NEG, -150, 0xcfbf81a4'd0296d0d'd20d3d8c'2625ac1b_u128}, + {Sign::NEG, -150, 0xc9fa2fd8'53162b3c'fbb6dfa2'97551554_u128}, + {Sign::NEG, -150, 0xc434de0b'79adcd6b'6bb0c62c'a2867d91_u128}, + {Sign::NEG, -150, 0xbe6f8c3e'43f0538d'9757893d'57e40877_u128}, + {Sign::NEG, -150, 0xb8aa3a70'b1ddbd97'f407bebd'c8f8c28e_u128}, + {Sign::NEG, -150, 0xb2e4e8a2'c3760b7e'f71dfa6d'08b016be_u128}, + {Sign::NEG, -150, 0xad1f96d4'78b93d37'15f6cde0'2b5543ce_u128}, + {Sign::NEG, -150, 0xa75a4505'd1a752b4'c5eec882'4692d1e9_u128}, + {Sign::NEG, -150, 0xa194f336'ce404bec'7c627794'7172081a_u128}, + {Sign::NEG, -150, 0x9bcfa167'6e8428d2'aeae662d'c45a61ce_u128}, + {Sign::NEG, -150, 0x960a4f97'b272e95b'd22f1d3b'59110455_u128}, + {Sign::NEG, -150, 0x9044fdc7'9a0c8d7c'5c412380'4ab83462_u128}, + {Sign::NEG, -150, 0x8a7fabf7'25511528'c240fd95'b5cecb89_u128}, + {Sign::NEG, -150, 0x84ba5a26'54408055'798b2dea'b82fadc4_u128}, + {Sign::NEG, -151, 0xfdea10aa'4db59ded'eef86988'e2227ddb_u128}, + {Sign::NEG, -151, 0xf25f6d07'3a400203'62e1207c'0209b090_u128}, + {Sign::NEG, -151, 0xe6d4c963'6e202cd4'39897891'13ec7bee_u128}, + {Sign::NEG, -151, 0xdb4a25be'e9561e49'5daa6556'5e562909_u128}, + {Sign::NEG, -151, 0xcfbf8219'abe1d64b'b9fcd606'2a84acbd_u128}, + {Sign::NEG, -151, 0xc434de73'b5c354c4'3939b586'c46792b3_u128}, + {Sign::NEG, -151, 0xb8aa3acd'06fa999b'c619ea6a'7a9ee85e_u128}, + {Sign::NEG, -151, 0xad1f9725'9f87a4bb'4b5656ef'9e7a27fd_u128}, + {Sign::NEG, -151, 0xa194f37d'7f6a760b'b3a7d900'83f7239c_u128}, + {Sign::NEG, -151, 0x960a4fd4'a6a30d75'e9c74a33'81c0f016_u128}, + {Sign::NEG, -151, 0x8a7fac2b'15316ae2'd86d7fca'f12ed012_u128}, + {Sign::NEG, -152, 0xfdea1101'962b1c76'd4a6956a'5c863e0f_u128}, + {Sign::NEG, -152, 0xe6d4c9ab'909eeed1'1462ef19'2f547877_u128}, + {Sign::NEG, -152, 0xcfbf8254'19be4ca6'45819d2f'1d72eb8b_u128}, + {Sign::NEG, -152, 0xb8aa3afb'318935c8'3d742790'eedbe719_u128}, + {Sign::NEG, -152, 0xa194f3a0'd7ffaa08'd1ac0d7b'70d74492_u128}, + {Sign::NEG, -152, 0x8a7fac45'0d21a939'd79ac583'75f83d0c_u128}, + {Sign::NEG, -153, 0xe6d4c9cf'a1de665a'49637b2b'ac367e87_u128}, + {Sign::NEG, -153, 0xb8aa3b12'46d08f69'1cc4b5ee'dcc78b35_u128}, + {Sign::NEG, -153, 0x8a7fac52'0919cd43'd43bf48a'42745836_u128}, + {Sign::NEG, -154, 0xb8aa3b1d'd1743f1c'3557bdcf'592619eb_u128}, + {Sign::NEG, -155, 0xb8aa3b23'96c617ae'6bdc2e83'd3ebb0c4_u128}, + {Sign::POS, 0, 0_u128}, + {Sign::POS, -155, 0xb8aa3b2f'2169ca44'2d5b4005'0e44e8ab_u128}, + {Sign::POS, -154, 0xb8aa3b34'e6bba447'b8560371'b8f04afe_u128}, + {Sign::POS, -153, 0x8a7fac6c'010a1f14'c79a43cc'c70459cc_u128}, + {Sign::POS, -153, 0xb8aa3b40'715f59c0'22c25632'f519f77f_u128}, + {Sign::POS, -153, 0xe6d4ca17'c45d8282'42c10a31'4e35fb9e_u128}, + {Sign::POS, -152, 0x8a7fac78'fd024cdb'be5a212e'd7b949e4_u128}, + {Sign::POS, -152, 0xa194f3e7'892a4fde'12dcf94e'f5c5b918_u128}, + {Sign::POS, -152, 0xb8aa3b57'86a6ca76'49781013'e57110ce_u128}, + {Sign::POS, -152, 0xcfbf82c8'f577bcd2'8cba70c0'85c12cb3_u128}, + {Sign::POS, -152, 0xe6d4ca3b'd59d2721'07332f3f'b09328b8_u128}, + {Sign::POS, -152, 0xfdea11b0'2717098f'e3716824'3a9d8b14_u128}, + {Sign::POS, -151, 0x8a7fac92'f4f2b226'a6022054'79b93722_u128}, + {Sign::POS, -151, 0x960a504e'8f041bc3'b5bd7358'52c0d583_u128}, + {Sign::POS, -151, 0xa194f40a'e1bfc1b6'36324863'0b0d812d_u128}, + {Sign::POS, -151, 0xad1f97c7'ed25a415'3ca83f0e'02b823c0_u128}, + {Sign::POS, -151, 0xb8aa3b85'b135c2f7'de66fb46'974bc4fd_u128}, + {Sign::POS, -151, 0xc434df44'2df01e75'30b6254e'23c69fc2_u128}, + {Sign::POS, -151, 0xcfbf8303'6354b6a4'48dd69ba'009b370c_u128}, + {Sign::POS, -151, 0xdb4a26c3'51638b9c'3c247973'83b16af5_u128}, + {Sign::POS, -151, 0xe6d4ca83'f81c9d74'1fd309b8'00678db7_u128}, + {Sign::POS, -151, 0xf25f6e45'577fec43'0930d418'c79378a3_u128}, + {Sign::POS, -151, 0xfdea1207'6f8d7820'0d85967b'2783a12c_u128}, + {Sign::POS, -150, 0x84ba5ae5'2022a091'210c898c'360016ed_u128}, + {Sign::POS, -150, 0x8a7facc6'e4d3a3b0'5e19883e'ef2605ab_u128}, + {Sign::POS, -150, 0x9044fea9'05d9c579'488dacc6'629300ae_u128}, + {Sign::POS, -150, 0x960a508b'833505f7'6b0cdebd'3264e3e3_u128}, + {Sign::POS, -150, 0x9bcfa26e'5ce56536'503b07e7'ff788dc2_u128}, + {Sign::POS, -150, 0xa194f451'92eae341'82bc1435'696a69d1_u128}, + {Sign::POS, -150, 0xa75a4635'25458024'8d33f1be'0e96fb1f_u128}, + {Sign::POS, -150, 0xad1f9819'13f53bea'fa4690c4'8c1b66c9_u128}, + {Sign::POS, -150, 0xb2e4e9fd'5efa16a0'5497e3b5'7dd5fe75_u128}, + {Sign::POS, -150, 0xb8aa3be2'06541050'26cbdf27'7e66cad5_u128}, + {Sign::POS, -150, 0xbe6f8dc7'0a032905'fb8679db'27301625_u128}, + {Sign::POS, -150, 0xc434dfac'6a0760cd'5d6bacbb'1056f6aa_u128}, + {Sign::POS, -150, 0xc9fa3192'2660b7b1'd71f72db'd0c3d936_u128}, + {Sign::POS, -150, 0xcfbf8378'3f0f2dbe'f345c97b'fe230ba2_u128}, + {Sign::POS, -150, 0xd584d55e'b412c300'3c82b004'2ce54751_u128}, + {Sign::POS, -150, 0xdb4a2745'856b7781'3d7a2806'f0403bae_u128}, + {Sign::POS, -150, 0xe10f792c'b3194b4d'80d03540'da2f18ae_u128}, + {Sign::POS, -150, 0xe6d4cb14'3d1c3e70'9128dd98'7b73194f_u128}, + {Sign::POS, -150, 0xec9a1cfc'237450f5'f928291e'63940e14_u128}, + {Sign::POS, -150, 0xf25f6ee4'662182e9'4372220d'20e0e78a_u128}, + {Sign::POS, -150, 0xf824c0cd'0523d455'faaad4c9'407040c7_u128}, + {Sign::POS, -150, 0xfdea12b6'007b4547'a9764fe1'4e20e9e4_u128}, + {Sign::POS, -149, 0x81d7b24f'ac13eae4'ed3c5206'ea4d3942_u128}, + {Sign::POS, -149, 0x84ba5b44'8614c2f4'0c2af218'aea6da27_u128}, + {Sign::POS, -149, 0x879d0439'8e402ad6'f6d912ac'383aaeba_u128}, + {Sign::POS, -149, 0x8a7fad2e'c4962293'7298bf5c'ca8b3d95_u128}, + {Sign::POS, -149, 0x8d625624'2916aa2f'44bc04da'a8808214_u128}, + {Sign::POS, -149, 0x9044ff19'bbc1c1b0'3294f0eb'14683198_u128}, + {Sign::POS, -149, 0x9327a80f'7c97691c'01759268'4ff600c3_u128}, + {Sign::POS, -149, 0x960a5105'6b97a078'76aff941'9c43e8b9_u128}, + {Sign::POS, -149, 0x98ecf9fb'88c267cb'5796367b'39d26c63_u128}, + {Sign::POS, -149, 0x9bcfa2f1'd417bf1a'697a5c2e'6888ddaa_u128}, + {Sign::POS, -149, 0x9eb24be8'4d97a66b'71ae7d89'67b5a2b7_u128}, + {Sign::POS, -149, 0xa194f4de'f5421dc4'3584aecf'760e7b39_u128}, + {Sign::POS, -149, 0xa4779dd5'cb17252a'7a4f0558'd1b0c59e_u128}, + {Sign::POS, -149, 0xa75a46cc'cf16bca4'055f9792'b821c455_u128}, + {Sign::POS, -149, 0xaa3cefc4'0140e436'9c087cff'664ee311_u128}, + {Sign::POS, -149, 0xad1f98bb'61959be8'039bce36'188dfc04_u128}, + {Sign::POS, -149, 0xb00241b2'f014e3be'016ba4e3'0a9d9d21_u128}, + {Sign::POS, -149, 0xb2e4eaaa'acbebbbe'5aca1bc7'77a54d5e_u128}, + {Sign::POS, -149, 0xb5c793a2'979323ee'd5094eb9'9a35d1f0_u128}, + {Sign::POS, -149, 0xb8aa3c9a'b0921c55'357b5aa4'ac49738d_u128}, + }}; + +// > P = fpminimax(log2(1 + x)/x, 3, [|128...|], [-0x1.0002143p-29 , 0x1p-29]); +// > P; +// > dirtyinfnorm(log2(1 + x)/x - P, [-0x1.0002143p-29 , 0x1p-29]); +// 0x1.27ad5...p-121 +LIBC_INLINE_VAR constexpr Float128 BIG_COEFFS[4]{ + {Sign::NEG, -129, 0xb8aa3b29'5c2b21e3'3eccf694'0d66bbcc_u128}, + {Sign::POS, -129, 0xf6384ee1'd01febc9'ee39a6d6'49394bb1_u128}, + {Sign::NEG, -128, 0xb8aa3b29'5c17f0bb'be87fed0'67ea2ad5_u128}, + {Sign::POS, -127, 0xb8aa3b29'5c17f0bb'be87fed0'691d3e3f_u128}, +}; + +// Reuse the output of the fast pass range reduction. +// -2^-8 <= m_x < 2^-7 +LIBC_INLINE static double log2_accurate(int e_x, int index, double m_x) { + + Float128 sum(static_cast<float>(e_x)); + sum = fputil::quick_add(sum, LOG2_TABLE.step_1[index]); + + Float128 v_f128 = log_range_reduction(m_x, LOG2_TABLE, sum); + + // Polynomial approximation + Float128 p = fputil::quick_mul(v_f128, BIG_COEFFS[0]); + p = fputil::quick_mul(v_f128, fputil::quick_add(p, BIG_COEFFS[1])); + p = fputil::quick_mul(v_f128, fputil::quick_add(p, BIG_COEFFS[2])); + p = fputil::quick_mul(v_f128, fputil::quick_add(p, BIG_COEFFS[3])); + + Float128 r = fputil::quick_add(sum, p); + + return static_cast<double>(r); +} +#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS + +} // namespace log2_internal + +LIBC_INLINE static double log2(double x) { + using namespace log2_internal; + using namespace common_constants_internal; + using FPBits_t = typename fputil::FPBits<double>; + + FPBits_t xbits(x); + uint64_t x_u = xbits.uintval(); + + int x_e = -FPBits_t::EXP_BIAS; + + if (LIBC_UNLIKELY(xbits == FPBits_t::one())) { + // log2(1.0) = +0.0 + return 0.0; + } + + if (LIBC_UNLIKELY(xbits.uintval() < FPBits_t::min_normal().uintval() || + xbits.uintval() > FPBits_t::max_normal().uintval())) { + if (x == 0.0) { + // return -Inf and raise FE_DIVBYZERO. + fputil::set_errno_if_required(ERANGE); + fputil::raise_except_if_required(FE_DIVBYZERO); + return FPBits_t::inf(Sign::NEG).get_val(); + } + if (xbits.is_neg() && !xbits.is_nan()) { + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_INVALID); + return FPBits_t::quiet_nan().get_val(); + } + if (xbits.is_inf_or_nan()) { + return x; + } + // Normalize denormal inputs. + xbits = FPBits_t(x * 0x1.0p52); + x_e -= 52; + x_u = xbits.uintval(); + } + + // log2(x) = log2(2^x_e * x_m) + // = x_e + log2(x_m) + // Range reduction for log2(x_m): + // For each x_m, we would like to find r such that: + // -2^-8 <= r * x_m - 1 < 2^-7 + int shifted = static_cast<int>(x_u >> 45); + int index = shifted & 0x7F; + double r = RD[index]; + + // Add unbiased exponent. Add an extra 1 if the 8 leading fractional bits are + // all 1's. + x_e += static_cast<int>((x_u + (1ULL << 45)) >> 52); + double e_x = static_cast<double>(x_e); + + // Set m = 1.mantissa. + uint64_t x_m = (x_u & 0x000F'FFFF'FFFF'FFFFULL) | 0x3FF0'0000'0000'0000ULL; + double m = FPBits_t(x_m).get_val(); + + fputil::DoubleDouble r1; + + // Perform exact range reduction +#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE + double u = fputil::multiply_add(r, m, -1.0); // exact +#else + uint64_t c_m = x_m & 0x3FFF'E000'0000'0000ULL; + double c = FPBits_t(c_m).get_val(); + double u = fputil::multiply_add(r, m - c, CD[index]); // exact +#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE + + // Exact sum: + // r1.hi + r1.lo = e_x * log(2)_hi - log(r)_hi + u + r1 = fputil::exact_add(LOG_R1[index].hi, u); + + // Error of u_sq = ulp(u^2); + double u_sq = u * u; + // Degree-7 minimax polynomial + double p0 = fputil::multiply_add(u, LOG_COEFFS[1], LOG_COEFFS[0]); + double p1 = fputil::multiply_add(u, LOG_COEFFS[3], LOG_COEFFS[2]); + double p2 = fputil::multiply_add(u, LOG_COEFFS[5], LOG_COEFFS[4]); + double p = fputil::polyeval(u_sq, LOG_R1[index].lo, p0, p1, p2); + + r1.lo += p; + + // Quick double-double multiplication: + // r2.hi + r2.lo ~ r1 * log2(e), + // with error bounded by: + // 4*ulp( ulp(r2.hi) ) + fputil::DoubleDouble r2 = fputil::quick_mult(r1, LOG2_E); + fputil::DoubleDouble r3 = fputil::exact_add(e_x, r2.hi); + r3.lo += r2.lo; + + // Overall, if we choose sufficiently large constant C, the total error is + // bounded by (C * ulp(u^2)). + +#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + return r3.hi + r3.lo; +#else + // Total error is bounded by ~ C * ulp(u^2). + double err = u_sq * P_ERR; + // Lower bound from the result + double left = r3.hi + (r3.lo - err); + // Upper bound from the result + double right = r3.hi + (r3.lo + err); + + // Ziv's test if fast pass is accurate enough. + if (left == right) + return left; + + return log2_accurate(x_e, index, u); +#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_LOG2_H diff --git a/libc/src/__support/math/logbf.h b/libc/src/__support/math/logbf.h new file mode 100644 index 0000000..1b0daf9 --- /dev/null +++ b/libc/src/__support/math/logbf.h @@ -0,0 +1,26 @@ +//===-- Implementation header for logbf -------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_LOGBF_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_LOGBF_H + +#include "src/__support/FPUtil/ManipulationFunctions.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +LIBC_INLINE static constexpr float logbf(float x) { return fputil::logb(x); } + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_LOGBF_H diff --git a/libc/src/__support/math/logbf128.h b/libc/src/__support/math/logbf128.h new file mode 100644 index 0000000..d18efc5 --- /dev/null +++ b/libc/src/__support/math/logbf128.h @@ -0,0 +1,34 @@ +//===-- Implementation header for logbf128-----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_LOGBF128_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_LOGBF128_H + +#include "include/llvm-libc-types/float128.h" + +#ifdef LIBC_TYPES_HAS_FLOAT128 + +#include "src/__support/FPUtil/ManipulationFunctions.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +LIBC_INLINE static constexpr float128 logbf128(float128 x) { + return fputil::logb(x); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_TYPES_HAS_FLOAT128 + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_LOGBF128_H diff --git a/libc/src/__support/math/logbf16.h b/libc/src/__support/math/logbf16.h new file mode 100644 index 0000000..239e57b --- /dev/null +++ b/libc/src/__support/math/logbf16.h @@ -0,0 +1,34 @@ +//===-- Implementation header for logbf16 -----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_LOGBF16_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_LOGBF16_H + +#include "include/llvm-libc-macros/float16-macros.h" + +#ifdef LIBC_TYPES_HAS_FLOAT16 + +#include "src/__support/FPUtil/ManipulationFunctions.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +LIBC_INLINE static constexpr float16 logbf16(float16 x) { + return fputil::logb(x); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_TYPES_HAS_FLOAT16 + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_LOGBF16_H diff --git a/libc/src/__support/math/logf.h b/libc/src/__support/math/logf.h new file mode 100644 index 0000000..e96fe28 --- /dev/null +++ b/libc/src/__support/math/logf.h @@ -0,0 +1,192 @@ +//===-- Single-precision log(x) function ----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_LOGF_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_LOGF_H + +#include "common_constants.h" // Lookup table for (1/f) and log(f) +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/PolyEval.h" +#include "src/__support/FPUtil/except_value_utils.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY +#include "src/__support/macros/properties/cpu_features.h" + +// This is an algorithm for log(x) in single precision which is correctly +// rounded for all rounding modes, based on the implementation of log(x) from +// the RLIBM project at: +// https://people.cs.rutgers.edu/~sn349/rlibm + +// Step 1 - Range reduction: +// For x = 2^m * 1.mant, log(x) = m * log(2) + log(1.m) +// If x is denormal, we normalize it by multiplying x by 2^23 and subtracting +// m by 23. + +// Step 2 - Another range reduction: +// To compute log(1.mant), let f be the highest 8 bits including the hidden +// bit, and d be the difference (1.mant - f), i.e. the remaining 16 bits of the +// mantissa. Then we have the following approximation formula: +// log(1.mant) = log(f) + log(1.mant / f) +// = log(f) + log(1 + d/f) +// ~ log(f) + P(d/f) +// since d/f is sufficiently small. +// log(f) and 1/f are then stored in two 2^7 = 128 entries look-up tables. + +// Step 3 - Polynomial approximation: +// To compute P(d/f), we use a single degree-5 polynomial in double precision +// which provides correct rounding for all but few exception values. +// For more detail about how this polynomial is obtained, please refer to the +// paper: +// Lim, J. and Nagarakatte, S., "One Polynomial Approximation to Produce +// Correctly Rounded Results of an Elementary Function for Multiple +// Representations and Rounding Modes", Proceedings of the 49th ACM SIGPLAN +// Symposium on Principles of Programming Languages (POPL-2022), Philadelphia, +// USA, January 16-22, 2022. +// https://people.cs.rutgers.edu/~sn349/papers/rlibmall-popl-2022.pdf + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +LIBC_INLINE static float logf(float x) { + using namespace common_constants_internal; + constexpr double LOG_2 = 0x1.62e42fefa39efp-1; + using FPBits = typename fputil::FPBits<float>; + + FPBits xbits(x); + uint32_t x_u = xbits.uintval(); + + int m = -FPBits::EXP_BIAS; + + using fputil::round_result_slightly_down; + using fputil::round_result_slightly_up; + + // Small inputs + if (x_u < 0x4c5d65a5U) { +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + // Hard-to-round cases. + switch (x_u) { + case 0x3f7f4d6fU: // x = 0x1.fe9adep-1f + return round_result_slightly_up(-0x1.659ec8p-9f); + case 0x41178febU: // x = 0x1.2f1fd6p+3f + return round_result_slightly_up(0x1.1fcbcep+1f); +#ifdef LIBC_TARGET_CPU_HAS_FMA + case 0x3f800000U: // x = 1.0f + return 0.0f; +#else + case 0x1e88452dU: // x = 0x1.108a5ap-66f + return round_result_slightly_up(-0x1.6d7b18p+5f); +#endif // LIBC_TARGET_CPU_HAS_FMA + } +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + // Subnormal inputs. + if (LIBC_UNLIKELY(x_u < FPBits::min_normal().uintval())) { + if (x == 0.0f) { + // Return -inf and raise FE_DIVBYZERO + fputil::set_errno_if_required(ERANGE); + fputil::raise_except_if_required(FE_DIVBYZERO); + return FPBits::inf(Sign::NEG).get_val(); + } + // Normalize denormal inputs. + xbits = FPBits(xbits.get_val() * 0x1.0p23f); + m -= 23; + x_u = xbits.uintval(); + } + } else { +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + // Hard-to-round cases. + switch (x_u) { + case 0x4c5d65a5U: // x = 0x1.bacb4ap+25f + return round_result_slightly_down(0x1.1e0696p+4f); + case 0x65d890d3U: // x = 0x1.b121a6p+76f + return round_result_slightly_down(0x1.a9a3f2p+5f); + case 0x6f31a8ecU: // x = 0x1.6351d8p+95f + return round_result_slightly_down(0x1.08b512p+6f); + case 0x7a17f30aU: // x = 0x1.2fe614p+117f + return round_result_slightly_up(0x1.451436p+6f); +#ifndef LIBC_TARGET_CPU_HAS_FMA_DOUBLE + case 0x500ffb03U: // x = 0x1.1ff606p+33f + return round_result_slightly_up(0x1.6fdd34p+4f); + case 0x5cd69e88U: // x = 0x1.ad3d1p+58f + return round_result_slightly_up(0x1.45c146p+5f); + case 0x5ee8984eU: // x = 0x1.d1309cp+62f; + return round_result_slightly_up(0x1.5c9442p+5f); +#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE + } +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + // Exceptional inputs. + if (LIBC_UNLIKELY(x_u > FPBits::max_normal().uintval())) { + if (x_u == 0x8000'0000U) { + // Return -inf and raise FE_DIVBYZERO + fputil::set_errno_if_required(ERANGE); + fputil::raise_except_if_required(FE_DIVBYZERO); + return FPBits::inf(Sign::NEG).get_val(); + } + if (xbits.is_neg() && !xbits.is_nan()) { + // Return NaN and raise FE_INVALID + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + // x is +inf or nan + if (xbits.is_signaling_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + + return x; + } + } + +#ifndef LIBC_TARGET_CPU_HAS_FMA + // Returning the correct +0 when x = 1.0 for non-FMA targets with FE_DOWNWARD + // rounding mode. + if (LIBC_UNLIKELY((x_u & 0x007f'ffffU) == 0)) + return static_cast<float>( + static_cast<double>(m + xbits.get_biased_exponent()) * LOG_2); +#endif // LIBC_TARGET_CPU_HAS_FMA + + uint32_t mant = xbits.get_mantissa(); + // Extract 7 leading fractional bits of the mantissa + int index = mant >> 16; + // Add unbiased exponent. Add an extra 1 if the 7 leading fractional bits are + // all 1's. + m += static_cast<int>((x_u + (1 << 16)) >> 23); + + // Set bits to 1.m + xbits.set_biased_exponent(0x7F); + + float u = xbits.get_val(); + double v = 0.0; +#ifdef LIBC_TARGET_CPU_HAS_FMA_FLOAT + v = static_cast<double>(fputil::multiply_add(u, R[index], -1.0f)); // Exact. +#else + v = fputil::multiply_add(static_cast<double>(u), RD[index], -1.0); // Exact +#endif // LIBC_TARGET_CPU_HAS_FMA_FLOAT + + // Degree-5 polynomial approximation of log generated by Sollya with: + // > P = fpminimax(log(1 + x)/x, 4, [|1, D...|], [-2^-8, 2^-7]); + constexpr double COEFFS[4] = {-0x1.000000000fe63p-1, 0x1.555556e963c16p-2, + -0x1.000028dedf986p-2, 0x1.966681bfda7f7p-3}; + double v2 = v * v; // Exact + double p2 = fputil::multiply_add(v, COEFFS[3], COEFFS[2]); + double p1 = fputil::multiply_add(v, COEFFS[1], COEFFS[0]); + double p0 = LOG_R[index] + v; + double r = fputil::multiply_add(static_cast<double>(m), LOG_2, + fputil::polyeval(v2, p0, p1, p2)); + return static_cast<float>(r); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_LOGF_H diff --git a/libc/src/__support/math/logf16.h b/libc/src/__support/math/logf16.h new file mode 100644 index 0000000..c123eb0 --- /dev/null +++ b/libc/src/__support/math/logf16.h @@ -0,0 +1,180 @@ +//===-- Implementation header for logf16 ------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_LOGF16_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_LOGF16_H + +#include "include/llvm-libc-macros/float16-macros.h" + +#ifdef LIBC_TYPES_HAS_FLOAT16 + +#include "expxf16_utils.h" +#include "hdr/errno_macros.h" +#include "hdr/fenv_macros.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/PolyEval.h" +#include "src/__support/FPUtil/cast.h" +#include "src/__support/FPUtil/except_value_utils.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" +#include "src/__support/macros/properties/cpu_features.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +namespace logf16_internal { + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS +#ifdef LIBC_TARGET_CPU_HAS_FMA_FLOAT +LIBC_INLINE_VAR constexpr size_t N_LOGF16_EXCEPTS = 5; +#else +LIBC_INLINE_VAR constexpr size_t N_LOGF16_EXCEPTS = 11; +#endif +LIBC_INLINE_VAR constexpr fputil::ExceptValues<float16, N_LOGF16_EXCEPTS> + LOGF16_EXCEPTS = {{ +// (input, RZ output, RU offset, RD offset, RN offset) +#ifndef LIBC_TARGET_CPU_HAS_FMA_FLOAT + // x = 0x1.61cp-13, logf16(x) = -0x1.16p+3 (RZ) + {0x0987U, 0xc858U, 0U, 1U, 0U}, + // x = 0x1.f2p-12, logf16(x) = -0x1.e98p+2 (RZ) + {0x0fc8U, 0xc7a6U, 0U, 1U, 1U}, +#endif + // x = 0x1.4d4p-9, logf16(x) = -0x1.7e4p+2 (RZ) + {0x1935U, 0xc5f9U, 0U, 1U, 0U}, + // x = 0x1.5ep-8, logf16(x) = -0x1.4ecp+2 (RZ) + {0x1d78U, 0xc53bU, 0U, 1U, 0U}, +#ifndef LIBC_TARGET_CPU_HAS_FMA_FLOAT + // x = 0x1.fdp-1, logf16(x) = -0x1.81p-8 (RZ) + {0x3bf4U, 0x9e04U, 0U, 1U, 1U}, + // x = 0x1.fep-1, logf16(x) = -0x1.008p-8 (RZ) + {0x3bf8U, 0x9c02U, 0U, 1U, 0U}, +#endif + // x = 0x1.ffp-1, logf16(x) = -0x1.004p-9 (RZ) + {0x3bfcU, 0x9801U, 0U, 1U, 0U}, + // x = 0x1.ff8p-1, logf16(x) = -0x1p-10 (RZ) + {0x3bfeU, 0x9400U, 0U, 1U, 1U}, +#ifdef LIBC_TARGET_CPU_HAS_FMA_FLOAT + // x = 0x1.4c4p+1, logf16(x) = 0x1.e84p-1 (RZ) + {0x4131U, 0x3ba1U, 1U, 0U, 1U}, +#else + // x = 0x1.75p+2, logf16(x) = 0x1.c34p+0 (RZ) + {0x45d4U, 0x3f0dU, 1U, 0U, 0U}, + // x = 0x1.75p+2, logf16(x) = 0x1.c34p+0 (RZ) + {0x45d4U, 0x3f0dU, 1U, 0U, 0U}, + // x = 0x1.d5p+9, logf16(x) = 0x1.b5cp+2 (RZ) + {0x6354U, 0x46d7U, 1U, 0U, 1U}, +#endif + }}; +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + +} // namespace logf16_internal + +LIBC_INLINE static float16 logf16(float16 x) { + using namespace math::expxf16_internal; + using namespace math::logf16_internal; + using FPBits = fputil::FPBits<float16>; + FPBits x_bits(x); + + uint16_t x_u = x_bits.uintval(); + + // If x <= 0, or x is 1, or x is +inf, or x is NaN. + if (LIBC_UNLIKELY(x_u == 0U || x_u == 0x3c00U || x_u >= 0x7c00U)) { + // log(NaN) = NaN + if (x_bits.is_nan()) { + if (x_bits.is_signaling_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + + return x; + } + + // log(+/-0) = −inf + if ((x_u & 0x7fffU) == 0U) { + fputil::raise_except_if_required(FE_DIVBYZERO); + return FPBits::inf(Sign::NEG).get_val(); + } + + if (x_u == 0x3c00U) + return FPBits::zero().get_val(); + + // When x < 0. + if (x_u > 0x8000U) { + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + + // log(+inf) = +inf + return FPBits::inf().get_val(); + } + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + if (auto r = LOGF16_EXCEPTS.lookup(x_u); LIBC_UNLIKELY(r.has_value())) + return r.value(); +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + + // To compute log(x), we perform the following range reduction: + // x = 2^m * 1.mant, + // log(x) = m * log(2) + log(1.mant). + // To compute log(1.mant), let f be the highest 6 bits including the hidden + // bit, and d be the difference (1.mant - f), i.e., the remaining 5 bits of + // the mantissa, then: + // log(1.mant) = log(f) + log(1.mant / f) + // = log(f) + log(1 + d/f) + // since d/f is sufficiently small. + // We store log(f) and 1/f in the lookup tables LOGF_F and ONE_OVER_F_F + // respectively. + + int m = -FPBits::EXP_BIAS; + + // When x is subnormal, normalize it. + if ((x_u & FPBits::EXP_MASK) == 0U) { + // Can't pass an integer to fputil::cast directly. + constexpr float NORMALIZE_EXP = 1U << FPBits::FRACTION_LEN; + x_bits = FPBits(x_bits.get_val() * fputil::cast<float16>(NORMALIZE_EXP)); + x_u = x_bits.uintval(); + m -= FPBits::FRACTION_LEN; + } + + uint16_t mant = x_bits.get_mantissa(); + // Leading 10 - 5 = 5 bits of the mantissa. + int f = mant >> 5; + // Unbiased exponent. + m += x_u >> FPBits::FRACTION_LEN; + + // Set bits to 1.mant instead of 2^m * 1.mant. + x_bits.set_biased_exponent(FPBits::EXP_BIAS); + float mant_f = x_bits.get_val(); + // v = 1.mant * 1/f - 1 = d/f + float v = fputil::multiply_add(mant_f, ONE_OVER_F_F[f], -1.0f); + + // Degree-3 minimax polynomial generated by Sollya with the following + // commands: + // > display = hexadecimal; + // > P = fpminimax(log(1 + x)/x, 2, [|SG...|], [-2^-5, 2^-5]); + // > x * P; + float log1p_d_over_f = + v * fputil::polyeval(v, 0x1p+0f, -0x1.001804p-1f, 0x1.557ef6p-2f); + // log(1.mant) = log(f) + log(1 + d/f) + float log_1_mant = LOGF_F[f] + log1p_d_over_f; + return fputil::cast<float16>( + fputil::multiply_add(static_cast<float>(m), LOGF_2, log_1_mant)); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_TYPES_HAS_FLOAT16 + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_LOGF16_H diff --git a/libc/src/__support/math/range_reduction.h b/libc/src/__support/math/range_reduction.h index e3f25e4..b813b2e 100644 --- a/libc/src/__support/math/range_reduction.h +++ b/libc/src/__support/math/range_reduction.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LIBC_SRC___SUPPORT_MATH_RANGE_REDUCTION_H -#define LIBC_SRC___SUPPORT_MATH_RANGE_REDUCTION_H +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_RANGE_REDUCTION_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_RANGE_REDUCTION_H #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/multiply_add.h" @@ -87,4 +87,4 @@ LIBC_INLINE int64_t large_range_reduction(double x, int x_exp, double &y) { } // namespace LIBC_NAMESPACE_DECL -#endif // LIBC_SRC___SUPPORT_MATH_RANGE_REDUCTION_H +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_RANGE_REDUCTION_H diff --git a/libc/src/__support/math/range_reduction_fma.h b/libc/src/__support/math/range_reduction_fma.h index c06a1d8..d8676d0 100644 --- a/libc/src/__support/math/range_reduction_fma.h +++ b/libc/src/__support/math/range_reduction_fma.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LIBC_SRC___SUPPORT_MATH_RANGE_REDUCTION_FMA_H -#define LIBC_SRC___SUPPORT_MATH_RANGE_REDUCTION_FMA_H +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_RANGE_REDUCTION_FMA_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_RANGE_REDUCTION_FMA_H #include "src/__support/FPUtil/FMA.h" #include "src/__support/FPUtil/FPBits.h" @@ -89,4 +89,4 @@ LIBC_INLINE int64_t large_range_reduction(double x, int x_exp, double &y) { } // namespace LIBC_NAMESPACE_DECL -#endif // LIBC_SRC___SUPPORT_MATH_RANGE_REDUCTION_FMA_H +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_RANGE_REDUCTION_FMA_H diff --git a/libc/src/__support/math/sin.h b/libc/src/__support/math/sin.h index af1eb59..3a67af0 100644 --- a/libc/src/__support/math/sin.h +++ b/libc/src/__support/math/sin.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LIBC_SRC___SUPPORT_MATH_SIN_H -#define LIBC_SRC___SUPPORT_MATH_SIN_H +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_SIN_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_SIN_H #include "range_reduction_double_common.h" #include "sincos_eval.h" @@ -178,4 +178,4 @@ LIBC_INLINE static constexpr double sin(double x) { } // namespace LIBC_NAMESPACE_DECL -#endif // LIBC_SRC___SUPPORT_MATH_SIN_H +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_SIN_H diff --git a/libc/src/__support/math/sincosf_utils.h b/libc/src/__support/math/sincosf_utils.h index ed9d9f6..62586c2 100644 --- a/libc/src/__support/math/sincosf_utils.h +++ b/libc/src/__support/math/sincosf_utils.h @@ -6,8 +6,8 @@ // //===----------------------------------------------------------------------===// -#ifndef LIBC_SRC___SUPPORT_MATH_SINCOSF_UTILS_H -#define LIBC_SRC___SUPPORT_MATH_SINCOSF_UTILS_H +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_SINCOSF_UTILS_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_SINCOSF_UTILS_H #include "src/__support/FPUtil/FPBits.h" #include "src/__support/FPUtil/PolyEval.h" @@ -122,4 +122,4 @@ LIBC_INLINE void sincospif_eval(double xd, double &sin_k, double &cos_k, } // namespace LIBC_NAMESPACE_DECL -#endif // LIBC_SRC___SUPPORT_MATH_SINCOSF_UTILS_H +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_SINCOSF_UTILS_H diff --git a/libc/src/__support/math/sinf.h b/libc/src/__support/math/sinf.h new file mode 100644 index 0000000..9290444b --- /dev/null +++ b/libc/src/__support/math/sinf.h @@ -0,0 +1,194 @@ +//===-- Single-precision sin function -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_SINF_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_SINF_H + +#include "src/__support/FPUtil/BasicOperations.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/PolyEval.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/FPUtil/rounding_mode.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY +#include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA + +#if defined(LIBC_MATH_HAS_SKIP_ACCURATE_PASS) && \ + defined(LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT) && \ + defined(LIBC_TARGET_CPU_HAS_FMA_FLOAT) + +#include "sincosf_float_eval.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +LIBC_INLINE static float sinf(float x) { + return math::sincosf_float_eval::sincosf_eval</*IS_SIN*/ true>(x); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#else // !LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT + +#include "src/__support/math/sincosf_utils.h" + +#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE +#include "src/__support/math/range_reduction_fma.h" +#else // !LIBC_TARGET_CPU_HAS_FMA_DOUBLE +#include "src/__support/math/range_reduction.h" +#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +LIBC_INLINE static float sinf(float x) { + using FPBits = typename fputil::FPBits<float>; + FPBits xbits(x); + + uint32_t x_u = xbits.uintval(); + uint32_t x_abs = x_u & 0x7fff'ffffU; + double xd = static_cast<double>(x); + + // Range reduction: + // For |x| > pi/32, we perform range reduction as follows: + // Find k and y such that: + // x = (k + y) * pi/32 + // k is an integer + // |y| < 0.5 + // For small range (|x| < 2^45 when FMA instructions are available, 2^22 + // otherwise), this is done by performing: + // k = round(x * 32/pi) + // y = x * 32/pi - k + // For large range, we will omit all the higher parts of 32/pi such that the + // least significant bits of their full products with x are larger than 63, + // since sin((k + y + 64*i) * pi/32) = sin(x + i * 2pi) = sin(x). + // + // When FMA instructions are not available, we store the digits of 32/pi in + // chunks of 28-bit precision. This will make sure that the products: + // x * THIRTYTWO_OVER_PI_28[i] are all exact. + // When FMA instructions are available, we simply store the digits of 32/pi in + // chunks of doubles (53-bit of precision). + // So when multiplying by the largest values of single precision, the + // resulting output should be correct up to 2^(-208 + 128) ~ 2^-80. By the + // worst-case analysis of range reduction, |y| >= 2^-38, so this should give + // us more than 40 bits of accuracy. For the worst-case estimation of range + // reduction, see for instances: + // Elementary Functions by J-M. Muller, Chapter 11, + // Handbook of Floating-Point Arithmetic by J-M. Muller et. al., + // Chapter 10.2. + // + // Once k and y are computed, we then deduce the answer by the sine of sum + // formula: + // sin(x) = sin((k + y)*pi/32) + // = sin(y*pi/32) * cos(k*pi/32) + cos(y*pi/32) * sin(k*pi/32) + // The values of sin(k*pi/32) and cos(k*pi/32) for k = 0..31 are precomputed + // and stored using a vector of 32 doubles. Sin(y*pi/32) and cos(y*pi/32) are + // computed using degree-7 and degree-6 minimax polynomials generated by + // Sollya respectively. + + // |x| <= pi/16 + if (LIBC_UNLIKELY(x_abs <= 0x3e49'0fdbU)) { + + // |x| < 0x1.d12ed2p-12f + if (LIBC_UNLIKELY(x_abs < 0x39e8'9769U)) { + if (LIBC_UNLIKELY(x_abs == 0U)) { + // For signed zeros. + return x; + } + // When |x| < 2^-12, the relative error of the approximation sin(x) ~ x + // is: + // |sin(x) - x| / |sin(x)| < |x^3| / (6|x|) + // = x^2 / 6 + // < 2^-25 + // < epsilon(1)/2. + // So the correctly rounded values of sin(x) are: + // = x - sign(x)*eps(x) if rounding mode = FE_TOWARDZERO, + // or (rounding mode = FE_UPWARD and x is + // negative), + // = x otherwise. + // To simplify the rounding decision and make it more efficient, we use + // fma(x, -2^-25, x) instead. + // An exhaustive test shows that this formula work correctly for all + // rounding modes up to |x| < 0x1.c555dep-11f. + // Note: to use the formula x - 2^-25*x to decide the correct rounding, we + // do need fma(x, -2^-25, x) to prevent underflow caused by -2^-25*x when + // |x| < 2^-125. For targets without FMA instructions, we simply use + // double for intermediate results as it is more efficient than using an + // emulated version of FMA. +#if defined(LIBC_TARGET_CPU_HAS_FMA_FLOAT) + return fputil::multiply_add(x, -0x1.0p-25f, x); +#else + return static_cast<float>(fputil::multiply_add(xd, -0x1.0p-25, xd)); +#endif // LIBC_TARGET_CPU_HAS_FMA_FLOAT + } + + // |x| < pi/16. + double xsq = xd * xd; + + // Degree-9 polynomial approximation: + // sin(x) ~ x + a_3 x^3 + a_5 x^5 + a_7 x^7 + a_9 x^9 + // = x (1 + a_3 x^2 + ... + a_9 x^8) + // = x * P(x^2) + // generated by Sollya with the following commands: + // > display = hexadecimal; + // > Q = fpminimax(sin(x)/x, [|0, 2, 4, 6, 8|], [|1, D...|], [0, pi/16]); + double result = + fputil::polyeval(xsq, 1.0, -0x1.55555555554c6p-3, 0x1.1111111085e65p-7, + -0x1.a019f70fb4d4fp-13, 0x1.718d179815e74p-19); + return static_cast<float>(xd * result); + } + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + if (LIBC_UNLIKELY(x_abs == 0x4619'9998U)) { // x = 0x1.33333p13 + float r = -0x1.63f4bap-2f; + int rounding = fputil::quick_get_round(); + if ((rounding == FE_DOWNWARD && xbits.is_pos()) || + (rounding == FE_UPWARD && xbits.is_neg())) + r = -0x1.63f4bcp-2f; + return xbits.is_neg() ? -r : r; + } +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + + if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) { + if (xbits.is_signaling_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + + if (x_abs == 0x7f80'0000U) { + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_INVALID); + } + return x + FPBits::quiet_nan().get_val(); + } + + // Combine the results with the sine of sum formula: + // sin(x) = sin((k + y)*pi/32) + // = sin(y*pi/32) * cos(k*pi/32) + cos(y*pi/32) * sin(k*pi/32) + // = sin_y * cos_k + (1 + cosm1_y) * sin_k + // = sin_y * cos_k + (cosm1_y * sin_k + sin_k) + double sin_k, cos_k, sin_y, cosm1_y; + + sincosf_eval(xd, x_abs, sin_k, cos_k, sin_y, cosm1_y); + + return static_cast<float>(fputil::multiply_add( + sin_y, cos_k, fputil::multiply_add(cosm1_y, sin_k, sin_k))); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_SINF_H diff --git a/libc/src/__support/math/sinf16.h b/libc/src/__support/math/sinf16.h new file mode 100644 index 0000000..e18d0cf --- /dev/null +++ b/libc/src/__support/math/sinf16.h @@ -0,0 +1,136 @@ +//===-- Half-precision sin(x) function ------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_SINF16_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_SINF16_H + +#include "include/llvm-libc-macros/float16-macros.h" + +#ifdef LIBC_TYPES_HAS_FLOAT16 + +#include "hdr/errno_macros.h" +#include "hdr/fenv_macros.h" +#include "sincosf16_utils.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/cast.h" +#include "src/__support/FPUtil/except_value_utils.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/macros/optimization.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +namespace sinf16_internal { + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS +LIBC_INLINE_VAR constexpr size_t N_EXCEPTS = 4; + +LIBC_INLINE_VAR constexpr fputil::ExceptValues<float16, N_EXCEPTS> + SINF16_EXCEPTS{{ + // (input, RZ output, RU offset, RD offset, RN offset) + {0x2b45, 0x2b43, 1, 0, 1}, + {0x585c, 0x3ba3, 1, 0, 1}, + {0x5cb0, 0xbbff, 0, 1, 0}, + {0x51f5, 0xb80f, 0, 1, 0}, + }}; +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + +} // namespace sinf16_internal + +LIBC_INLINE static float16 sinf16(float16 x) { + using namespace sinf16_internal; + using namespace sincosf16_internal; + using FPBits = fputil::FPBits<float16>; + FPBits xbits(x); + + uint16_t x_u = xbits.uintval(); + uint16_t x_abs = x_u & 0x7fff; + float xf = x; + + // Range reduction: + // For |x| > pi/32, we perform range reduction as follows: + // Find k and y such that: + // x = (k + y) * pi/32 + // k is an integer, |y| < 0.5 + // + // This is done by performing: + // k = round(x * 32/pi) + // y = x * 32/pi - k + // + // Once k and y are computed, we then deduce the answer by the sine of sum + // formula: + // sin(x) = sin((k + y) * pi/32) + // = sin(k * pi/32) * cos(y * pi/32) + + // sin(y * pi/32) * cos(k * pi/32) + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + // Handle exceptional values + bool x_sign = x_u >> 15; + + if (auto r = SINF16_EXCEPTS.lookup_odd(x_abs, x_sign); + LIBC_UNLIKELY(r.has_value())) + return r.value(); +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + + int rounding = fputil::quick_get_round(); + + // Exhaustive tests show that for |x| <= 0x1.f4p-11, 1ULP rounding errors + // occur. To fix this, the following apply: + if (LIBC_UNLIKELY(x_abs <= 0x13d0)) { + // sin(+/-0) = +/-0 + if (LIBC_UNLIKELY(x_abs == 0U)) + return x; + + // When x > 0, and rounding upward, sin(x) == x. + // When x < 0, and rounding downward, sin(x) == x. + if ((rounding == FE_UPWARD && xbits.is_pos()) || + (rounding == FE_DOWNWARD && xbits.is_neg())) + return x; + + // When x < 0, and rounding upward, sin(x) == (x - 1ULP) + if (rounding == FE_UPWARD && xbits.is_neg()) { + x_u--; + return FPBits(x_u).get_val(); + } + } + + if (xbits.is_inf_or_nan()) { + if (xbits.is_signaling_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + + if (xbits.is_inf()) { + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_INVALID); + } + + return x + FPBits::quiet_nan().get_val(); + } + + float sin_k, cos_k, sin_y, cosm1_y; + sincosf16_eval(xf, sin_k, cos_k, sin_y, cosm1_y); + + if (LIBC_UNLIKELY(sin_y == 0 && sin_k == 0)) + return FPBits::zero(xbits.sign()).get_val(); + + // Since, cosm1_y = cos_y - 1, therefore: + // sin(x) = cos_k * sin_y + sin_k + (cosm1_y * sin_k) + return fputil::cast<float16>(fputil::multiply_add( + sin_y, cos_k, fputil::multiply_add(cosm1_y, sin_k, sin_k))); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_TYPES_HAS_FLOAT16 + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_SINF16_H diff --git a/libc/src/__support/math/sinhf.h b/libc/src/__support/math/sinhf.h new file mode 100644 index 0000000..e8efc29 --- /dev/null +++ b/libc/src/__support/math/sinhf.h @@ -0,0 +1,88 @@ +//===-- Single-precision sinh function ------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_SINHF_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_SINHF_H + +#include "sinhfcoshf_utils.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/rounding_mode.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +LIBC_INLINE static constexpr float sinhf(float x) { + using FPBits = typename fputil::FPBits<float>; + FPBits xbits(x); + uint32_t x_abs = xbits.abs().uintval(); + + // When |x| >= 90, or x is inf or nan + if (LIBC_UNLIKELY(x_abs >= 0x42b4'0000U || x_abs <= 0x3da0'0000U)) { + // |x| <= 0.078125 + if (x_abs <= 0x3da0'0000U) { +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + // |x| = 0.0005589424981735646724700927734375 + if (LIBC_UNLIKELY(x_abs == 0x3a12'85ffU)) { + if (fputil::fenv_is_round_to_nearest()) + return x; + } +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + + // |x| <= 2^-26 + if (LIBC_UNLIKELY(x_abs <= 0x3280'0000U)) { + return static_cast<float>( + LIBC_UNLIKELY(x_abs == 0) ? x : (x + 0.25 * x * x * x)); + } + + double xdbl = x; + double x2 = xdbl * xdbl; + // Sollya: fpminimax(sinh(x),[|3,5,7|],[|D...|],[-1/16-1/64;1/16+1/64],x); + // Sollya output: x * (0x1p0 + x^0x1p1 * (0x1.5555555556583p-3 + x^0x1p1 + // * (0x1.111110d239f1fp-7 + // + x^0x1p1 * 0x1.a02b5a284013cp-13))) + // Therefore, output of Sollya = x * pe; + double pe = fputil::polyeval(x2, 0.0, 0x1.5555555556583p-3, + 0x1.111110d239f1fp-7, 0x1.a02b5a284013cp-13); + return static_cast<float>(fputil::multiply_add(xdbl, pe, xdbl)); + } + + if (xbits.is_nan()) + return x + 1.0f; // sNaN to qNaN + signal + + if (xbits.is_inf()) + return x; + + int rounding = fputil::quick_get_round(); + if (xbits.is_neg()) { + if (LIBC_UNLIKELY(rounding == FE_UPWARD || rounding == FE_TOWARDZERO)) + return -FPBits::max_normal().get_val(); + } else { + if (LIBC_UNLIKELY(rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)) + return FPBits::max_normal().get_val(); + } + + fputil::set_errno_if_required(ERANGE); + fputil::raise_except_if_required(FE_OVERFLOW); + + return x + FPBits::inf(xbits.sign()).get_val(); + } + + // sinh(x) = (e^x - e^(-x)) / 2. + return static_cast<float>( + math::sinhfcoshf_internal::exp_pm_eval</*is_sinh*/ true>(x)); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_SINHF_H diff --git a/libc/src/__support/math/sinhf16.h b/libc/src/__support/math/sinhf16.h new file mode 100644 index 0000000..df9b82c --- /dev/null +++ b/libc/src/__support/math/sinhf16.h @@ -0,0 +1,168 @@ +//===-- Half-precision sinh(x) function -----------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_SINHF16_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_SINHF16_H + +#include "include/llvm-libc-macros/float16-macros.h" + +#ifdef LIBC_TYPES_HAS_FLOAT16 + +#include "expxf16_utils.h" +#include "hdr/errno_macros.h" +#include "hdr/fenv_macros.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/except_value_utils.h" +#include "src/__support/FPUtil/rounding_mode.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +LIBC_INLINE static constexpr float16 sinhf16(float16 x) { + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + constexpr fputil::ExceptValues<float16, 17> SINHF16_EXCEPTS_POS = {{ + // x = 0x1.714p-5, sinhf16(x) = 0x1.714p-5 (RZ) + {0x29c5U, 0x29c5U, 1U, 0U, 1U}, + // x = 0x1.25p-4, sinhf16(x) = 0x1.25p-4 (RZ) + {0x2c94U, 0x2c94U, 1U, 0U, 1U}, + // x = 0x1.f5p-4, sinhf16(x) = 0x1.f64p-4 (RZ) + {0x2fd4U, 0x2fd9U, 1U, 0U, 0U}, + // x = 0x1.b1cp-3, sinhf16(x) = 0x1.b4cp-3 (RZ) + {0x32c7U, 0x32d3U, 1U, 0U, 1U}, + // x = 0x1.6e8p-2, sinhf16(x) = 0x1.764p-2 (RZ) + {0x35baU, 0x35d9U, 1U, 0U, 1U}, + // x = 0x1.6b4p-1, sinhf16(x) = 0x1.8a4p-1 (RZ) + {0x39adU, 0x3a29U, 1U, 0U, 1U}, + // x = 0x1.a58p-1, sinhf16(x) = 0x1.d68p-1 (RZ) + {0x3a96U, 0x3b5aU, 1U, 0U, 1U}, + // x = 0x1.574p+0, sinhf16(x) = 0x1.c78p+0 (RZ) + {0x3d5dU, 0x3f1eU, 1U, 0U, 1U}, + // x = 0x1.648p+1, sinhf16(x) = 0x1.024p+3 (RZ) + {0x4192U, 0x4809U, 1U, 0U, 0U}, + // x = 0x1.cdcp+1, sinhf16(x) = 0x1.26cp+4 (RZ) + {0x4337U, 0x4c9bU, 1U, 0U, 0U}, + // x = 0x1.d0cp+1, sinhf16(x) = 0x1.2d8p+4 (RZ) + {0x4343U, 0x4cb6U, 1U, 0U, 1U}, + // x = 0x1.018p+2, sinhf16(x) = 0x1.bfp+4 (RZ) + {0x4406U, 0x4efcU, 1U, 0U, 0U}, + // x = 0x1.2fcp+2, sinhf16(x) = 0x1.cc4p+5 (RZ) + {0x44bfU, 0x5331U, 1U, 0U, 1U}, + // x = 0x1.4ecp+2, sinhf16(x) = 0x1.75cp+6 (RZ) + {0x453bU, 0x55d7U, 1U, 0U, 0U}, + // x = 0x1.8a4p+2, sinhf16(x) = 0x1.d94p+7 (RZ) + {0x4629U, 0x5b65U, 1U, 0U, 1U}, + // x = 0x1.5fp+3, sinhf16(x) = 0x1.c54p+14 (RZ) + {0x497cU, 0x7715U, 1U, 0U, 1U}, + // x = 0x1.3c8p+1, sinhf16(x) = 0x1.78ap+2 (RZ) + {0x40f2U, 0x45e2U, 1U, 0U, 1U}, + }}; + + constexpr fputil::ExceptValues<float16, 13> SINHF16_EXCEPTS_NEG = {{ + // x = -0x1.714p-5, sinhf16(x) = -0x1.714p-5 (RZ) + {0xa9c5U, 0xa9c5U, 0U, 1U, 1U}, + // x = -0x1.25p-4, sinhf16(x) = -0x1.25p-4 (RZ) + {0xac94U, 0xac94U, 0U, 1U, 1U}, + // x = -0x1.f5p-4, sinhf16(x) = -0x1.f64p-4 (RZ) + {0xafd4U, 0xafd9U, 0U, 1U, 0U}, + // x = -0x1.6e8p-2, sinhf16(x) = -0x1.764p-2 (RZ) + {0xb5baU, 0xb5d9U, 0U, 1U, 1U}, + // x = -0x1.a58p-1, sinhf16(x) = -0x1.d68p-1 (RZ) + {0xba96U, 0xbb5aU, 0U, 1U, 1U}, + // x = -0x1.cdcp+1, sinhf16(x) = -0x1.26cp+4 (RZ) + {0xc337U, 0xcc9bU, 0U, 1U, 0U}, + // x = -0x1.d0cp+1, sinhf16(x) = -0x1.2d8p+4 (RZ) + {0xc343U, 0xccb6U, 0U, 1U, 1U}, + // x = -0x1.018p+2, sinhf16(x) = -0x1.bfp+4 (RZ) + {0xc406U, 0xcefcU, 0U, 1U, 0U}, + // x = -0x1.2fcp+2, sinhf16(x) = -0x1.cc4p+5 (RZ) + {0xc4bfU, 0xd331U, 0U, 1U, 1U}, + // x = -0x1.4ecp+2, sinhf16(x) = -0x1.75cp+6 (RZ) + {0xc53bU, 0xd5d7U, 0U, 1U, 0U}, + // x = -0x1.8a4p+2, sinhf16(x) = -0x1.d94p+7 (RZ) + {0xc629U, 0xdb65U, 0U, 1U, 1U}, + // x = -0x1.5fp+3, sinhf16(x) = -0x1.c54p+14 (RZ) + {0xc97cU, 0xf715U, 0U, 1U, 1U}, + // x = -0x1.3c8p+1, sinhf16(x) = -0x1.78ap+2 (RZ) + {0xc0f2U, 0xc5e2U, 0U, 1U, 1U}, + }}; +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + + using namespace math::expxf16_internal; + using FPBits = fputil::FPBits<float16>; + FPBits x_bits(x); + + uint16_t x_u = x_bits.uintval(); + uint16_t x_abs = x_u & 0x7fffU; + + // When |x| = 0, or -2^(-14) <= x <= -2^(-9), or |x| >= asinh(2^16), or x is + // NaN. + if (LIBC_UNLIKELY(x_abs == 0U || (x_u >= 0x8400U && x_u <= 0xa400U) || + x_abs >= 0x49e5U)) { + // sinh(NaN) = NaN + if (x_bits.is_nan()) { + if (x_bits.is_signaling_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + + return x; + } + + // sinh(+/-0) = sinh(+/-0) + if (x_abs == 0U) + return FPBits::zero(x_bits.sign()).get_val(); + + // When |x| >= asinh(2^16). + if (x_abs >= 0x49e5U) { + // sinh(+/-inf) = +/-inf + if (x_bits.is_inf()) + return FPBits::inf(x_bits.sign()).get_val(); + + int rounding_mode = fputil::quick_get_round(); + if (rounding_mode == FE_TONEAREST || + (x_bits.is_pos() && rounding_mode == FE_UPWARD) || + (x_bits.is_neg() && rounding_mode == FE_DOWNWARD)) { + fputil::set_errno_if_required(ERANGE); + fputil::raise_except_if_required(FE_OVERFLOW | FE_INEXACT); + return FPBits::inf(x_bits.sign()).get_val(); + } + return FPBits::max_normal(x_bits.sign()).get_val(); + } + + // When -2^(-14) <= x <= -2^(-9). + if (fputil::fenv_is_round_down()) + return FPBits(static_cast<uint16_t>(x_u + 1)).get_val(); + return FPBits(static_cast<uint16_t>(x_u)).get_val(); + } + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + if (x_bits.is_pos()) { + if (auto r = SINHF16_EXCEPTS_POS.lookup(x_u); LIBC_UNLIKELY(r.has_value())) + return r.value(); + } else { + if (auto r = SINHF16_EXCEPTS_NEG.lookup(x_u); LIBC_UNLIKELY(r.has_value())) + return r.value(); + } +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + + return eval_sinh_or_cosh</*IsSinh=*/true>(x); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_TYPES_HAS_FLOAT16 + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_SINHF16_H diff --git a/libc/src/__support/math/sinpif.h b/libc/src/__support/math/sinpif.h new file mode 100644 index 0000000..8f15703 --- /dev/null +++ b/libc/src/__support/math/sinpif.h @@ -0,0 +1,123 @@ +//===-- Implementation header for sinpif ---------------------------* C++*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_SINPIF_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_SINPIF_H + +#include "sincosf_utils.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/PolyEval.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/common.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY + +namespace LIBC_NAMESPACE_DECL { +namespace math { + +LIBC_INLINE static float sinpif(float x) { + using FPBits = typename fputil::FPBits<float>; + FPBits xbits(x); + + uint32_t x_u = xbits.uintval(); + uint32_t x_abs = x_u & 0x7fff'ffffU; + double xd = static_cast<double>(x); + + // Range reduction: + // For |x| > 1/32, we perform range reduction as follows: + // Find k and y such that: + // x = (k + y) * 1/32 + // k is an integer + // |y| < 0.5 + // + // This is done by performing: + // k = round(x * 32) + // y = x * 32 - k + // + // Once k and y are computed, we then deduce the answer by the sine of sum + // formula: + // sin(x * pi) = sin((k + y)*pi/32) + // = sin(y*pi/32) * cos(k*pi/32) + cos(y*pi/32) * sin(k*pi/32) + // The values of sin(k*pi/32) and cos(k*pi/32) for k = 0..31 are precomputed + // and stored using a vector of 32 doubles. Sin(y*pi/32) and cos(y*pi/32) are + // computed using degree-7 and degree-6 minimax polynomials generated by + // Sollya respectively. + + // |x| <= 1/16 + if (LIBC_UNLIKELY(x_abs <= 0x3d80'0000U)) { + + if (LIBC_UNLIKELY(x_abs < 0x33CD'01D7U)) { + if (LIBC_UNLIKELY(x_abs == 0U)) { + // For signed zeros. + return x; + } + + // For very small values we can approximate sinpi(x) with x * pi + // An exhaustive test shows that this is accurate for |x| < 9.546391 × + // 10-8 + double xdpi = xd * 0x1.921fb54442d18p1; + return static_cast<float>(xdpi); + } + + // |x| < 1/16. + double xsq = xd * xd; + + // Degree-9 polynomial approximation: + // sinpi(x) ~ x + a_3 x^3 + a_5 x^5 + a_7 x^7 + a_9 x^9 + // = x (1 + a_3 x^2 + ... + a_9 x^8) + // = x * P(x^2) + // generated by Sollya with the following commands: + // > display = hexadecimal; + // > Q = fpminimax(sin(pi * x)/x, [|0, 2, 4, 6, 8|], [|D...|], [0, 1/16]); + double result = fputil::polyeval( + xsq, 0x1.921fb54442d18p1, -0x1.4abbce625bbf2p2, 0x1.466bc675e116ap1, + -0x1.32d2c0b62d41cp-1, 0x1.501ec4497cb7dp-4); + return static_cast<float>(xd * result); + } + + // Numbers greater or equal to 2^23 are always integers or NaN + if (LIBC_UNLIKELY(x_abs >= 0x4B00'0000)) { + + // check for NaN values + if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) { + if (xbits.is_signaling_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + + if (x_abs == 0x7f80'0000U) { + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_INVALID); + } + + return x + FPBits::quiet_nan().get_val(); + } + + return FPBits::zero(xbits.sign()).get_val(); + } + + // Combine the results with the sine of sum formula: + // sin(x * pi) = sin((k + y)*pi/32) + // = sin(y*pi/32) * cos(k*pi/32) + cos(y*pi/32) * sin(k*pi/32) + // = sin_y * cos_k + (1 + cosm1_y) * sin_k + // = sin_y * cos_k + (cosm1_y * sin_k + sin_k) + double sin_k = 0, cos_k = 0, sin_y = 0, cosm1_y = 0; + sincospif_eval(xd, sin_k, cos_k, sin_y, cosm1_y); + + if (LIBC_UNLIKELY(sin_y == 0 && sin_k == 0)) + return FPBits::zero(xbits.sign()).get_val(); + + return static_cast<float>(fputil::multiply_add( + sin_y, cos_k, fputil::multiply_add(cosm1_y, sin_k, sin_k))); +} + +} // namespace math +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_SINPIF_H diff --git a/libc/src/__support/math/sqrt.h b/libc/src/__support/math/sqrt.h new file mode 100644 index 0000000..3faa62d --- /dev/null +++ b/libc/src/__support/math/sqrt.h @@ -0,0 +1,24 @@ +//===-- Implementation header for sqrt --------------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_SQRT_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_SQRT_H + +#include "src/__support/FPUtil/sqrt.h" + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +LIBC_INLINE static double sqrt(double x) { return fputil::sqrt<double>(x); } + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_SQRT_H diff --git a/libc/src/__support/math/sqrtf16.h b/libc/src/__support/math/sqrtf16.h new file mode 100644 index 0000000..8c9e1e6 --- /dev/null +++ b/libc/src/__support/math/sqrtf16.h @@ -0,0 +1,31 @@ +//===-- Implementation header for sqrtf16 -----------------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_SQRTF16_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_SQRTF16_H + +#include "include/llvm-libc-macros/float16-macros.h" + +#ifdef LIBC_TYPES_HAS_FLOAT16 + +#include "src/__support/FPUtil/sqrt.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { +namespace math { + +LIBC_INLINE static constexpr float16 sqrtf16(float16 x) { + return fputil::sqrt<float16>(x); +} + +} // namespace math +} // namespace LIBC_NAMESPACE_DECL + +#endif // LIBC_TYPES_HAS_FLOAT16 + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_SQRTF16_H diff --git a/libc/src/__support/math/tan.h b/libc/src/__support/math/tan.h new file mode 100644 index 0000000..f7566bd --- /dev/null +++ b/libc/src/__support/math/tan.h @@ -0,0 +1,305 @@ +//===-- Double-precision tan function -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_TAN_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_TAN_H + +#include "hdr/errno_macros.h" +#include "range_reduction_double_common.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/PolyEval.h" +#include "src/__support/FPUtil/double_double.h" +#include "src/__support/FPUtil/dyadic_float.h" +#include "src/__support/FPUtil/except_value_utils.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/FPUtil/rounding_mode.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY +#include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA + +#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE +#include "range_reduction_double_fma.h" +#else +#include "range_reduction_double_nofma.h" +#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +namespace tan_internal { + +using DoubleDouble = fputil::DoubleDouble; +using Float128 = typename fputil::DyadicFloat<128>; + +LIBC_INLINE static double tan_eval(const DoubleDouble &u, + DoubleDouble &result) { + // Evaluate tan(y) = tan(x - k * (pi/128)) + // We use the degree-9 Taylor approximation: + // tan(y) ~ P(y) = y + y^3/3 + 2*y^5/15 + 17*y^7/315 + 62*y^9/2835 + // Then the error is bounded by: + // |tan(y) - P(y)| < 2^-6 * |y|^11 < 2^-6 * 2^-66 = 2^-72. + // For y ~ u_hi + u_lo, fully expanding the polynomial and drop any terms + // < ulp(u_hi^3) gives us: + // P(y) = y + y^3/3 + 2*y^5/15 + 17*y^7/315 + 62*y^9/2835 = ... + // ~ u_hi + u_hi^3 * (1/3 + u_hi^2 * (2/15 + u_hi^2 * (17/315 + + // + u_hi^2 * 62/2835))) + + // + u_lo (1 + u_hi^2 * (1 + u_hi^2 * 2/3)) + double u_hi_sq = u.hi * u.hi; // Error < ulp(u_hi^2) < 2^(-6 - 52) = 2^-58. + // p1 ~ 17/315 + u_hi^2 62 / 2835. + double p1 = + fputil::multiply_add(u_hi_sq, 0x1.664f4882c10fap-6, 0x1.ba1ba1ba1ba1cp-5); + // p2 ~ 1/3 + u_hi^2 2 / 15. + double p2 = + fputil::multiply_add(u_hi_sq, 0x1.1111111111111p-3, 0x1.5555555555555p-2); + // q1 ~ 1 + u_hi^2 * 2/3. + double q1 = fputil::multiply_add(u_hi_sq, 0x1.5555555555555p-1, 1.0); + double u_hi_3 = u_hi_sq * u.hi; + double u_hi_4 = u_hi_sq * u_hi_sq; + // p3 ~ 1/3 + u_hi^2 * (2/15 + u_hi^2 * (17/315 + u_hi^2 * 62/2835)) + double p3 = fputil::multiply_add(u_hi_4, p1, p2); + // q2 ~ 1 + u_hi^2 * (1 + u_hi^2 * 2/3) + double q2 = fputil::multiply_add(u_hi_sq, q1, 1.0); + double tan_lo = fputil::multiply_add(u_hi_3, p3, u.lo * q2); + // Overall, |tan(y) - (u_hi + tan_lo)| < ulp(u_hi^3) <= 2^-71. + // And the relative errors is: + // |(tan(y) - (u_hi + tan_lo)) / tan(y) | <= 2*ulp(u_hi^2) < 2^-64 + result = fputil::exact_add(u.hi, tan_lo); + return fputil::multiply_add(fputil::FPBits<double>(u_hi_3).abs().get_val(), + 0x1.0p-51, 0x1.0p-102); +} + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS +// Accurate evaluation of tan for small u. +[[maybe_unused]] LIBC_INLINE static Float128 tan_eval(const Float128 &u) { + Float128 u_sq = fputil::quick_mul(u, u); + + // tan(x) ~ x + x^3/3 + x^5 * 2/15 + x^7 * 17/315 + x^9 * 62/2835 + + // + x^11 * 1382/155925 + x^13 * 21844/6081075 + + // + x^15 * 929569/638512875 + x^17 * 6404582/10854718875 + // Relative errors < 2^-127 for |u| < pi/256. + constexpr Float128 TAN_COEFFS[] = { + {Sign::POS, -127, 0x80000000'00000000'00000000'00000000_u128}, // 1 + {Sign::POS, -129, 0xaaaaaaaa'aaaaaaaa'aaaaaaaa'aaaaaaab_u128}, // 1 + {Sign::POS, -130, 0x88888888'88888888'88888888'88888889_u128}, // 2/15 + {Sign::POS, -132, 0xdd0dd0dd'0dd0dd0d'd0dd0dd0'dd0dd0dd_u128}, // 17/315 + {Sign::POS, -133, 0xb327a441'6087cf99'6b5dd24e'ec0b327a_u128}, // 62/2835 + {Sign::POS, -134, + 0x91371aaf'3611e47a'da8e1cba'7d900eca_u128}, // 1382/155925 + {Sign::POS, -136, + 0xeb69e870'abeefdaf'e606d2e4'd1e65fbc_u128}, // 21844/6081075 + {Sign::POS, -137, + 0xbed1b229'5baf15b5'0ec9af45'a2619971_u128}, // 929569/638512875 + {Sign::POS, -138, + 0x9aac1240'1b3a2291'1b2ac7e3'e4627d0a_u128}, // 6404582/10854718875 + }; + + return fputil::quick_mul( + u, fputil::polyeval(u_sq, TAN_COEFFS[0], TAN_COEFFS[1], TAN_COEFFS[2], + TAN_COEFFS[3], TAN_COEFFS[4], TAN_COEFFS[5], + TAN_COEFFS[6], TAN_COEFFS[7], TAN_COEFFS[8])); +} + +// Calculation a / b = a * (1/b) for Float128. +// Using the initial approximation of q ~ (1/b), then apply 2 Newton-Raphson +// iterations, before multiplying by a. +[[maybe_unused]] Float128 newton_raphson_div(const Float128 &a, Float128 b, + double q) { + Float128 q0(q); + constexpr Float128 TWO(2.0); + b.sign = (b.sign == Sign::POS) ? Sign::NEG : Sign::POS; + Float128 q1 = + fputil::quick_mul(q0, fputil::quick_add(TWO, fputil::quick_mul(b, q0))); + Float128 q2 = + fputil::quick_mul(q1, fputil::quick_add(TWO, fputil::quick_mul(b, q1))); + return fputil::quick_mul(a, q2); +} +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + +} // namespace tan_internal + +LIBC_INLINE static double tan(double x) { + using namespace tan_internal; + using namespace math::range_reduction_double_internal; + using FPBits = typename fputil::FPBits<double>; + FPBits xbits(x); + + uint16_t x_e = xbits.get_biased_exponent(); + + DoubleDouble y; + unsigned k; + LargeRangeReduction range_reduction_large{}; + + // |x| < 2^16 + if (LIBC_LIKELY(x_e < FPBits::EXP_BIAS + FAST_PASS_EXPONENT)) { + // |x| < 2^-7 + if (LIBC_UNLIKELY(x_e < FPBits::EXP_BIAS - 7)) { + // |x| < 2^-27, |tan(x) - x| < ulp(x)/2. + if (LIBC_UNLIKELY(x_e < FPBits::EXP_BIAS - 27)) { + // Signed zeros. + if (LIBC_UNLIKELY(x == 0.0)) + return x + x; // Make sure it works with FTZ/DAZ. + +#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE + return fputil::multiply_add(x, 0x1.0p-54, x); +#else + if (LIBC_UNLIKELY(x_e < 4)) { + int rounding_mode = fputil::quick_get_round(); + if ((xbits.sign() == Sign::POS && rounding_mode == FE_UPWARD) || + (xbits.sign() == Sign::NEG && rounding_mode == FE_DOWNWARD)) + return FPBits(xbits.uintval() + 1).get_val(); + } + return fputil::multiply_add(x, 0x1.0p-54, x); +#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE + } + // No range reduction needed. + k = 0; + y.lo = 0.0; + y.hi = x; + } else { + // Small range reduction. + k = range_reduction_small(x, y); + } + } else { + // Inf or NaN + if (LIBC_UNLIKELY(x_e > 2 * FPBits::EXP_BIAS)) { + if (xbits.is_signaling_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + // tan(+-Inf) = NaN + if (xbits.get_mantissa() == 0) { + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_INVALID); + } + return x + FPBits::quiet_nan().get_val(); + } + + // Large range reduction. + k = range_reduction_large.fast(x, y); + } + + DoubleDouble tan_y; + [[maybe_unused]] double err = tan_eval(y, tan_y); + + // Look up sin(k * pi/128) and cos(k * pi/128) +#ifdef LIBC_MATH_HAS_SMALL_TABLES + // Memory saving versions. Use 65-entry table: + auto get_idx_dd = [](unsigned kk) -> DoubleDouble { + unsigned idx = (kk & 64) ? 64 - (kk & 63) : (kk & 63); + DoubleDouble ans = SIN_K_PI_OVER_128[idx]; + if (kk & 128) { + ans.hi = -ans.hi; + ans.lo = -ans.lo; + } + return ans; + }; + DoubleDouble msin_k = get_idx_dd(k + 128); + DoubleDouble cos_k = get_idx_dd(k + 64); +#else + // Fast look up version, but needs 256-entry table. + // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). + DoubleDouble msin_k = SIN_K_PI_OVER_128[(k + 128) & 255]; + DoubleDouble cos_k = SIN_K_PI_OVER_128[(k + 64) & 255]; +#endif // LIBC_MATH_HAS_SMALL_TABLES + + // After range reduction, k = round(x * 128 / pi) and y = x - k * (pi / 128). + // So k is an integer and -pi / 256 <= y <= pi / 256. + // Then tan(x) = sin(x) / cos(x) + // = sin((k * pi/128 + y) / cos((k * pi/128 + y) + // = (cos(y) * sin(k*pi/128) + sin(y) * cos(k*pi/128)) / + // / (cos(y) * cos(k*pi/128) - sin(y) * sin(k*pi/128)) + // = (sin(k*pi/128) + tan(y) * cos(k*pi/128)) / + // / (cos(k*pi/128) - tan(y) * sin(k*pi/128)) + DoubleDouble cos_k_tan_y = fputil::quick_mult(tan_y, cos_k); + DoubleDouble msin_k_tan_y = fputil::quick_mult(tan_y, msin_k); + + // num_dd = sin(k*pi/128) + tan(y) * cos(k*pi/128) + DoubleDouble num_dd = fputil::exact_add<false>(cos_k_tan_y.hi, -msin_k.hi); + // den_dd = cos(k*pi/128) - tan(y) * sin(k*pi/128) + DoubleDouble den_dd = fputil::exact_add<false>(msin_k_tan_y.hi, cos_k.hi); + num_dd.lo += cos_k_tan_y.lo - msin_k.lo; + den_dd.lo += msin_k_tan_y.lo + cos_k.lo; + +#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + double tan_x = (num_dd.hi + num_dd.lo) / (den_dd.hi + den_dd.lo); + return tan_x; +#else + // Accurate test and pass for correctly rounded implementation. + + // Accurate double-double division + DoubleDouble tan_x = fputil::div(num_dd, den_dd); + + // Simple error bound: |1 / den_dd| < 2^(1 + floor(-log2(den_dd)))). + uint64_t den_inv = (static_cast<uint64_t>(FPBits::EXP_BIAS + 1) + << (FPBits::FRACTION_LEN + 1)) - + (FPBits(den_dd.hi).uintval() & FPBits::EXP_MASK); + + // For tan_x = (num_dd + err) / (den_dd + err), the error is bounded by: + // | tan_x - num_dd / den_dd | <= err * ( 1 + | tan_x * den_dd | ). + double tan_err = + err * fputil::multiply_add(FPBits(den_inv).get_val(), + FPBits(tan_x.hi).abs().get_val(), 1.0); + + double err_higher = tan_x.lo + tan_err; + double err_lower = tan_x.lo - tan_err; + + double tan_upper = tan_x.hi + err_higher; + double tan_lower = tan_x.hi + err_lower; + + // Ziv's rounding test. + if (LIBC_LIKELY(tan_upper == tan_lower)) + return tan_upper; + + Float128 u_f128; + if (LIBC_LIKELY(x_e < FPBits::EXP_BIAS + FAST_PASS_EXPONENT)) + u_f128 = range_reduction_small_f128(x); + else + u_f128 = range_reduction_large.accurate(); + + Float128 tan_u = tan_eval(u_f128); + + auto get_sin_k = [](unsigned kk) -> Float128 { + unsigned idx = (kk & 64) ? 64 - (kk & 63) : (kk & 63); + Float128 ans = SIN_K_PI_OVER_128_F128[idx]; + if (kk & 128) + ans.sign = Sign::NEG; + return ans; + }; + + // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). + Float128 sin_k_f128 = get_sin_k(k); + Float128 cos_k_f128 = get_sin_k(k + 64); + Float128 msin_k_f128 = get_sin_k(k + 128); + + // num_f128 = sin(k*pi/128) + tan(y) * cos(k*pi/128) + Float128 num_f128 = + fputil::quick_add(sin_k_f128, fputil::quick_mul(cos_k_f128, tan_u)); + // den_f128 = cos(k*pi/128) - tan(y) * sin(k*pi/128) + Float128 den_f128 = + fputil::quick_add(cos_k_f128, fputil::quick_mul(msin_k_f128, tan_u)); + + // tan(x) = (sin(k*pi/128) + tan(y) * cos(k*pi/128)) / + // / (cos(k*pi/128) - tan(y) * sin(k*pi/128)) + // TODO: The initial seed 1.0/den_dd.hi for Newton-Raphson reciprocal can be + // reused from DoubleDouble fputil::div in the fast pass. + Float128 result = newton_raphson_div(num_f128, den_f128, 1.0 / den_dd.hi); + + // TODO: Add assertion if Ziv's accuracy tests fail in debug mode. + // https://github.com/llvm/llvm-project/issues/96452. + return static_cast<double>(result); + +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_TAN_H diff --git a/libc/src/__support/math/tanf.h b/libc/src/__support/math/tanf.h new file mode 100644 index 0000000..139de3c5 --- /dev/null +++ b/libc/src/__support/math/tanf.h @@ -0,0 +1,164 @@ +//===-- Single-precision tan function -------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_MATH_TANF_H +#define LLVM_LIBC_SRC___SUPPORT_MATH_TANF_H + +#include "sincosf_utils.h" +#include "src/__support/FPUtil/FEnvImpl.h" +#include "src/__support/FPUtil/FPBits.h" +#include "src/__support/FPUtil/PolyEval.h" +#include "src/__support/FPUtil/except_value_utils.h" +#include "src/__support/FPUtil/multiply_add.h" +#include "src/__support/FPUtil/nearest_integer.h" +#include "src/__support/macros/config.h" +#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY +#include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA + +namespace LIBC_NAMESPACE_DECL { + +namespace math { + +namespace tanf_internal { + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS +// Exceptional cases for tanf. +LIBC_INLINE_VAR constexpr size_t N_EXCEPTS = 6; + +LIBC_INLINE_VAR constexpr fputil::ExceptValues<float, N_EXCEPTS> TANF_EXCEPTS{{ + // (inputs, RZ output, RU offset, RD offset, RN offset) + // x = 0x1.ada6aap27, tan(x) = 0x1.e80304p-3 (RZ) + {0x4d56d355, 0x3e740182, 1, 0, 0}, + // x = 0x1.862064p33, tan(x) = -0x1.8dee56p-3 (RZ) + {0x50431032, 0xbe46f72b, 0, 1, 1}, + // x = 0x1.af61dap48, tan(x) = 0x1.60d1c6p-2 (RZ) + {0x57d7b0ed, 0x3eb068e3, 1, 0, 1}, + // x = 0x1.0088bcp52, tan(x) = 0x1.ca1edp0 (RZ) + {0x5980445e, 0x3fe50f68, 1, 0, 0}, + // x = 0x1.f90dfcp72, tan(x) = 0x1.597f9cp-1 (RZ) + {0x63fc86fe, 0x3f2cbfce, 1, 0, 0}, + // x = 0x1.a6ce12p86, tan(x) = -0x1.c5612ep-1 (RZ) + {0x6ad36709, 0xbf62b097, 0, 1, 0}, +}}; +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + +} // namespace tanf_internal + +LIBC_INLINE static float tanf(float x) { + using namespace tanf_internal; + using FPBits = typename fputil::FPBits<float>; + FPBits xbits(x); + uint32_t x_abs = xbits.uintval() & 0x7fff'ffffU; + + // |x| < pi/32 + if (LIBC_UNLIKELY(x_abs <= 0x3dc9'0fdbU)) { + double xd = static_cast<double>(x); + + // |x| < 0x1.0p-12f + if (LIBC_UNLIKELY(x_abs < 0x3980'0000U)) { + if (LIBC_UNLIKELY(x_abs == 0U)) { + // For signed zeros. + return x; + } + // When |x| < 2^-12, the relative error of the approximation tan(x) ~ x + // is: + // |tan(x) - x| / |tan(x)| < |x^3| / (3|x|) + // = x^2 / 3 + // < 2^-25 + // < epsilon(1)/2. + // So the correctly rounded values of tan(x) are: + // = x + sign(x)*eps(x) if rounding mode = FE_UPWARD and x is positive, + // or (rounding mode = FE_DOWNWARD and x is + // negative), + // = x otherwise. + // To simplify the rounding decision and make it more efficient, we use + // fma(x, 2^-25, x) instead. + // Note: to use the formula x + 2^-25*x to decide the correct rounding, we + // do need fma(x, 2^-25, x) to prevent underflow caused by 2^-25*x when + // |x| < 2^-125. For targets without FMA instructions, we simply use + // double for intermediate results as it is more efficient than using an + // emulated version of FMA. +#if defined(LIBC_TARGET_CPU_HAS_FMA_FLOAT) + return fputil::multiply_add(x, 0x1.0p-25f, x); +#else + return static_cast<float>(fputil::multiply_add(xd, 0x1.0p-25, xd)); +#endif // LIBC_TARGET_CPU_HAS_FMA_FLOAT + } + + // |x| < pi/32 + double xsq = xd * xd; + + // Degree-9 minimax odd polynomial of tan(x) generated by Sollya with: + // > P = fpminimax(tan(x)/x, [|0, 2, 4, 6, 8|], [|1, D...|], [0, pi/32]); + double result = + fputil::polyeval(xsq, 1.0, 0x1.555555553d022p-2, 0x1.111111ce442c1p-3, + 0x1.ba180a6bbdecdp-5, 0x1.69c0a88a0b71fp-6); + return static_cast<float>(xd * result); + } + +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + bool x_sign = xbits.uintval() >> 31; + // Check for exceptional values + if (LIBC_UNLIKELY(x_abs == 0x3f8a1f62U)) { + // |x| = 0x1.143ec4p0 + float sign = x_sign ? -1.0f : 1.0f; + + // volatile is used to prevent compiler (gcc) from optimizing the + // computation, making the results incorrect in different rounding modes. + volatile float tmp = 0x1.ddf9f4p0f; + tmp = fputil::multiply_add(sign, tmp, sign * 0x1.1p-24f); + + return tmp; + } +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + + // |x| > 0x1.ada6a8p+27f + if (LIBC_UNLIKELY(x_abs > 0x4d56'd354U)) { + // Inf or NaN + if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) { + if (xbits.is_signaling_nan()) { + fputil::raise_except_if_required(FE_INVALID); + return FPBits::quiet_nan().get_val(); + } + + if (x_abs == 0x7f80'0000U) { + fputil::set_errno_if_required(EDOM); + fputil::raise_except_if_required(FE_INVALID); + } + return x + FPBits::quiet_nan().get_val(); + } +#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS + // Other large exceptional values + if (auto r = TANF_EXCEPTS.lookup_odd(x_abs, x_sign); + LIBC_UNLIKELY(r.has_value())) + return r.value(); +#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS + } + + // For |x| >= pi/32, we use the definition of tan(x) function: + // tan(x) = sin(x) / cos(x) + // The we follow the same computations of sin(x) and cos(x) as sinf, cosf, + // and sincosf. + + double xd = static_cast<double>(x); + double sin_k, cos_k, sin_y, cosm1_y; + + sincosf_eval(xd, x_abs, sin_k, cos_k, sin_y, cosm1_y); + // tan(x) = sin(x) / cos(x) + // = (sin_y * cos_k + cos_y * sin_k) / (cos_y * cos_k - sin_y * sin_k) + using fputil::multiply_add; + return static_cast<float>( + multiply_add(sin_y, cos_k, multiply_add(cosm1_y, sin_k, sin_k)) / + multiply_add(sin_y, -sin_k, multiply_add(cosm1_y, cos_k, cos_k))); +} + +} // namespace math + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_MATH_TANF_H diff --git a/libc/src/__support/threads/fork_callbacks.cpp b/libc/src/__support/threads/fork_callbacks.cpp index b050b171..49fb41a 100644 --- a/libc/src/__support/threads/fork_callbacks.cpp +++ b/libc/src/__support/threads/fork_callbacks.cpp @@ -22,7 +22,6 @@ struct ForkCallbackTriple { ForkCallback *prepare = nullptr; ForkCallback *parent = nullptr; ForkCallback *child = nullptr; - constexpr ForkCallbackTriple() = default; }; class AtForkCallbackManager { diff --git a/libc/src/__support/wchar/CMakeLists.txt b/libc/src/__support/wchar/CMakeLists.txt index aed1d53..304b123 100644 --- a/libc/src/__support/wchar/CMakeLists.txt +++ b/libc/src/__support/wchar/CMakeLists.txt @@ -20,12 +20,10 @@ add_header_library( .character_converter ) -add_object_library( +add_header_library( character_converter HDRS character_converter.h - SRCS - character_converter.cpp DEPENDS libc.hdr.errno_macros libc.hdr.types.char8_t @@ -36,12 +34,10 @@ add_object_library( .mbstate ) -add_object_library( +add_header_library( wcrtomb HDRS wcrtomb.h - SRCS - wcrtomb.cpp DEPENDS libc.hdr.errno_macros libc.hdr.types.char32_t @@ -49,6 +45,7 @@ add_object_library( libc.hdr.types.wchar_t libc.src.__support.error_or libc.src.__support.common + libc.src.__support.macros.null_check .character_converter .mbstate ) diff --git a/libc/src/__support/wchar/character_converter.cpp b/libc/src/__support/wchar/character_converter.cpp deleted file mode 100644 index 2667288..0000000 --- a/libc/src/__support/wchar/character_converter.cpp +++ /dev/null @@ -1,176 +0,0 @@ -//===-- Implementation of a class for conversion --------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "hdr/errno_macros.h" -#include "hdr/types/char32_t.h" -#include "hdr/types/char8_t.h" -#include "hdr/types/size_t.h" -#include "src/__support/CPP/bit.h" -#include "src/__support/common.h" -#include "src/__support/error_or.h" -#include "src/__support/math_extras.h" -#include "src/__support/wchar/mbstate.h" - -#include "character_converter.h" - -namespace LIBC_NAMESPACE_DECL { -namespace internal { - -// This is for utf-8 bytes other than the first byte -constexpr size_t ENCODED_BITS_PER_UTF8 = 6; -// The number of bits per utf-8 byte that actually encode character -// Information not metadata (# of bits excluding the byte headers) -constexpr uint32_t MASK_ENCODED_BITS = - mask_trailing_ones<uint32_t, ENCODED_BITS_PER_UTF8>(); -// Maximum value for utf-32 for a utf-8 sequence of a given length -constexpr char32_t MAX_VALUE_PER_UTF8_LEN[] = {0x7f, 0x7ff, 0xffff, 0x10ffff}; -constexpr int MAX_UTF8_LENGTH = 4; - -CharacterConverter::CharacterConverter(mbstate *mbstate) { state = mbstate; } - -void CharacterConverter::clear() { - state->partial = 0; - state->bytes_stored = 0; - state->total_bytes = 0; -} - -bool CharacterConverter::isFull() { - return state->bytes_stored == state->total_bytes && state->total_bytes != 0; -} - -bool CharacterConverter::isEmpty() { return state->bytes_stored == 0; } - -bool CharacterConverter::isValidState() { - if (state->total_bytes > MAX_UTF8_LENGTH) - return false; - - const char32_t max_utf32_value = - state->total_bytes == 0 ? 0 - : MAX_VALUE_PER_UTF8_LEN[state->total_bytes - 1]; - return state->bytes_stored <= state->total_bytes && - state->partial <= max_utf32_value; -} - -int CharacterConverter::push(char8_t utf8_byte) { - uint8_t num_ones = static_cast<uint8_t>(cpp::countl_one(utf8_byte)); - // Checking the first byte if first push - if (isEmpty()) { - // UTF-8 char has 1 byte total - if (num_ones == 0) { - state->total_bytes = 1; - } - // UTF-8 char has 2 through 4 bytes total - else if (num_ones >= 2 && num_ones <= 4) { - /* Since the format is 110xxxxx, 1110xxxx, and 11110xxx for 2, 3, and 4, - we will make the base mask with 7 ones and right shift it as necessary. */ - constexpr size_t SIGNIFICANT_BITS = 7; - char8_t base_mask = - static_cast<char8_t>(mask_trailing_ones<uint8_t, SIGNIFICANT_BITS>()); - state->total_bytes = num_ones; - utf8_byte &= (base_mask >> num_ones); - } - // Invalid first byte - else { - // bytes_stored and total_bytes will always be 0 here - state->partial = static_cast<char32_t>(0); - return EILSEQ; - } - state->partial = static_cast<char32_t>(utf8_byte); - state->bytes_stored++; - return 0; - } - // Any subsequent push - // Adding 6 more bits so need to left shift - if (num_ones == 1 && !isFull()) { - char32_t byte = utf8_byte & MASK_ENCODED_BITS; - state->partial = state->partial << ENCODED_BITS_PER_UTF8; - state->partial |= byte; - state->bytes_stored++; - return 0; - } - - // Invalid byte -> reset the state - clear(); - return EILSEQ; -} - -int CharacterConverter::push(char32_t utf32) { - // we can't be partially through a conversion when pushing a utf32 value - if (!isEmpty()) - return -1; - - state->partial = utf32; - - // determine number of utf-8 bytes needed to represent this utf32 value - for (uint8_t i = 0; i < MAX_UTF8_LENGTH; i++) { - if (state->partial <= MAX_VALUE_PER_UTF8_LEN[i]) { - state->total_bytes = i + 1; - state->bytes_stored = i + 1; - return 0; - } - } - - // `utf32` contains a value that is too large to actually represent a valid - // unicode character - clear(); - return EILSEQ; -} - -ErrorOr<char32_t> CharacterConverter::pop_utf32() { - // If pop is called too early, do not reset the state, use error to determine - // whether enough bytes have been pushed - if (!isFull()) - return Error(-1); - char32_t utf32 = state->partial; - // reset if successful pop - clear(); - return utf32; -} - -ErrorOr<char8_t> CharacterConverter::pop_utf8() { - if (isEmpty()) - return Error(-1); - - constexpr char8_t FIRST_BYTE_HEADERS[] = {0, 0xC0, 0xE0, 0xF0}; - constexpr char8_t CONTINUING_BYTE_HEADER = 0x80; - - char32_t output; - - // Shift to get the next 6 bits from the utf32 encoding - const size_t shift_amount = (state->bytes_stored - 1) * ENCODED_BITS_PER_UTF8; - if (isFull()) { - /* - Choose the correct set of most significant bits to encode the length - of the utf8 sequence. The remaining bits contain the most significant - bits of the unicode value of the character. - */ - output = FIRST_BYTE_HEADERS[state->total_bytes - 1] | - (state->partial >> shift_amount); - } else { - // Get the next 6 bits and format it like so: 10xxxxxx - output = CONTINUING_BYTE_HEADER | - ((state->partial >> shift_amount) & MASK_ENCODED_BITS); - } - - state->bytes_stored--; - if (state->bytes_stored == 0) - clear(); - - return static_cast<char8_t>(output); -} - -template <> ErrorOr<char8_t> CharacterConverter::pop() { return pop_utf8(); } -template <> ErrorOr<char32_t> CharacterConverter::pop() { return pop_utf32(); } - -template <> size_t CharacterConverter::sizeAs<char8_t>() { - return state->total_bytes; -} -template <> size_t CharacterConverter::sizeAs<char32_t>() { return 1; } - -} // namespace internal -} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/__support/wchar/character_converter.h b/libc/src/__support/wchar/character_converter.h index 2cc28ab..e730016 100644 --- a/libc/src/__support/wchar/character_converter.h +++ b/libc/src/__support/wchar/character_converter.h @@ -9,12 +9,16 @@ #ifndef LLVM_LIBC_SRC___SUPPORT_CHARACTER_CONVERTER_H #define LLVM_LIBC_SRC___SUPPORT_CHARACTER_CONVERTER_H +#include "hdr/errno_macros.h" #include "hdr/types/char32_t.h" #include "hdr/types/char8_t.h" #include "hdr/types/size_t.h" + +#include "src/__support/CPP/bit.h" #include "src/__support/CPP/type_traits.h" #include "src/__support/common.h" #include "src/__support/error_or.h" +#include "src/__support/math_extras.h" #include "src/__support/wchar/mbstate.h" namespace LIBC_NAMESPACE_DECL { @@ -24,12 +28,31 @@ class CharacterConverter { private: mbstate *state; + // This is for utf-8 bytes other than the first byte + static constexpr size_t ENCODED_BITS_PER_UTF8 = 6; + + // The number of bits per utf-8 byte that actually encode character + // Information not metadata (# of bits excluding the byte headers) + static constexpr uint32_t MASK_ENCODED_BITS = + mask_trailing_ones<uint32_t, ENCODED_BITS_PER_UTF8>(); + + // Maximum value for utf-32 for a utf-8 sequence of a given length + static constexpr char32_t MAX_VALUE_PER_UTF8_LEN[] = {0x7f, 0x7ff, 0xffff, + 0x10ffff}; + static constexpr int MAX_UTF8_LENGTH = 4; + public: - CharacterConverter(mbstate *mbstate); + CharacterConverter(mbstate *mbstate) : state(mbstate) {} - void clear(); - bool isFull(); - bool isEmpty(); + void clear() { + state->partial = 0; + state->bytes_stored = 0; + state->total_bytes = 0; + } + bool isFull() { + return state->bytes_stored == state->total_bytes && state->total_bytes != 0; + } + bool isEmpty() { return state->bytes_stored == 0; } bool isValidState(); template <typename CharType> size_t sizeAs(); @@ -42,6 +65,141 @@ public: template <typename CharType> ErrorOr<CharType> pop(); }; +LIBC_INLINE bool CharacterConverter::isValidState() { + if (state->total_bytes > MAX_UTF8_LENGTH) + return false; + + const char32_t max_utf32_value = + state->total_bytes == 0 ? 0 + : MAX_VALUE_PER_UTF8_LEN[state->total_bytes - 1]; + return state->bytes_stored <= state->total_bytes && + state->partial <= max_utf32_value; +} + +LIBC_INLINE int CharacterConverter::push(char8_t utf8_byte) { + uint8_t num_ones = static_cast<uint8_t>(cpp::countl_one(utf8_byte)); + // Checking the first byte if first push + if (isEmpty()) { + // UTF-8 char has 1 byte total + if (num_ones == 0) { + state->total_bytes = 1; + } + // UTF-8 char has 2 through 4 bytes total + else if (num_ones >= 2 && num_ones <= 4) { + /* Since the format is 110xxxxx, 1110xxxx, and 11110xxx for 2, 3, and 4, + we will make the base mask with 7 ones and right shift it as necessary. */ + constexpr size_t SIGNIFICANT_BITS = 7; + char8_t base_mask = + static_cast<char8_t>(mask_trailing_ones<uint8_t, SIGNIFICANT_BITS>()); + state->total_bytes = num_ones; + utf8_byte &= (base_mask >> num_ones); + } + // Invalid first byte + else { + // bytes_stored and total_bytes will always be 0 here + state->partial = static_cast<char32_t>(0); + return EILSEQ; + } + state->partial = static_cast<char32_t>(utf8_byte); + state->bytes_stored++; + return 0; + } + // Any subsequent push + // Adding 6 more bits so need to left shift + if (num_ones == 1 && !isFull()) { + char32_t byte = utf8_byte & MASK_ENCODED_BITS; + state->partial = state->partial << ENCODED_BITS_PER_UTF8; + state->partial |= byte; + state->bytes_stored++; + return 0; + } + + // Invalid byte -> reset the state + clear(); + return EILSEQ; +} + +LIBC_INLINE int CharacterConverter::push(char32_t utf32) { + // we can't be partially through a conversion when pushing a utf32 value + if (!isEmpty()) + return -1; + + state->partial = utf32; + + // determine number of utf-8 bytes needed to represent this utf32 value + for (uint8_t i = 0; i < MAX_UTF8_LENGTH; i++) { + if (state->partial <= MAX_VALUE_PER_UTF8_LEN[i]) { + state->total_bytes = i + 1; + state->bytes_stored = i + 1; + return 0; + } + } + + // `utf32` contains a value that is too large to actually represent a valid + // unicode character + clear(); + return EILSEQ; +} + +LIBC_INLINE ErrorOr<char32_t> CharacterConverter::pop_utf32() { + // If pop is called too early, do not reset the state, use error to determine + // whether enough bytes have been pushed + if (!isFull()) + return Error(-1); + char32_t utf32 = state->partial; + // reset if successful pop + clear(); + return utf32; +} + +LIBC_INLINE ErrorOr<char8_t> CharacterConverter::pop_utf8() { + if (isEmpty()) + return Error(-1); + + constexpr char8_t FIRST_BYTE_HEADERS[] = {0, 0xC0, 0xE0, 0xF0}; + constexpr char8_t CONTINUING_BYTE_HEADER = 0x80; + + char32_t output; + + // Shift to get the next 6 bits from the utf32 encoding + const size_t shift_amount = (state->bytes_stored - 1) * ENCODED_BITS_PER_UTF8; + if (isFull()) { + /* + Choose the correct set of most significant bits to encode the length + of the utf8 sequence. The remaining bits contain the most significant + bits of the unicode value of the character. + */ + output = FIRST_BYTE_HEADERS[state->total_bytes - 1] | + (state->partial >> shift_amount); + } else { + // Get the next 6 bits and format it like so: 10xxxxxx + output = CONTINUING_BYTE_HEADER | + ((state->partial >> shift_amount) & MASK_ENCODED_BITS); + } + + state->bytes_stored--; + if (state->bytes_stored == 0) + clear(); + + return static_cast<char8_t>(output); +} + +template <> LIBC_INLINE ErrorOr<char8_t> CharacterConverter::pop() { + return pop_utf8(); +} + +template <> LIBC_INLINE ErrorOr<char32_t> CharacterConverter::pop() { + return pop_utf32(); +} + +template <> LIBC_INLINE size_t CharacterConverter::sizeAs<char8_t>() { + return state->total_bytes; +} + +template <> LIBC_INLINE size_t CharacterConverter::sizeAs<char32_t>() { + return 1; +} + } // namespace internal } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/__support/wchar/wcrtomb.cpp b/libc/src/__support/wchar/wcrtomb.cpp deleted file mode 100644 index fc54bbf..0000000 --- a/libc/src/__support/wchar/wcrtomb.cpp +++ /dev/null @@ -1,50 +0,0 @@ -//===-- Implementation of wcrtomb -----------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "src/__support/wchar/wcrtomb.h" -#include "src/__support/error_or.h" -#include "src/__support/wchar/character_converter.h" -#include "src/__support/wchar/mbstate.h" - -#include "hdr/errno_macros.h" -#include "hdr/types/char32_t.h" -#include "hdr/types/size_t.h" -#include "hdr/types/wchar_t.h" -#include "src/__support/common.h" -#include "src/__support/libc_assert.h" - -namespace LIBC_NAMESPACE_DECL { -namespace internal { - -ErrorOr<size_t> wcrtomb(char *__restrict s, wchar_t wc, - mbstate *__restrict ps) { - static_assert(sizeof(wchar_t) == 4); - - CharacterConverter cr(ps); - - if (!cr.isValidState()) - return Error(EINVAL); - - int status = cr.push(static_cast<char32_t>(wc)); - if (status != 0) - return Error(status); - - size_t count = 0; - while (!cr.isEmpty()) { - auto utf8 = cr.pop_utf8(); // can never fail as long as the push succeeded - LIBC_ASSERT(utf8.has_value()); - - *s = utf8.value(); - s++; - count++; - } - return count; -} - -} // namespace internal -} // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/__support/wchar/wcrtomb.h b/libc/src/__support/wchar/wcrtomb.h index bcd39a9..98cf852 100644 --- a/libc/src/__support/wchar/wcrtomb.h +++ b/libc/src/__support/wchar/wcrtomb.h @@ -9,16 +9,47 @@ #ifndef LLVM_LIBC_SRC__SUPPORT_WCHAR_WCRTOMB_H #define LLVM_LIBC_SRC__SUPPORT_WCHAR_WCRTOMB_H -#include "hdr/types/size_t.h" -#include "hdr/types/wchar_t.h" #include "src/__support/error_or.h" -#include "src/__support/macros/config.h" +#include "src/__support/macros/null_check.h" +#include "src/__support/wchar/character_converter.h" #include "src/__support/wchar/mbstate.h" +#include "hdr/errno_macros.h" +#include "hdr/types/char32_t.h" +#include "hdr/types/size_t.h" +#include "hdr/types/wchar_t.h" +#include "src/__support/common.h" +#include "src/__support/libc_assert.h" + namespace LIBC_NAMESPACE_DECL { namespace internal { -ErrorOr<size_t> wcrtomb(char *__restrict s, wchar_t wc, mbstate *__restrict ps); +LIBC_INLINE ErrorOr<size_t> wcrtomb(char *__restrict s, wchar_t wc, + mbstate *__restrict ps) { + LIBC_CRASH_ON_NULLPTR(s); + LIBC_CRASH_ON_NULLPTR(ps); + static_assert(sizeof(wchar_t) == 4); + + CharacterConverter cr(ps); + + if (!cr.isValidState()) + return Error(EINVAL); + + int status = cr.push(static_cast<char32_t>(wc)); + if (status != 0) + return Error(status); + + size_t count = 0; + while (!cr.isEmpty()) { + auto utf8 = cr.pop_utf8(); // can never fail as long as the push succeeded + LIBC_ASSERT(utf8.has_value()); + + *s = utf8.value(); + s++; + count++; + } + return count; +} } // namespace internal } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/__support/weak_avl.h b/libc/src/__support/weak_avl.h new file mode 100644 index 0000000..31c7e31 --- /dev/null +++ b/libc/src/__support/weak_avl.h @@ -0,0 +1,595 @@ +//===-- Implementation header for weak AVL tree -----------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC___SUPPORT_WEAK_AVL_H +#define LLVM_LIBC_SRC___SUPPORT_WEAK_AVL_H + +#include "hdr/stdint_proxy.h" +#include "src/__support/CPP/bit.h" +#include "src/__support/CPP/new.h" +#include "src/__support/CPP/optional.h" +#include "src/__support/CPP/utility/move.h" +#include "src/__support/alloc-checker.h" +#include "src/__support/libc_assert.h" +#include "src/__support/macros/attributes.h" +#include "src/__support/macros/config.h" + +namespace LIBC_NAMESPACE_DECL { + +// A general self-balancing binary search tree where the node pointer can +// be used as stable handles to the stored values. +// +// The self-balancing strategy is the Weak AVL (WAVL) tree, based on the +// following foundational references: +// 1. https://maskray.me/blog/2025-12-14-weak-avl-tree +// 2. https://reviews.freebsd.org/D25480 +// 3. https://ics.uci.edu/~goodrich/teach/cs165/notes/WeakAVLTrees.pdf +// 4. https://dl.acm.org/doi/10.1145/2689412 (Rank-Balanced Trees) +// +// WAVL trees belong to the rank-balanced binary search tree framework +// (reference 4), alongside AVL and Red-Black trees. +// +// Key Properties of WAVL Trees: +// 1. Relationship to Red-Black Trees: A WAVL tree can always be colored as a +// Red-Black tree. +// 2. Relationship to AVL Trees: An AVL tree meets all the requirements of a +// WAVL tree. Insertion-only WAVL trees maintain the same structure as AVL +// trees. +// +// Rank-Based Balancing: +// In rank-balanced trees, each node is assigned a rank (conceptually similar +// to height). The rank difference between a parent and its child is +// strictly enforced to be either **1** or **2**. +// +// - **AVL Trees:** Rank is equivalent to height. The strict condition is that +// there are no 2-2 nodes (a parent with rank difference 2 to both children). +// - **WAVL Trees:** The no 2-2 node rule is relaxed for internal nodes during +// the deletion fixup process, making WAVL trees less strictly balanced than +// AVL trees but easier to maintain than Red-Black trees. +// +// Balancing Mechanics (Promotion/Demotion): +// - **Null nodes** are considered to have rank -1. +// - **External/leaf nodes** have rank 0. +// - **Insertion:** Inserting a node may create a situation where a parent and +// child have the same rank (difference 0). This is fixed by **promoting** +// the rank of the parent and propagating the fix upwards using at most two +// rotations (trinode fixup). +// - **Deletion:** Deleting a node may result in a parent being 3 ranks higher +// than a child (difference 3). This is fixed by **demoting** the parent's +// rank and propagating the fix upwards. +// +// Implementation Detail: +// The rank is **implicitly** maintained. We never store the full rank. Instead, +// a 2-bit tag is used on each node to record the rank difference to each child: +// - Bit cleared (0) -> Rank difference is **1**. +// - Bit set (1) -> Rank difference is **2**. +template <typename T> class WeakAVLNode { + // Data + T data; + + // Parent pointer + WeakAVLNode *parent; + + // Children pointers + WeakAVLNode *children[2]; + + // Flags + unsigned char left_rank_diff_2 : 1; + unsigned char right_rank_diff_2 : 1; + + LIBC_INLINE bool is_leaf() { + return (children[0] == nullptr) && (children[1] == nullptr); + } + + LIBC_INLINE void toggle_rank_diff_2(bool is_right) { + if (is_right) + right_rank_diff_2 ^= 1; + else + left_rank_diff_2 ^= 1; + } + + LIBC_INLINE bool both_flags_set() const { + return left_rank_diff_2 && right_rank_diff_2; + } + + LIBC_INLINE bool any_flag_set() const { + return left_rank_diff_2 || right_rank_diff_2; + } + + LIBC_INLINE void clear_flags() { + left_rank_diff_2 = 0; + right_rank_diff_2 = 0; + } + + LIBC_INLINE void set_both_flags() { + left_rank_diff_2 = 1; + right_rank_diff_2 = 1; + } + + LIBC_INLINE WeakAVLNode(T data) + : data(cpp::move(data)), parent(nullptr), children{nullptr, nullptr}, + left_rank_diff_2(0), right_rank_diff_2(0) {} + + LIBC_INLINE static WeakAVLNode *create(T value) { + AllocChecker ac; + WeakAVLNode *res = new (ac) WeakAVLNode(value); + if (ac) + return res; + return nullptr; + } + + // Unlink a node from tree. The corresponding flag is not updated. The node is + // not deleted and its pointers are not cleared. + // FixupSite is the lowest surviving node from which rank/flag invariants may + // be violated. + // Our tree requires value to stay in their node to maintain stable addresses. + // This complicates the unlink operation as the successor transplanting needs + // to update all the pointers and flags. + struct FixupSite { + WeakAVLNode *parent; + bool is_right; + }; + LIBC_INLINE static FixupSite unlink(WeakAVLNode *&root, WeakAVLNode *node) { + bool has_left = node->children[0] != nullptr; + bool has_right = node->children[1] != nullptr; + + // Case 0: no children + if (!has_left && !has_right) { + if (!node->parent) { + root = nullptr; + return {nullptr, false}; + } + FixupSite site = {node->parent, node->parent->children[1] == node}; + site.parent->children[site.is_right] = nullptr; + return site; + } + + // Case 1: one child + if (has_left != has_right) { + WeakAVLNode *child = node->children[has_right]; + if (!node->parent) { + root = child; + child->parent = nullptr; + return {nullptr, false}; + } + FixupSite site = {node->parent, node->parent->children[1] == node}; + site.parent->children[site.is_right] = child; + child->parent = site.parent; + return site; + } + + // Case 2: two children: replace by successor (leftmost in right subtree) + WeakAVLNode *succ = node->children[1]; + while (succ->children[0]) + succ = succ->children[0]; + + WeakAVLNode *succ_parent = succ->parent; + // succ and node may be adjacent to each other, so we + // still need to check the exact direction of the successor. + bool succ_was_right = succ_parent->children[1] == succ; + WeakAVLNode *succ_rchild = succ->children[1]; + + // 1) Splice successor out of its old position (flags intentionally + // unchanged) + FixupSite site = {succ_parent, succ_was_right}; + succ_parent->children[succ_was_right] = succ_rchild; + if (succ_rchild) + succ_rchild->parent = succ_parent; + + // 2) Transplant successor into node's position + succ->parent = node->parent; + succ->left_rank_diff_2 = node->left_rank_diff_2; + succ->right_rank_diff_2 = node->right_rank_diff_2; + + succ->children[0] = node->children[0]; + succ->children[1] = node->children[1]; + if (succ->children[0]) + succ->children[0]->parent = succ; + if (succ->children[1]) + succ->children[1]->parent = succ; + + if (succ->parent) { + bool node_was_right = succ->parent->children[1] == node; + succ->parent->children[node_was_right] = succ; + } else { + root = succ; + } + + // 3) If the physical removal was under `node`, fixup parent must be the + // successor (since `node` is deleted and successor now occupies that + // spot). + if (site.parent == node) + site.parent = succ; + + return site; + } + +public: + using OptionalNodePtr = cpp::optional<WeakAVLNode *>; + + LIBC_INLINE const WeakAVLNode *get_left() const { return children[0]; } + LIBC_INLINE const WeakAVLNode *get_right() const { return children[1]; } + LIBC_INLINE const T &get_data() const { return data; } + LIBC_INLINE bool has_rank_diff_2(bool is_right) const { + return is_right ? right_rank_diff_2 : left_rank_diff_2; + } + + // Destroy the subtree rooted at node + LIBC_INLINE static void destroy(WeakAVLNode *node) { + if (!node) + return; + destroy(node->children[0]); + destroy(node->children[1]); + delete node; + } + // Rotate the subtree rooted at node in the given direction. + // + // Illustration for is_right = true (Left Rotation): + // + // (Node) (Pivot) + // / \ / \ + // A (Pivot) => (Node) C + // / \ / \ + // B C A B + // + LIBC_INLINE static WeakAVLNode *rotate(WeakAVLNode *&root, WeakAVLNode *node, + bool is_right) { + WeakAVLNode *pivot = node->children[is_right]; + // Handover pivot's child + WeakAVLNode *grandchild = pivot->children[!is_right]; + node->children[is_right] = grandchild; + if (grandchild) + grandchild->parent = node; + pivot->parent = node->parent; + // Pivot becomes the new root of the subtree + if (!node->parent) { + root = pivot; + } else { + bool node_is_right = node->parent->children[1] == node; + node->parent->children[node_is_right] = pivot; + } + pivot->children[!is_right] = node; + node->parent = pivot; + return pivot; + } + + // Find data in the subtree rooted at root. If not found, returns + // OptionalNode. `Compare` returns integer values for ternary comparison. + // Unlike other interfaces, `find` does not modify the tree; hence we pass + // the `root` by value. + // It is assumed that the order returned by the comparator is consistent + // on each call. + template <typename Compare> + LIBC_INLINE static OptionalNodePtr find(WeakAVLNode *root, T data, + Compare comp) { + WeakAVLNode *cursor = root; + while (cursor != nullptr) { + int comp_result = comp(cursor->data, data); + if (comp_result == 0) + return cursor; // Node found + bool is_right = comp_result < 0; + cursor = cursor->children[is_right]; + } + return cpp::nullopt; + } + // Insert data into the subtree rooted at root. + // Returns the node if insertion is successful or the node exists in + // the tree. + // Returns cpp::nullopt if memory allocation fails. + // `Compare` returns integer values for ternary comparison. + // It is assumed that the order returned by the comparator is consistent + // on each call. + template <typename Compare> + LIBC_INLINE static OptionalNodePtr find_or_insert(WeakAVLNode *&root, T data, + Compare comp) { + WeakAVLNode *parent = nullptr, *cursor = root; + bool is_right = false; + while (cursor != nullptr) { + parent = cursor; + int comp_result = comp(parent->data, data); + if (comp_result == 0) + return parent; // Node already exists + is_right = comp_result < 0; + cursor = cursor->children[is_right]; + } + WeakAVLNode *allocated = create(cpp::move(data)); + if (!allocated) + return cpp::nullopt; + WeakAVLNode *node = allocated; + node->parent = parent; + + // Case 0: inserting into an empty tree + if (!parent) { + root = node; // Tree was empty + return node; + } + + parent->children[is_right] = node; + // Rebalance process + // Case 1: both node and its sibling have rank-difference 1. So after the + // insertion, the node is at the same level as the parent. Promoting parent + // will fix the conflict of the trinodes but we may need to continue on + // parent. + // + // (GP) (GP) + // | Promote | x - 1 + // | x -----> (P) + // 0 | / 1 / \ + // (N) --- (P) ---- (N) \ 2 + // \ 1 \ + // (S) (S) + while (parent && !parent->any_flag_set()) { + parent->toggle_rank_diff_2(!is_right); + node = parent; + parent = node->parent; + if (parent) + is_right = (parent->children[1] == node); + } + // We finish if node has reaches the root -- otherwise, we end up with + // two more cases. + if (!parent) + return allocated; + + // Case 2: parent does not need to be promoted as node is lower + // than the parent by 2 ranks. + // (P) (P) + // / \ / \ + // 2 1 => 1 1 + // / \ / \ + // (N) (*) (N) (*) + if (parent->has_rank_diff_2(is_right)) { + parent->toggle_rank_diff_2(is_right); + return allocated; + } + + // At this point, we know there is a violation but one-step fix is possible. + LIBC_ASSERT(!node->both_flags_set() && + "there should be no 2-2 node along the insertion fixup path"); + + LIBC_ASSERT((node == allocated || node->any_flag_set()) && + "Internal node must have a child with rank-difference 2, " + "otherwise it should have already been handled."); + + // Case 3: node's sibling has rank-difference 2. And node has a 1-node + // along the same direction. We can do a single rotation to fix the + // trinode. + // (GP) (GP) + // 0 | X Rotate | + // (N) ----- (P) => (N) + // 1 / \ 2 \ 2 1 / \ 1 + // (C1) \ \ (C1) (P) + // (C2) (S) 1 / \ 1 + // (C2) (S) + if (node->has_rank_diff_2(!is_right)) { + WeakAVLNode *new_subroot = rotate(root, parent, is_right); + new_subroot->clear_flags(); + parent->clear_flags(); + return allocated; + } + // Case 4: node's sibling has rank-difference 2. And node has a 1-node + // along the opposite direction. We need a double rotation to fix the + // trinode. + // (GP) (GP) + // 0 | X Zig-Zag | X + // (N) ----- (P) => (C1) + // 2 / \ 1 \ 2 1 / \ 1 + // / (C1) \ (N) (P) + // (C2) L / \ R (S) 1 / \ L R / \ 1 + // (A) (B) (C2) (A)(B) (S) + // (mirrored) + // (GP) (GP) + // X | 0 Zig-Zag | X + // (P) ----- (N) => (C1) + // 2 / 1 / \ 2 1 / \ 1 + // / (C1) \ (P) (N) + // (S) L / \ R (C2) 1 / \ L R / \ 1 + // (A) (B) (S)(A) (B)(C2) + + WeakAVLNode *subroot1 = rotate(root, node, !is_right); // First rotation + [[maybe_unused]] WeakAVLNode *subroot2 = + rotate(root, parent, is_right); // Second rotation + LIBC_ASSERT(subroot1 == subroot2 && + "Subroots after double rotation should be the same"); + bool subroot_left_diff_2 = subroot1->left_rank_diff_2; + bool subroot_right_diff_2 = subroot1->right_rank_diff_2; + node->clear_flags(); + parent->clear_flags(); + subroot1->clear_flags(); + // Select destinations + WeakAVLNode *dst_left = is_right ? parent : node; + WeakAVLNode *dst_right = is_right ? node : parent; + // Masked toggles + if (subroot_left_diff_2) + dst_left->toggle_rank_diff_2(true); + + if (subroot_right_diff_2) + dst_right->toggle_rank_diff_2(false); + return allocated; + } + + // Erase the node from the tree rooted at root. + LIBC_INLINE static void erase(WeakAVLNode *&root, WeakAVLNode *node) { + // Unlink the node from the tree + auto [cursor, is_right] = unlink(root, node); + delete node; + WeakAVLNode *sibling = nullptr; + while (cursor) { + // Case 0. cursor previously had rank-difference 1 on the side of the + // deleted node. We can simply update the rank-difference and stop. + // Notice that this step may create 2-2 nodes, thus deviate from "strong" + // AVL tree. + // + // (C) (C) + // X / \ 1 => X / \ + // (*) (D) (*) \ 2 + // (D) + if (!cursor->has_rank_diff_2(is_right)) { + cursor->toggle_rank_diff_2(is_right); + // If we created a 2-2 leaf, we must demote it and continue. + // Otherwise, we are done as the internal node becomes a 2-2 node and + // there is no further violation upwards. + if (!cursor->both_flags_set() || !cursor->is_leaf()) + return; + // Clear flags for demotion. + cursor->clear_flags(); + } + + // Case 1. cursor previously had rank-difference 2 on the side of the + // deleted node. Now it has rank-difference 3, which violates the + // weak-AVL property. We found that we have a sibling with rank-difference + // 2, so we can demote cursor and continue upwards. + // + // (P) (P) + // | X | (X + 1) + // (C) | + // / \ => (C) + // 2 / \ 1 / \ + // (*) \ 3 (*) \ 2 + // (D) (D) + else if (cursor->has_rank_diff_2(!is_right)) + cursor->toggle_rank_diff_2(!is_right); + + // Case 2. continue from Case 1; but the sibling has rank-difference 1. + // However, we found that the sibling is a 2-2 node. We demote both + // sibling and cursor, and continue upwards. We break for other cases if + // sibling cannot be demoted. + // + // (P) (P) + // | X | (X + 1) + // (C) | + // 1 / \ => (C) + // (S) \ 1 / \ + // / \ \ 3 (S) \ 2 + // 2 / \ 2 (D) 1 / \ 1 (D) + // (*) (*) (*) (*) + else { + sibling = cursor->children[!is_right]; + LIBC_ASSERT(sibling && "rank-difference 1 sibling cannot be empty"); + if (sibling->both_flags_set()) + sibling->clear_flags(); + else + break; + } + + // Update cursor to move upwards + if (cursor->parent) + is_right = (cursor->parent->children[1] == cursor); + cursor = cursor->parent; + } + + // Either cursor is nullptr (we reached the root), or sibling has + // rank-difference 1. + if (!cursor) + return; + LIBC_ASSERT(sibling && "rank-difference 1 sibling must exist"); + bool sibling_is_right = !is_right; // Rename for clarity + + // Case 3. continue from Case 2; but the sibling cannot be demoted. + // Sibling has a node T along the same direction with rank-difference 1. + // + // (P) (P) + // | X | X + // (C) (S) + // 1 / \ Rotate 2 / \ 1 + // (S) \ => / (C) + // 1 / \ Y \ 3 (T) Y / \ 2 + // (T) \ (D) (*) \ + // (*) (D) + if (!sibling->has_rank_diff_2(sibling_is_right)) { + WeakAVLNode *new_subroot = rotate(root, cursor, sibling_is_right); + LIBC_ASSERT(new_subroot == sibling && + "sibling should become the subtree root"); + // Update flags + bool sibling_alter_child_has_rank_diff_2 = + new_subroot->has_rank_diff_2(!sibling_is_right); + new_subroot->clear_flags(); + new_subroot->toggle_rank_diff_2(sibling_is_right); + + // Cursor only needs to be updated if it becomes a 2-2 node + if (sibling_alter_child_has_rank_diff_2) { + // Demote a 2-2 cursor if it is a leaf + bool cursor_is_leaf = cursor->is_leaf(); + if (cursor_is_leaf) + cursor->clear_flags(); + + // If cursor is now a leaf, then its parent (which should be the pivot) + // becomes a 2-2 node after cursor's demotion. Otherwise, cursor itself + // should become a 2-2 node. + WeakAVLNode *candidate = cursor_is_leaf ? new_subroot : cursor; + candidate->toggle_rank_diff_2(sibling_is_right ^ cursor_is_leaf); + LIBC_ASSERT(candidate->both_flags_set() && + "target node should become a 2-2 node."); + } + } + // Case 4. continue from Case 3; but rank-difference 1 child T of sibling + // is on the opposite direction. + // + // (P) (P) + // | X | X + // (C) Zig-Zag (T) + // 1 / \ => / \ + // (S) \ 2 / \ 2 + // / \ 1 \ 3 (S) (C) + // 2 / (T) (D) 1 / Y \ / Z \ 1 + // (*) Y / \ Z (*) (A)(B) (D) + // (A) (B) + else { + WeakAVLNode *target_child = rotate(root, sibling, !sibling_is_right); + bool subtree_left_diff_2 = target_child->left_rank_diff_2; + bool subtree_right_diff_2 = target_child->right_rank_diff_2; + [[maybe_unused]] WeakAVLNode *new_subroot = + rotate(root, cursor, sibling_is_right); + LIBC_ASSERT(new_subroot == target_child && + "target_child should become the subtree root"); + // Set flags + target_child->set_both_flags(); + cursor->clear_flags(); + sibling->clear_flags(); + // Select destinations + WeakAVLNode *dst_left = sibling_is_right ? cursor : sibling; + WeakAVLNode *dst_right = sibling_is_right ? sibling : cursor; + // Masked toggles + if (subtree_left_diff_2) + dst_left->toggle_rank_diff_2(true); + if (subtree_right_diff_2) + dst_right->toggle_rank_diff_2(false); + } + } + + enum struct WalkType { + PreOrder, + InOrder, + PostOrder, + Leaf, + }; + template <typename Func> + LIBC_INLINE static void walk(WeakAVLNode *node, Func func) { + if (!node) + return; + + if (node->is_leaf()) { + func(node, WalkType::Leaf); + return; + } + + func(node, WalkType::PreOrder); + + if (node->children[0]) + walk(node->children[0], func); + + func(node, WalkType::InOrder); + + if (node->children[1]) + walk(node->children[1], func); + func(node, WalkType::PostOrder); + } +}; + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC___SUPPORT_WEAK_AVL_H diff --git a/libc/src/math/generic/CMakeLists.txt b/libc/src/math/generic/CMakeLists.txt index 6de4cf3..21c3a86 100644 --- a/libc/src/math/generic/CMakeLists.txt +++ b/libc/src/math/generic/CMakeLists.txt @@ -249,8 +249,7 @@ add_entrypoint_object( HDRS ../dfmaf128.h DEPENDS - libc.src.__support.FPUtil.fma - libc.src.__support.macros.properties.types + libc.src.__support.math.dfmaf128 ) add_entrypoint_object( @@ -260,7 +259,7 @@ add_entrypoint_object( HDRS ../dfmal.h DEPENDS - libc.src.__support.FPUtil.fma + libc.src.__support.math.dfmal ) add_entrypoint_object( @@ -373,16 +372,8 @@ add_entrypoint_object( HDRS ../sinf.h DEPENDS - libc.src.__support.math.range_reduction - libc.src.__support.math.sincosf_utils + libc.src.__support.math.sinf libc.src.errno.errno - libc.src.__support.FPUtil.basic_operations - libc.src.__support.FPUtil.fenv_impl - libc.src.__support.FPUtil.fp_bits - libc.src.__support.FPUtil.fma - libc.src.__support.FPUtil.polyeval - libc.src.__support.FPUtil.rounding_mode - libc.src.__support.macros.optimization ) add_entrypoint_object( @@ -392,16 +383,7 @@ add_entrypoint_object( HDRS ../sinf16.h DEPENDS - libc.hdr.errno_macros - libc.hdr.fenv_macros - libc.src.__support.FPUtil.cast - libc.src.__support.FPUtil.fenv_impl - libc.src.__support.FPUtil.fp_bits - libc.src.__support.FPUtil.except_value_utils - libc.src.__support.FPUtil.multiply_add - libc.src.__support.macros.optimization - libc.src.__support.macros.properties.types - libc.src.__support.math.sincosf16_utils + libc.src.__support.math.sinf16 COMPILE_OPTIONS ${libc_opt_high_flag} ) @@ -433,14 +415,7 @@ add_entrypoint_object( HDRS ../sinpif.h DEPENDS - libc.src.__support.math.sincosf_utils - libc.src.__support.FPUtil.fenv_impl - libc.src.__support.FPUtil.fp_bits - libc.src.__support.FPUtil.fma - libc.src.__support.FPUtil.multiply_add - libc.src.__support.FPUtil.polyeval - libc.src.__support.common - libc.src.__support.macros.optimization + libc.src.__support.math.sinpif ) add_entrypoint_object( @@ -486,16 +461,8 @@ add_entrypoint_object( HDRS ../tan.h DEPENDS - libc.src.__support.math.range_reduction_double - libc.hdr.errno_macros + libc.src.__support.math.tan libc.src.errno.errno - libc.src.__support.FPUtil.double_double - libc.src.__support.FPUtil.dyadic_float - libc.src.__support.FPUtil.except_value_utils - libc.src.__support.FPUtil.fenv_impl - libc.src.__support.FPUtil.fp_bits - libc.src.__support.FPUtil.multiply_add - libc.src.__support.macros.optimization ) add_entrypoint_object( @@ -505,17 +472,8 @@ add_entrypoint_object( HDRS ../tanf.h DEPENDS - libc.src.__support.math.range_reduction - libc.src.__support.math.sincosf_utils + libc.src.__support.math.tanf libc.src.errno.errno - libc.src.__support.FPUtil.fenv_impl - libc.src.__support.FPUtil.fenv_impl - libc.src.__support.FPUtil.except_value_utils - libc.src.__support.FPUtil.nearest_integer - libc.src.__support.FPUtil.fma - libc.src.__support.FPUtil.multiply_add - libc.src.__support.FPUtil.polyeval - libc.src.__support.macros.optimization ) add_entrypoint_object( @@ -1762,7 +1720,7 @@ add_entrypoint_object( HDRS ../ilogb.h DEPENDS - libc.src.__support.FPUtil.manipulation_functions + libc.src.__support.math.ilogb ) add_entrypoint_object( @@ -1772,7 +1730,7 @@ add_entrypoint_object( HDRS ../ilogbf.h DEPENDS - libc.src.__support.FPUtil.manipulation_functions + libc.src.__support.math.ilogbf ) add_entrypoint_object( @@ -1782,7 +1740,8 @@ add_entrypoint_object( HDRS ../ilogbl.h DEPENDS - libc.src.__support.FPUtil.manipulation_functions + libc.src.__support.math.ilogbl + libc.src.errno.errno ) add_entrypoint_object( @@ -1802,8 +1761,7 @@ add_entrypoint_object( HDRS ../ilogbf128.h DEPENDS - libc.src.__support.macros.properties.types - libc.src.__support.FPUtil.manipulation_functions + libc.src.__support.math.ilogbf128 ) add_entrypoint_object( @@ -1827,7 +1785,7 @@ add_entrypoint_object( HDRS ../llogb.h DEPENDS - libc.src.__support.FPUtil.manipulation_functions + libc.src.__support.math.llogb ) add_entrypoint_object( @@ -1837,7 +1795,8 @@ add_entrypoint_object( HDRS ../llogbf.h DEPENDS - libc.src.__support.FPUtil.manipulation_functions + libc.src.__support.math.llogbf + libc.src.errno.errno ) add_entrypoint_object( @@ -1857,8 +1816,7 @@ add_entrypoint_object( HDRS ../llogbf16.h DEPENDS - libc.src.__support.macros.properties.types - libc.src.__support.FPUtil.manipulation_functions + libc.src.__support.math.llogbf16 ) add_entrypoint_object( @@ -1868,8 +1826,7 @@ add_entrypoint_object( HDRS ../llogbf128.h DEPENDS - libc.src.__support.macros.properties.types - libc.src.__support.FPUtil.manipulation_functions + libc.src.__support.math.llogbf128 ) add_entrypoint_object( @@ -1957,16 +1914,7 @@ add_entrypoint_object( HDRS ../log10.h DEPENDS - libc.src.__support.FPUtil.double_double - libc.src.__support.FPUtil.dyadic_float - libc.src.__support.FPUtil.fenv_impl - libc.src.__support.FPUtil.fp_bits - libc.src.__support.FPUtil.multiply_add - libc.src.__support.FPUtil.polyeval - libc.src.__support.integer_literals - libc.src.__support.macros.optimization - libc.src.__support.math.common_constants - libc.src.__support.math.log_range_reduction + libc.src.__support.math.log10 ) add_entrypoint_object( @@ -2011,15 +1959,7 @@ add_entrypoint_object( HDRS ../log1p.h DEPENDS - libc.src.__support.FPUtil.double_double - libc.src.__support.FPUtil.dyadic_float - libc.src.__support.FPUtil.fenv_impl - libc.src.__support.FPUtil.fp_bits - libc.src.__support.FPUtil.multiply_add - libc.src.__support.FPUtil.polyeval - libc.src.__support.integer_literals - libc.src.__support.macros.optimization - libc.src.__support.math.common_constants + libc.src.__support.math.log1p ) add_entrypoint_object( @@ -2045,16 +1985,7 @@ add_entrypoint_object( HDRS ../log2.h DEPENDS - libc.src.__support.FPUtil.double_double - libc.src.__support.FPUtil.dyadic_float - libc.src.__support.FPUtil.fenv_impl - libc.src.__support.FPUtil.fp_bits - libc.src.__support.FPUtil.multiply_add - libc.src.__support.FPUtil.polyeval - libc.src.__support.integer_literals - libc.src.__support.macros.optimization - libc.src.__support.math.common_constants - libc.src.__support.math.log_range_reduction + libc.src.__support.math.log2 ) add_entrypoint_object( @@ -2110,14 +2041,7 @@ add_entrypoint_object( HDRS ../logf.h DEPENDS - libc.src.__support.FPUtil.except_value_utils - libc.src.__support.FPUtil.fenv_impl - libc.src.__support.FPUtil.fp_bits - libc.src.__support.FPUtil.multiply_add - libc.src.__support.FPUtil.polyeval - libc.src.__support.macros.optimization - libc.src.__support.macros.properties.cpu_features - libc.src.__support.math.common_constants + libc.src.__support.math.logf ) add_entrypoint_object( @@ -2127,17 +2051,7 @@ add_entrypoint_object( HDRS ../logf16.h DEPENDS - libc.hdr.errno_macros - libc.hdr.fenv_macros - libc.src.__support.FPUtil.cast - libc.src.__support.FPUtil.except_value_utils - libc.src.__support.FPUtil.fenv_impl - libc.src.__support.FPUtil.fp_bits - libc.src.__support.FPUtil.multiply_add - libc.src.__support.FPUtil.polyeval - libc.src.__support.macros.optimization - libc.src.__support.macros.properties.cpu_features - libc.src.__support.math.expxf16_utils + libc.src.__support.math.logf16 ) add_entrypoint_object( @@ -2173,7 +2087,8 @@ add_entrypoint_object( HDRS ../logbf.h DEPENDS - libc.src.__support.FPUtil.manipulation_functions + libc.src.__support.math.logbf + libc.src.errno.errno ) add_entrypoint_object( @@ -2193,8 +2108,8 @@ add_entrypoint_object( HDRS ../logbf16.h DEPENDS - libc.src.__support.macros.properties.types - libc.src.__support.FPUtil.manipulation_functions + libc.src.__support.math.logbf16 + libc.src.errno.errno ) add_entrypoint_object( @@ -2204,8 +2119,8 @@ add_entrypoint_object( HDRS ../logbf128.h DEPENDS - libc.src.__support.macros.properties.types - libc.src.__support.FPUtil.manipulation_functions + libc.src.__support.math.logbf128 + libc.src.errno.errno ) add_entrypoint_object( @@ -3067,7 +2982,7 @@ add_entrypoint_object( HDRS ../sqrt.h DEPENDS - libc.src.__support.FPUtil.sqrt + libc.src.__support.math.sqrt ) @@ -3098,7 +3013,7 @@ add_entrypoint_object( HDRS ../sqrtf16.h DEPENDS - libc.src.__support.FPUtil.sqrt + libc.src.__support.math.sqrtf16 ) add_entrypoint_object( @@ -3269,12 +3184,8 @@ add_entrypoint_object( HDRS ../hypotf.h DEPENDS - libc.src.__support.FPUtil.double_double - libc.src.__support.FPUtil.fenv_impl - libc.src.__support.FPUtil.fp_bits - libc.src.__support.FPUtil.multiply_add - libc.src.__support.FPUtil.sqrt - libc.src.__support.macros.optimization + libc.src.__support.math.hypotf + libc.src.errno.errno ) add_entrypoint_object( @@ -4194,10 +4105,7 @@ add_entrypoint_object( HDRS ../sinhf.h DEPENDS - libc.src.__support.FPUtil.fp_bits - libc.src.__support.FPUtil.rounding_mode - libc.src.__support.macros.optimization - libc.src.__support.math.sinhfcoshf_utils + libc.src.__support.math.sinhf ) add_entrypoint_object( @@ -4207,14 +4115,7 @@ add_entrypoint_object( HDRS ../sinhf16.h DEPENDS - libc.hdr.errno_macros - libc.hdr.fenv_macros - libc.src.__support.FPUtil.except_value_utils - libc.src.__support.FPUtil.fenv_impl - libc.src.__support.FPUtil.fp_bits - libc.src.__support.FPUtil.rounding_mode - libc.src.__support.macros.optimization - libc.src.__support.math.expxf16_utils + libc.src.__support.math.sinhf16 ) add_entrypoint_object( @@ -5136,8 +5037,7 @@ add_entrypoint_object( HDRS ../f16fma.h DEPENDS - libc.src.__support.macros.properties.types - libc.src.__support.FPUtil.fma + libc.src.__support.math.f16fma ) add_entrypoint_object( @@ -5158,8 +5058,7 @@ add_entrypoint_object( HDRS ../f16fmal.h DEPENDS - libc.src.__support.macros.properties.types - libc.src.__support.FPUtil.fma + libc.src.__support.math.f16fmal ) add_entrypoint_object( @@ -5202,8 +5101,8 @@ add_entrypoint_object( HDRS ../f16sqrtl.h DEPENDS - libc.src.__support.macros.properties.types - libc.src.__support.FPUtil.sqrt + libc.src.__support.math.f16sqrtl + libc.src.errno.errno ) add_entrypoint_object( @@ -5224,7 +5123,7 @@ add_entrypoint_object( HDRS ../fsqrt.h DEPENDS - libc.src.__support.FPUtil.generic.sqrt + libc.src.__support.math.fsqrt ) add_entrypoint_object( @@ -5234,7 +5133,7 @@ add_entrypoint_object( HDRS ../fsqrtl.h DEPENDS - libc.src.__support.FPUtil.generic.sqrt + libc.src.__support.math.fsqrtl ) add_entrypoint_object( @@ -5244,8 +5143,8 @@ add_entrypoint_object( HDRS ../fsqrtf128.h DEPENDS - libc.src.__support.macros.properties.types - libc.src.__support.FPUtil.generic.sqrt + libc.src.__support.math.fsqrtf128 + libc.src.errno.errno ) add_entrypoint_object( diff --git a/libc/src/math/generic/asin.cpp b/libc/src/math/generic/asin.cpp index b5ba9ea..865c44d 100644 --- a/libc/src/math/generic/asin.cpp +++ b/libc/src/math/generic/asin.cpp @@ -11,266 +11,6 @@ namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(double, asin, (double x)) { - using namespace asin_internal; - using FPBits = fputil::FPBits<double>; - - FPBits xbits(x); - int x_exp = xbits.get_biased_exponent(); - - // |x| < 0.5. - if (x_exp < FPBits::EXP_BIAS - 1) { - // |x| < 2^-26. - if (LIBC_UNLIKELY(x_exp < FPBits::EXP_BIAS - 26)) { - // When |x| < 2^-26, the relative error of the approximation asin(x) ~ x - // is: - // |asin(x) - x| / |asin(x)| < |x^3| / (6|x|) - // = x^2 / 6 - // < 2^-54 - // < epsilon(1)/2. - // So the correctly rounded values of asin(x) are: - // = x + sign(x)*eps(x) if rounding mode = FE_TOWARDZERO, - // or (rounding mode = FE_UPWARD and x is - // negative), - // = x otherwise. - // To simplify the rounding decision and make it more efficient, we use - // fma(x, 2^-54, x) instead. - // Note: to use the formula x + 2^-54*x to decide the correct rounding, we - // do need fma(x, 2^-54, x) to prevent underflow caused by 2^-54*x when - // |x| < 2^-1022. For targets without FMA instructions, when x is close to - // denormal range, we normalize x, -#if defined(LIBC_MATH_HAS_SKIP_ACCURATE_PASS) - return x; -#elif defined(LIBC_TARGET_CPU_HAS_FMA_DOUBLE) - return fputil::multiply_add(x, 0x1.0p-54, x); -#else - if (xbits.abs().uintval() == 0) - return x; - // Get sign(x) * min_normal. - FPBits eps_bits = FPBits::min_normal(); - eps_bits.set_sign(xbits.sign()); - double eps = eps_bits.get_val(); - double normalize_const = (x_exp == 0) ? eps : 0.0; - double scaled_normal = - fputil::multiply_add(x + normalize_const, 0x1.0p54, eps); - return fputil::multiply_add(scaled_normal, 0x1.0p-54, -normalize_const); -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS - } - -#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - return x * asin_eval(x * x); -#else - unsigned idx; - DoubleDouble x_sq = fputil::exact_mult(x, x); - double err = xbits.abs().get_val() * 0x1.0p-51; - // Polynomial approximation: - // p ~ asin(x)/x - - DoubleDouble p = asin_eval(x_sq, idx, err); - // asin(x) ~ x * (ASIN_COEFFS[idx][0] + p) - DoubleDouble r0 = fputil::exact_mult(x, p.hi); - double r_lo = fputil::multiply_add(x, p.lo, r0.lo); - - // Ziv's accuracy test. - - double r_upper = r0.hi + (r_lo + err); - double r_lower = r0.hi + (r_lo - err); - - if (LIBC_LIKELY(r_upper == r_lower)) - return r_upper; - - // Ziv's accuracy test failed, perform 128-bit calculation. - - // Recalculate mod 1/64. - idx = static_cast<unsigned>(fputil::nearest_integer(x_sq.hi * 0x1.0p6)); - - // Get x^2 - idx/64 exactly. When FMA is available, double-double - // multiplication will be correct for all rounding modes. Otherwise we use - // Float128 directly. - Float128 x_f128(x); - -#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE - // u = x^2 - idx/64 - Float128 u_hi( - fputil::multiply_add(static_cast<double>(idx), -0x1.0p-6, x_sq.hi)); - Float128 u = fputil::quick_add(u_hi, Float128(x_sq.lo)); -#else - Float128 x_sq_f128 = fputil::quick_mul(x_f128, x_f128); - Float128 u = fputil::quick_add( - x_sq_f128, Float128(static_cast<double>(idx) * (-0x1.0p-6))); -#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE - - Float128 p_f128 = asin_eval(u, idx); - Float128 r = fputil::quick_mul(x_f128, p_f128); - - return static_cast<double>(r); -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS - } - // |x| >= 0.5 - - double x_abs = xbits.abs().get_val(); - - // Maintaining the sign: - constexpr double SIGN[2] = {1.0, -1.0}; - double x_sign = SIGN[xbits.is_neg()]; - - // |x| >= 1 - if (LIBC_UNLIKELY(x_exp >= FPBits::EXP_BIAS)) { - // x = +-1, asin(x) = +- pi/2 - if (x_abs == 1.0) { - // return +- pi/2 - return fputil::multiply_add(x_sign, PI_OVER_TWO.hi, - x_sign * PI_OVER_TWO.lo); - } - // |x| > 1, return NaN. - if (xbits.is_quiet_nan()) - return x; - - // Set domain error for non-NaN input. - if (!xbits.is_nan()) - fputil::set_errno_if_required(EDOM); - - fputil::raise_except_if_required(FE_INVALID); - return FPBits::quiet_nan().get_val(); - } - - // When |x| >= 0.5, we perform range reduction as follow: - // - // Assume further that 0.5 <= x < 1, and let: - // y = asin(x) - // We will use the double angle formula: - // cos(2y) = 1 - 2 sin^2(y) - // and the complement angle identity: - // x = sin(y) = cos(pi/2 - y) - // = 1 - 2 sin^2 (pi/4 - y/2) - // So: - // sin(pi/4 - y/2) = sqrt( (1 - x)/2 ) - // And hence: - // pi/4 - y/2 = asin( sqrt( (1 - x)/2 ) ) - // Equivalently: - // asin(x) = y = pi/2 - 2 * asin( sqrt( (1 - x)/2 ) ) - // Let u = (1 - x)/2, then: - // asin(x) = pi/2 - 2 * asin( sqrt(u) ) - // Moreover, since 0.5 <= x < 1: - // 0 < u <= 1/4, and 0 < sqrt(u) <= 0.5, - // And hence we can reuse the same polynomial approximation of asin(x) when - // |x| <= 0.5: - // asin(x) ~ pi/2 - 2 * sqrt(u) * P(u), - - // u = (1 - |x|)/2 - double u = fputil::multiply_add(x_abs, -0.5, 0.5); - // v_hi + v_lo ~ sqrt(u). - // Let: - // h = u - v_hi^2 = (sqrt(u) - v_hi) * (sqrt(u) + v_hi) - // Then: - // sqrt(u) = v_hi + h / (sqrt(u) + v_hi) - // ~ v_hi + h / (2 * v_hi) - // So we can use: - // v_lo = h / (2 * v_hi). - // Then, - // asin(x) ~ pi/2 - 2*(v_hi + v_lo) * P(u) - double v_hi = fputil::sqrt<double>(u); - -#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - double p = asin_eval(u); - double r = x_sign * fputil::multiply_add(-2.0 * v_hi, p, PI_OVER_TWO.hi); - return r; -#else - -#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE - double h = fputil::multiply_add(v_hi, -v_hi, u); -#else - DoubleDouble v_hi_sq = fputil::exact_mult(v_hi, v_hi); - double h = (u - v_hi_sq.hi) - v_hi_sq.lo; -#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE - - // Scale v_lo and v_hi by 2 from the formula: - // vh = v_hi * 2 - // vl = 2*v_lo = h / v_hi. - double vh = v_hi * 2.0; - double vl = h / v_hi; - - // Polynomial approximation: - // p ~ asin(sqrt(u))/sqrt(u) - unsigned idx; - double err = vh * 0x1.0p-51; - - DoubleDouble p = asin_eval(DoubleDouble{0.0, u}, idx, err); - - // Perform computations in double-double arithmetic: - // asin(x) = pi/2 - (v_hi + v_lo) * (ASIN_COEFFS[idx][0] + p) - DoubleDouble r0 = fputil::quick_mult(DoubleDouble{vl, vh}, p); - DoubleDouble r = fputil::exact_add(PI_OVER_TWO.hi, -r0.hi); - - double r_lo = PI_OVER_TWO.lo - r0.lo + r.lo; - - // Ziv's accuracy test. - -#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE - double r_upper = fputil::multiply_add( - r.hi, x_sign, fputil::multiply_add(r_lo, x_sign, err)); - double r_lower = fputil::multiply_add( - r.hi, x_sign, fputil::multiply_add(r_lo, x_sign, -err)); -#else - r_lo *= x_sign; - r.hi *= x_sign; - double r_upper = r.hi + (r_lo + err); - double r_lower = r.hi + (r_lo - err); -#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE - - if (LIBC_LIKELY(r_upper == r_lower)) - return r_upper; - - // Ziv's accuracy test failed, we redo the computations in Float128. - // Recalculate mod 1/64. - idx = static_cast<unsigned>(fputil::nearest_integer(u * 0x1.0p6)); - - // After the first step of Newton-Raphson approximating v = sqrt(u), we have - // that: - // sqrt(u) = v_hi + h / (sqrt(u) + v_hi) - // v_lo = h / (2 * v_hi) - // With error: - // sqrt(u) - (v_hi + v_lo) = h * ( 1/(sqrt(u) + v_hi) - 1/(2*v_hi) ) - // = -h^2 / (2*v * (sqrt(u) + v)^2). - // Since: - // (sqrt(u) + v_hi)^2 ~ (2sqrt(u))^2 = 4u, - // we can add another correction term to (v_hi + v_lo) that is: - // v_ll = -h^2 / (2*v_hi * 4u) - // = -v_lo * (h / 4u) - // = -vl * (h / 8u), - // making the errors: - // sqrt(u) - (v_hi + v_lo + v_ll) = O(h^3) - // well beyond 128-bit precision needed. - - // Get the rounding error of vl = 2 * v_lo ~ h / vh - // Get full product of vh * vl -#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE - double vl_lo = fputil::multiply_add(-v_hi, vl, h) / v_hi; -#else - DoubleDouble vh_vl = fputil::exact_mult(v_hi, vl); - double vl_lo = ((h - vh_vl.hi) - vh_vl.lo) / v_hi; -#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE - // vll = 2*v_ll = -vl * (h / (4u)). - double t = h * (-0.25) / u; - double vll = fputil::multiply_add(vl, t, vl_lo); - // m_v = -(v_hi + v_lo + v_ll). - Float128 m_v = fputil::quick_add( - Float128(vh), fputil::quick_add(Float128(vl), Float128(vll))); - m_v.sign = Sign::NEG; - - // Perform computations in Float128: - // asin(x) = pi/2 - (v_hi + v_lo + vll) * P(u). - Float128 y_f128(fputil::multiply_add(static_cast<double>(idx), -0x1.0p-6, u)); - - Float128 p_f128 = asin_eval(y_f128, idx); - Float128 r0_f128 = fputil::quick_mul(m_v, p_f128); - Float128 r_f128 = fputil::quick_add(PI_OVER_TWO_F128, r0_f128); - - if (xbits.is_neg()) - r_f128.sign = Sign::NEG; - - return static_cast<double>(r_f128); -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS -} +LLVM_LIBC_FUNCTION(double, asin, (double x)) { return math::asin(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/dfmaf128.cpp b/libc/src/math/generic/dfmaf128.cpp index b6e1bdb08..b8069c6 100644 --- a/libc/src/math/generic/dfmaf128.cpp +++ b/libc/src/math/generic/dfmaf128.cpp @@ -6,20 +6,13 @@ // //===----------------------------------------------------------------------===// -#ifndef LLVM_LIBC_SRC_MATH_DFMAf128_H -#define LLVM_LIBC_SRC_MATH_DFMAf128_H - #include "src/math/dfmaf128.h" -#include "src/__support/FPUtil/FMA.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" +#include "src/__support/math/dfmaf128.h" namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(double, dfmaf128, (float128 x, float128 y, float128 z)) { - return fputil::fma<double>(x, y, z); + return math::dfmaf128(x, y, z); } } // namespace LIBC_NAMESPACE_DECL - -#endif // LLVM_LIBC_SRC_MATH_DFMAf128_H diff --git a/libc/src/math/generic/dfmal.cpp b/libc/src/math/generic/dfmal.cpp index 02e0ce8..a50d837 100644 --- a/libc/src/math/generic/dfmal.cpp +++ b/libc/src/math/generic/dfmal.cpp @@ -7,15 +7,13 @@ //===----------------------------------------------------------------------===// #include "src/math/dfmal.h" -#include "src/__support/FPUtil/FMA.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" +#include "src/__support/math/dfmal.h" namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(double, dfmal, (long double x, long double y, long double z)) { - return fputil::fma<double>(x, y, z); + return math::dfmal(x, y, z); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/f16fma.cpp b/libc/src/math/generic/f16fma.cpp index 70314b5..e6673e7 100644 --- a/libc/src/math/generic/f16fma.cpp +++ b/libc/src/math/generic/f16fma.cpp @@ -7,14 +7,12 @@ //===----------------------------------------------------------------------===// #include "src/math/f16fma.h" -#include "src/__support/FPUtil/FMA.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" +#include "src/__support/math/f16fma.h" namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(float16, f16fma, (double x, double y, double z)) { - return fputil::fma<float16>(x, y, z); + return math::f16fma(x, y, z); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/f16fmal.cpp b/libc/src/math/generic/f16fmal.cpp index 4f2bf92..afc2339 100644 --- a/libc/src/math/generic/f16fmal.cpp +++ b/libc/src/math/generic/f16fmal.cpp @@ -7,15 +7,13 @@ //===----------------------------------------------------------------------===// #include "src/math/f16fmal.h" -#include "src/__support/FPUtil/FMA.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" +#include "src/__support/math/f16fmal.h" namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(float16, f16fmal, (long double x, long double y, long double z)) { - return fputil::fma<float16>(x, y, z); + return math::f16fmal(x, y, z); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/f16sqrtl.cpp b/libc/src/math/generic/f16sqrtl.cpp index c6ce73d..2c81ca2 100644 --- a/libc/src/math/generic/f16sqrtl.cpp +++ b/libc/src/math/generic/f16sqrtl.cpp @@ -7,14 +7,12 @@ //===----------------------------------------------------------------------===// #include "src/math/f16sqrtl.h" -#include "src/__support/FPUtil/sqrt.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" +#include "src/__support/math/f16sqrtl.h" namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(float16, f16sqrtl, (long double x)) { - return fputil::sqrt<float16>(x); + return math::f16sqrtl(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/fsqrt.cpp b/libc/src/math/generic/fsqrt.cpp index d54471f..df1d4a9a 100644 --- a/libc/src/math/generic/fsqrt.cpp +++ b/libc/src/math/generic/fsqrt.cpp @@ -7,12 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/math/fsqrt.h" -#include "src/__support/FPUtil/generic/sqrt.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" +#include "src/__support/math/fsqrt.h" namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(float, fsqrt, (double x)) { return fputil::sqrt<float>(x); } +LLVM_LIBC_FUNCTION(float, fsqrt, (double x)) { return math::fsqrt(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/fsqrtf128.cpp b/libc/src/math/generic/fsqrtf128.cpp index f2c0495..1b2ba2f 100644 --- a/libc/src/math/generic/fsqrtf128.cpp +++ b/libc/src/math/generic/fsqrtf128.cpp @@ -7,14 +7,11 @@ //===----------------------------------------------------------------------===// #include "src/math/fsqrtf128.h" -#include "src/__support/FPUtil/generic/sqrt.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" - +#include "src/__support/math/fsqrtf128.h" namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(float, fsqrtf128, (float128 x)) { - return fputil::sqrt<float>(x); + return math::fsqrtf128(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/fsqrtl.cpp b/libc/src/math/generic/fsqrtl.cpp index b896a84..d6f27b16 100644 --- a/libc/src/math/generic/fsqrtl.cpp +++ b/libc/src/math/generic/fsqrtl.cpp @@ -7,14 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/math/fsqrtl.h" -#include "src/__support/FPUtil/generic/sqrt.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" +#include "src/__support/math/fsqrtl.h" namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(float, fsqrtl, (long double x)) { - return fputil::sqrt<float>(x); -} +LLVM_LIBC_FUNCTION(float, fsqrtl, (long double x)) { return math::fsqrtl(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/hypotf.cpp b/libc/src/math/generic/hypotf.cpp index ec48f62..fa1697c 100644 --- a/libc/src/math/generic/hypotf.cpp +++ b/libc/src/math/generic/hypotf.cpp @@ -6,93 +6,12 @@ // //===----------------------------------------------------------------------===// #include "src/math/hypotf.h" -#include "src/__support/FPUtil/FEnvImpl.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/double_double.h" -#include "src/__support/FPUtil/multiply_add.h" -#include "src/__support/FPUtil/sqrt.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" -#include "src/__support/macros/optimization.h" +#include "src/__support/math/hypotf.h" namespace LIBC_NAMESPACE_DECL { LLVM_LIBC_FUNCTION(float, hypotf, (float x, float y)) { - using DoubleBits = fputil::FPBits<double>; - using FPBits = fputil::FPBits<float>; - - FPBits x_abs = FPBits(x).abs(); - FPBits y_abs = FPBits(y).abs(); - - bool x_abs_larger = x_abs.uintval() >= y_abs.uintval(); - - FPBits a_bits = x_abs_larger ? x_abs : y_abs; - FPBits b_bits = x_abs_larger ? y_abs : x_abs; - - uint32_t a_u = a_bits.uintval(); - uint32_t b_u = b_bits.uintval(); - - // Note: replacing `a_u >= FPBits::EXP_MASK` with `a_bits.is_inf_or_nan()` - // generates extra exponent bit masking instructions on x86-64. - if (LIBC_UNLIKELY(a_u >= FPBits::EXP_MASK)) { - // x or y is inf or nan - if (a_bits.is_signaling_nan() || b_bits.is_signaling_nan()) { - fputil::raise_except_if_required(FE_INVALID); - return FPBits::quiet_nan().get_val(); - } - if (a_bits.is_inf() || b_bits.is_inf()) - return FPBits::inf().get_val(); - return a_bits.get_val(); - } - - if (LIBC_UNLIKELY(a_u - b_u >= - static_cast<uint32_t>((FPBits::FRACTION_LEN + 2) - << FPBits::FRACTION_LEN))) - return x_abs.get_val() + y_abs.get_val(); - - double ad = static_cast<double>(a_bits.get_val()); - double bd = static_cast<double>(b_bits.get_val()); - - // These squares are exact. - double a_sq = ad * ad; -#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE - double sum_sq = fputil::multiply_add(bd, bd, a_sq); -#else - double b_sq = bd * bd; - double sum_sq = a_sq + b_sq; -#endif - - // Take sqrt in double precision. - DoubleBits result(fputil::sqrt<double>(sum_sq)); - uint64_t r_u = result.uintval(); - - // If any of the sticky bits of the result are non-zero, except the LSB, then - // the rounded result is correct. - if (LIBC_UNLIKELY(((r_u + 1) & 0x0000'0000'0FFF'FFFE) == 0)) { - double r_d = result.get_val(); - - // Perform rounding correction. -#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE - double sum_sq_lo = fputil::multiply_add(bd, bd, a_sq - sum_sq); - double err = sum_sq_lo - fputil::multiply_add(r_d, r_d, -sum_sq); -#else - fputil::DoubleDouble r_sq = fputil::exact_mult(r_d, r_d); - double sum_sq_lo = b_sq - (sum_sq - a_sq); - double err = (sum_sq - r_sq.hi) + (sum_sq_lo - r_sq.lo); -#endif - - if (err > 0) { - r_u |= 1; - } else if ((err < 0) && (r_u & 1) == 0) { - r_u -= 1; - } else if ((r_u & 0x0000'0000'1FFF'FFFF) == 0) { - // The rounded result is exact. - fputil::clear_except_if_required(FE_INEXACT); - } - return static_cast<float>(DoubleBits(r_u).get_val()); - } - - return static_cast<float>(result.get_val()); + return math::hypotf(x, y); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/ilogb.cpp b/libc/src/math/generic/ilogb.cpp index 60f2af2..74e6166 100644 --- a/libc/src/math/generic/ilogb.cpp +++ b/libc/src/math/generic/ilogb.cpp @@ -7,12 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/math/ilogb.h" -#include "src/__support/FPUtil/ManipulationFunctions.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" +#include "src/__support/math/ilogb.h" namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(int, ilogb, (double x)) { return fputil::intlogb<int>(x); } +LLVM_LIBC_FUNCTION(int, ilogb, (double x)) { return math::ilogb(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/ilogbf.cpp b/libc/src/math/generic/ilogbf.cpp index 7da2aff..0ed2cb5 100644 --- a/libc/src/math/generic/ilogbf.cpp +++ b/libc/src/math/generic/ilogbf.cpp @@ -7,12 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/math/ilogbf.h" -#include "src/__support/FPUtil/ManipulationFunctions.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" +#include "src/__support/math/ilogbf.h" namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(int, ilogbf, (float x)) { return fputil::intlogb<int>(x); } +LLVM_LIBC_FUNCTION(int, ilogbf, (float x)) { return math::ilogbf(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/ilogbf128.cpp b/libc/src/math/generic/ilogbf128.cpp index 4abc670..2cb6032 100644 --- a/libc/src/math/generic/ilogbf128.cpp +++ b/libc/src/math/generic/ilogbf128.cpp @@ -7,14 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/math/ilogbf128.h" -#include "src/__support/FPUtil/ManipulationFunctions.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" +#include "src/__support/math/ilogbf128.h" namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(int, ilogbf128, (float128 x)) { - return fputil::intlogb<int>(x); -} +LLVM_LIBC_FUNCTION(int, ilogbf128, (float128 x)) { return math::ilogbf128(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/ilogbl.cpp b/libc/src/math/generic/ilogbl.cpp index 12460a8..b496b53 100644 --- a/libc/src/math/generic/ilogbl.cpp +++ b/libc/src/math/generic/ilogbl.cpp @@ -7,14 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/math/ilogbl.h" -#include "src/__support/FPUtil/ManipulationFunctions.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" +#include "src/__support/math/ilogbl.h" namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(int, ilogbl, (long double x)) { - return fputil::intlogb<int>(x); -} +LLVM_LIBC_FUNCTION(int, ilogbl, (long double x)) { return math::ilogbl(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/llogb.cpp b/libc/src/math/generic/llogb.cpp index 3850ac0..2dcffb7 100644 --- a/libc/src/math/generic/llogb.cpp +++ b/libc/src/math/generic/llogb.cpp @@ -7,12 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/math/llogb.h" -#include "src/__support/FPUtil/ManipulationFunctions.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" +#include "src/__support/math/llogb.h" namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(long, llogb, (double x)) { return fputil::intlogb<long>(x); } +LLVM_LIBC_FUNCTION(long, llogb, (double x)) { return math::llogb(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/llogbf.cpp b/libc/src/math/generic/llogbf.cpp index fedad95..2b35e2c 100644 --- a/libc/src/math/generic/llogbf.cpp +++ b/libc/src/math/generic/llogbf.cpp @@ -7,12 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/math/llogbf.h" -#include "src/__support/FPUtil/ManipulationFunctions.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" +#include "src/__support/math/llogbf.h" namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(long, llogbf, (float x)) { return fputil::intlogb<long>(x); } +LLVM_LIBC_FUNCTION(long, llogbf, (float x)) { return math::llogbf(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/llogbf128.cpp b/libc/src/math/generic/llogbf128.cpp index 9106731..6f8f9c4 100644 --- a/libc/src/math/generic/llogbf128.cpp +++ b/libc/src/math/generic/llogbf128.cpp @@ -7,14 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/math/llogbf128.h" -#include "src/__support/FPUtil/ManipulationFunctions.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" +#include "src/__support/math/llogbf128.h" namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(long, llogbf128, (float128 x)) { - return fputil::intlogb<long>(x); -} +LLVM_LIBC_FUNCTION(long, llogbf128, (float128 x)) { return math::llogbf128(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/llogbf16.cpp b/libc/src/math/generic/llogbf16.cpp index c792e90..916a5b9 100644 --- a/libc/src/math/generic/llogbf16.cpp +++ b/libc/src/math/generic/llogbf16.cpp @@ -7,14 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/math/llogbf16.h" -#include "src/__support/FPUtil/ManipulationFunctions.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" +#include "src/__support/math/llogbf16.h" namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(long, llogbf16, (float16 x)) { - return fputil::intlogb<long>(x); -} +LLVM_LIBC_FUNCTION(long, llogbf16, (float16 x)) { return math::llogbf16(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/log10.cpp b/libc/src/math/generic/log10.cpp index 60c057d..54a4b5b5 100644 --- a/libc/src/math/generic/log10.cpp +++ b/libc/src/math/generic/log10.cpp @@ -7,906 +7,9 @@ //===----------------------------------------------------------------------===// #include "src/math/log10.h" -#include "src/__support/FPUtil/FEnvImpl.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/PolyEval.h" -#include "src/__support/FPUtil/double_double.h" -#include "src/__support/FPUtil/dyadic_float.h" -#include "src/__support/FPUtil/multiply_add.h" -#include "src/__support/common.h" -#include "src/__support/integer_literals.h" -#include "src/__support/macros/config.h" -#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY - -#include "src/__support/math/common_constants.h" -#include "src/__support/math/log_range_reduction.h" +#include "src/__support/math/log10.h" namespace LIBC_NAMESPACE_DECL { - -// 128-bit precision dyadic floating point numbers. -using Float128 = typename fputil::DyadicFloat<128>; - -using LIBC_NAMESPACE::operator""_u128; - -namespace { - -using namespace common_constants_internal; -using namespace math::log_range_reduction_internal; - -constexpr fputil::DoubleDouble LOG10_E = {0x1.95355baaafad3p-57, - 0x1.bcb7b1526e50ep-2}; - -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS -// A simple upper bound for the error of e_x * log(2) - log(r). -constexpr double HI_ERR = 0x1.0p-85; - -// Extra errors from P is from using x^2 to reduce evaluation latency. -constexpr double P_ERR = 0x1.0p-51; - -// log10(2) with 128-bit precision generated by SageMath with: -// def format_hex(value): -// l = hex(value)[2:] -// n = 8 -// x = [l[i:i + n] for i in range(0, len(l), n)] -// return "0x" + "'".join(x) + "_u128" -// (s, m, e) = RealField(128)(2).log10().sign_exponent_mantissa(); -// print(format_hex(m)); -constexpr Float128 LOG10_2(Sign::POS, /*exponent=*/-129, /*mantissa=*/ - 0x9a209a84'fbcff798'8f8959ac'0b7c9178_u128); - -alignas(16) constexpr LogRR LOG10_TABLE = { - // -log10(r) with 128-bit precision generated by SageMath with: - // - // for i in range(128): - // r = 2^-8 * ceil( 2^8 * (1 - 2^(-8)) / (1 + i*2^(-7)) ); - // s, m, e = RealField(128)(r).log10().sign_mantissa_exponent(); - // print("{Sign::POS,", e, ", format_hex(m), "},"); - /* .step_1 = */ { - {Sign::POS, 0, 0_u128}, - {Sign::POS, -136, 0xdf3b5ebb'da7e186b'65af394f'e05eafd3_u128}, - {Sign::POS, -135, 0xe01d4057'2f029c16'a8fb8d87'b30163b5_u128}, - {Sign::POS, -134, 0xa8c1263a'c3f57eb3'6bb0170e'5bb5d630_u128}, - {Sign::POS, -134, 0xe1e841bb'c26204e5'fc2ea6eb'0ea1370e_u128}, - {Sign::POS, -133, 0x8dc2eb02'274d6ff4'dc8a199a'4bb63382_u128}, - {Sign::POS, -133, 0xaacde920'361dd054'86b57ea6'10c7db33_u128}, - {Sign::POS, -133, 0xc81618eb'15421bab'5f034a40'e6a2f09d_u128}, - {Sign::POS, -133, 0xe59c7e66'c5fedb4b'594a31b2'c5cc891c_u128}, - {Sign::POS, -133, 0xf477584f'97b654de'221efda5'8221904b_u128}, - {Sign::POS, -132, 0x892e8219'75106e09'68a0dc47'567691c9_u128}, - {Sign::POS, -132, 0x9841c66e'17dfe7da'10bc94f4'4d216b49_u128}, - {Sign::POS, -132, 0x9fd7be33'18306cc5'e303ea7e'23c9d6fb_u128}, - {Sign::POS, -132, 0xaf1cb35b'f494a8dd'ce697dba'a00d4c7d_u128}, - {Sign::POS, -132, 0xbe8380a2'fa7eba5a'9c216079'dcf0ea96_u128}, - {Sign::POS, -132, 0xc643c775'8283a271'75278940'eecfc3a9_u128}, - {Sign::POS, -132, 0xd5de75ec'27e4fe68'2d3467d2'53e2d1fc_u128}, - {Sign::POS, -132, 0xddb904e8'f1272a95'ead4055d'cdec7b22_u128}, - {Sign::POS, -132, 0xed88f6bb'355fa196'e1e0dda0'b3d375a4_u128}, - {Sign::POS, -132, 0xf57e8281'ade9d92d'38dc40c4'fe11e608_u128}, - {Sign::POS, -131, 0x82c2941b'b20bbe1f'3bcdcfe7'b23976cd_u128}, - {Sign::POS, -131, 0x86cb3663'2807cdcd'456350b0'bda452a6_u128}, - {Sign::POS, -131, 0x8eeaa306'458b760a'78185dcc'37fda01a_u128}, - {Sign::POS, -131, 0x93018395'12fc1168'307643ad'bbbde1b3_u128}, - {Sign::POS, -131, 0x9b3dd1d5'50c41443'6c449d40'9f883fe3_u128}, - {Sign::POS, -131, 0x9f6356aa'03c34389'8ea7b30c'8b4ad886_u128}, - {Sign::POS, -131, 0xa7bd56cd'de5d76a2'961c6e69'0d8879b4_u128}, - {Sign::POS, -131, 0xabf1ea3e'1d7bd7cf'042643ce'd81ec14a_u128}, - {Sign::POS, -131, 0xb02b9af7'4c2f879e'4742fb3d'0b5cdd19_u128}, - {Sign::POS, -131, 0xb8ae8671'b3d7dd6c'f7e2ab36'f09e9014_u128}, - {Sign::POS, -131, 0xbcf7dabd'87c01afc'8d3fc634'85e7ff13_u128}, - {Sign::POS, -131, 0xc1467f69'4d10a581'f3edc493'75fbc5a5_u128}, - {Sign::POS, -131, 0xc9f3ef07'e1f3fc5e'5fcd7d0c'e937375f_u128}, - {Sign::POS, -131, 0xce52d50b'94fa253a'58252dad'a9f06111_u128}, - {Sign::POS, -131, 0xd2b74192'fae43777'62f01e5f'f43708ab_u128}, - {Sign::POS, -131, 0xd72142a8'4ca85abd'481d9b31'31f52639_u128}, - {Sign::POS, -131, 0xdb90e68b'8abf14af'b305ced1'419fe924_u128}, - {Sign::POS, -131, 0xe48150cf'32888b9c'849266a8'5513dc6d_u128}, - {Sign::POS, -131, 0xe90234c6'5a15e533'080ecf32'66b4dcf4_u128}, - {Sign::POS, -131, 0xed88f6bb'355fa196'e1e0dda0'b3d375a4_u128}, - {Sign::POS, -131, 0xf215a60b'6557943f'ce3537a3'a211b25b_u128}, - {Sign::POS, -131, 0xf6a85251'3757dfbd'5dab6830'7fedefcd_u128}, - {Sign::POS, -131, 0xffdfe15d'e3c01bac'1be2585c'279c50a5_u128}, - {Sign::POS, -130, 0x8242724a'155219f3'18aa3021'71017dcb_u128}, - {Sign::POS, -130, 0x849812d0'ccbb5cbd'abc7e698'502d43c0_u128}, - {Sign::POS, -130, 0x86f0dab1'ab5822b6'c339089a'51663370_u128}, - {Sign::POS, -130, 0x894cd27d'9f182c63'26f70b34'ce5cf201_u128}, - {Sign::POS, -130, 0x8bac02e8'ac3e09ac'676f20a8'7ab433df_u128}, - {Sign::POS, -130, 0x8e0e74ca'ae062e24'6db4169c'c4b83bc3_u128}, - {Sign::POS, -130, 0x90743120'1c7f651a'cd3fdb2f'ad0d1fd6_u128}, - {Sign::POS, -130, 0x92dd410a'd7bfe103'49d03e16'3250d1d4_u128}, - {Sign::POS, -130, 0x9549add2'f8a3c7e0'9ec7dc02'd5e723b9_u128}, - {Sign::POS, -130, 0x97b980e7'a743d71c'34698d03'a5442573_u128}, - {Sign::POS, -130, 0x9a2cc3df'f7548556'0522904d'1e47f3de_u128}, - {Sign::POS, -130, 0x9ca3807b'ca9fe93f'791a7264'6c87b976_u128}, - {Sign::POS, -130, 0x9f1dc0a4'b9cea286'3826f190'd655d736_u128}, - {Sign::POS, -130, 0xa19b8e6f'03b60e45'544ab3e4'8199b299_u128}, - {Sign::POS, -130, 0xa41cf41a'83643487'be775fa8'2961114e_u128}, - {Sign::POS, -130, 0xa6a1fc13'ad241953'45798e50'19e6c082_u128}, - {Sign::POS, -130, 0xa92ab0f4'92b772bd'91fb1ed0'cdc4d1fb_u128}, - {Sign::POS, -130, 0xabb71d85'ef05380d'818b8b9c'bbd17b72_u128}, - {Sign::POS, -130, 0xae474cc0'397f0d4f'a50c2fea'60c5b3b2_u128}, - {Sign::POS, -130, 0xb0db49cc'c1823c8e'58ea3498'0ad8b720_u128}, - {Sign::POS, -130, 0xb3732006'd1fbbba5'4b5f7194'1be508a4_u128}, - {Sign::POS, -130, 0xb60edafc'dd99ad1d'9e405fb8'bcb1ff1e_u128}, - {Sign::POS, -130, 0xb60edafc'dd99ad1d'9e405fb8'bcb1ff1e_u128}, - {Sign::POS, -130, 0xb8ae8671'b3d7dd6c'f7e2ab36'f09e9014_u128}, - {Sign::POS, -130, 0xbb522e5d'bf37f63b'c6696396'40c305bb_u128}, - {Sign::POS, -130, 0xbdf9def0'4cf980ff'a3dc9e46'4e98764b_u128}, - {Sign::POS, -130, 0xc0a5a490'dea95b5e'ffd3256b'59fa9c59_u128}, - {Sign::POS, -130, 0xc3558be0'85e3f4bc'b0a2d486'72a051a5_u128}, - {Sign::POS, -130, 0xc3558be0'85e3f4bc'b0a2d486'72a051a5_u128}, - {Sign::POS, -130, 0xc609a1bb'4aa98f59'acb2ca5d'4ca1c10e_u128}, - {Sign::POS, -130, 0xc8c1f339'9ca7d33b'43690b9e'3cde0d02_u128}, - {Sign::POS, -130, 0xcb7e8db1'cfe04827'18b1fd60'383f7e5a_u128}, - {Sign::POS, -130, 0xce3f7eb9'a517c969'0248757e'5f45af3d_u128}, - {Sign::POS, -130, 0xd104d427'de7fbcc4'7c4acd60'5be48bc1_u128}, - {Sign::POS, -130, 0xd104d427'de7fbcc4'7c4acd60'5be48bc1_u128}, - {Sign::POS, -130, 0xd3ce9c15'e10ec927'58ff6362'9a92652d_u128}, - {Sign::POS, -130, 0xd69ce4e1'6303fcdd'6b49be3b'd8c89f10_u128}, - {Sign::POS, -130, 0xd96fbd2e'2814c9cc'e6dd603a'881e9060_u128}, - {Sign::POS, -130, 0xd96fbd2e'2814c9cc'e6dd603a'881e9060_u128}, - {Sign::POS, -130, 0xdc4733e7'cbcbfc8c'89e281c9'8c1d705c_u128}, - {Sign::POS, -130, 0xdf235843'9aa5dd12'dc0db7cf'0cce9f32_u128}, - {Sign::POS, -130, 0xe20439c2'7a7c01b8'fdf1c5b8'46db9deb_u128}, - {Sign::POS, -130, 0xe20439c2'7a7c01b8'fdf1c5b8'46db9deb_u128}, - {Sign::POS, -130, 0xe4e9e832'e2da0c05'3dd7eab4'8869c402_u128}, - {Sign::POS, -130, 0xe7d473b2'e5db8f2a'4e8fcc90'0b41daef_u128}, - {Sign::POS, -130, 0xe7d473b2'e5db8f2a'4e8fcc90'0b41daef_u128}, - {Sign::POS, -130, 0xeac3ecb2'4a3ac7b4'7593e1a9'e917359a_u128}, - {Sign::POS, -130, 0xedb863f4'b73f982d'e7741396'b49e1ce5_u128}, - {Sign::POS, -130, 0xedb863f4'b73f982d'e7741396'b49e1ce5_u128}, - {Sign::POS, -130, 0xf0b1ea93'f34675a7'c8ba4f8f'47b85a5c_u128}, - {Sign::POS, -130, 0xf3b09202'359f9787'7007c127'6821b705_u128}, - {Sign::POS, -130, 0xf3b09202'359f9787'7007c127'6821b705_u128}, - {Sign::POS, -130, 0xf6b46c0c'8c8fdea1'7ee19afe'6db7e324_u128}, - {Sign::POS, -130, 0xf9bd8add'584687f0'edf54f37'f6d40420_u128}, - {Sign::POS, -130, 0xf9bd8add'584687f0'edf54f37'f6d40420_u128}, - {Sign::POS, -130, 0xfccc00fe'dba4e6fb'efe52ccf'03e7dee1_u128}, - {Sign::POS, -130, 0xffdfe15d'e3c01bac'1be2585c'279c50a5_u128}, - {Sign::POS, -130, 0xffdfe15d'e3c01bac'1be2585c'279c50a5_u128}, - {Sign::POS, -129, 0x817c9fa6'43880404'e0b571f5'c91b0446_u128}, - {Sign::POS, -129, 0x830c1742'7ea55eca'7178594b'ef2def59_u128}, - {Sign::POS, -129, 0x830c1742'7ea55eca'7178594b'ef2def59_u128}, - {Sign::POS, -129, 0x849e6196'487c1d1c'9a741bb1'71158d2a_u128}, - {Sign::POS, -129, 0x849e6196'487c1d1c'9a741bb1'71158d2a_u128}, - {Sign::POS, -129, 0x863388eb'55ebd295'1a618264'446cb495_u128}, - {Sign::POS, -129, 0x87cb97c3'ff9eac18'71dbdbbe'c51d7657_u128}, - {Sign::POS, -129, 0x87cb97c3'ff9eac18'71dbdbbe'c51d7657_u128}, - {Sign::POS, -129, 0x896698dc'e4cff76c'abe0b522'230f7d14_u128}, - {Sign::POS, -129, 0x896698dc'e4cff76c'abe0b522'230f7d14_u128}, - {Sign::POS, -129, 0x8b04972e'9d4d3011'd28e8ada'fea703b4_u128}, - {Sign::POS, -129, 0x8ca59def'7b5cefc5'208422d8'3be34b27_u128}, - {Sign::POS, -129, 0x8ca59def'7b5cefc5'208422d8'3be34b27_u128}, - {Sign::POS, -129, 0x8e49b895'5e3ffb8a'c385cf49'402af0e4_u128}, - {Sign::POS, -129, 0x8e49b895'5e3ffb8a'c385cf49'402af0e4_u128}, - {Sign::POS, -129, 0x8ff0f2d7'960a075c'da982a61'4e12c6dd_u128}, - {Sign::POS, -129, 0x8ff0f2d7'960a075c'da982a61'4e12c6dd_u128}, - {Sign::POS, -129, 0x919b58b0'd999bbc8'038401fc'1c1b5c2c_u128}, - {Sign::POS, -129, 0x919b58b0'd999bbc8'038401fc'1c1b5c2c_u128}, - {Sign::POS, -129, 0x9348f661'4f821394'a9b55d3f'16da746a_u128}, - {Sign::POS, -129, 0x9348f661'4f821394'a9b55d3f'16da746a_u128}, - {Sign::POS, -129, 0x94f9d870'aac256a5'088d2d14'73d4f7f5_u128}, - {Sign::POS, -129, 0x94f9d870'aac256a5'088d2d14'73d4f7f5_u128}, - {Sign::POS, -129, 0x96ae0bb0'5c35d5bd'7c1e117d'ea19e9e6_u128}, - {Sign::POS, -129, 0x96ae0bb0'5c35d5bd'7c1e117d'ea19e9e6_u128}, - {Sign::POS, -129, 0x98659d3d'd9b12532'336db063'0f536fb9_u128}, - {Sign::POS, 0, 0_u128}, - }, - // -log10(r) for the second step, generated by SageMath with: - // - // for i in range(-2^6, 2^7 + 1): - // r = 2^-16 * round( 2^16 / (1 + i*2^(-14)) ); - // s, m, e = RealField(128)(r).log10().sign_mantissa_exponent(); - // print("{Sign::POS," if s == -1 else "{Sign::NEG,", e, ", - // format_hex(m), "},"); - /* .step_2 = */ - { - {Sign::NEG, -137, 0xdeca7290'13cd7c31'7f1ce002'fa34131b_u128}, - {Sign::NEG, -137, 0xdb5475b4'4946d986'639afa08'5dd8b4c7_u128}, - {Sign::NEG, -137, 0xd7de6b0e'10cab7d2'05512632'fe9a58cb_u128}, - {Sign::NEG, -137, 0xd468529c'fc6fb395'b5380a99'53117d07_u128}, - {Sign::NEG, -137, 0xd0f22c60'9e474741'70af2d7d'53be1f31_u128}, - {Sign::NEG, -137, 0xcd7bf858'885dcae2'0ccd499c'49b74cc2_u128}, - {Sign::NEG, -137, 0xca05b684'4cba73cf'5b51ddc3'987ebfb8_u128}, - {Sign::NEG, -137, 0xc68f66e3'7d5f545a'49375f51'89b3782b_u128}, - {Sign::NEG, -137, 0xc3190975'ac495b7a'f6e57738'865c712f_u128}, - {Sign::NEG, -137, 0xbfa29e3a'6b70547e'ca02b10a'8c712acd_u128}, - {Sign::NEG, -137, 0xbc2c2531'4cc6e6b6'78e50382'10208151_u128}, - {Sign::NEG, -137, 0xb8b59e59'e23a9524'0fa099ec'd71ee0ea_u128}, - {Sign::NEG, -137, 0xb53f09b3'bdb3be28'eeb445cc'b8fb09ed_u128}, - {Sign::NEG, -137, 0xb1c8673e'71159b33'c352fff1'8a1c02fb_u128}, - {Sign::NEG, -137, 0xae51b6f9'8e3e406e'7949e03e'cf9b390b_u128}, - {Sign::NEG, -137, 0xaadaf8e4'a7069c6c'2681f33f'30aadedc_u128}, - {Sign::NEG, -137, 0xa7642cff'4d4277d6'f01d5496'eea213b3_u128}, - {Sign::NEG, -137, 0xa3ed5349'12c0751d'e92ef555'ff1de975_u128}, - {Sign::NEG, -137, 0xa0766bc1'894a1022'eb0c7519'b3e7c1e0_u128}, - {Sign::NEG, -137, 0x9c21b6e9'1e7f03a3'f60d204f'f0fe5296_u128}, - {Sign::NEG, -137, 0x98aab049'1050bea8'125c19a4'f057c18b_u128}, - {Sign::NEG, -137, 0x95339bd6'4cd953e7'7e9383ce'1bdf9575_u128}, - {Sign::NEG, -137, 0x91bc7990'65cc57d6'bf274f4d'8f770253_u128}, - {Sign::NEG, -137, 0x8e454976'ecd836ad'656bd9b7'58fe44ba_u128}, - {Sign::NEG, -137, 0x8ace0b89'73a63413'bfdd2c7f'388fc014_u128}, - {Sign::NEG, -137, 0x8756bfc7'8bda6ad0'83fbf6ed'936c493a_u128}, - {Sign::NEG, -137, 0x83df6630'c713cc76'71bfa9a1'8bec01cc_u128}, - {Sign::NEG, -137, 0x8067fec4'b6ec2111'f09d19f5'6dbfef72_u128}, - {Sign::NEG, -138, 0xf9e11305'd9f00dad'4c422713'b1642228_u128}, - {Sign::NEG, -138, 0xf2f20cd5'f58de39a'0c3c7c56'99b7a0a4_u128}, - {Sign::NEG, -138, 0xec02eaf8'e3c656ff'b8db7c69'e3fa0797_u128}, - {Sign::NEG, -138, 0xe513ad6d'c7a3a553'a083eb05'506ff7ed_u128}, - {Sign::NEG, -138, 0xde245433'c425b5c5'c21595e7'45f1fa15_u128}, - {Sign::NEG, -138, 0xd734df49'fc42189b'b9d5bcdb'fe719389_u128}, - {Sign::NEG, -138, 0xd0454eaf'92e4068b'a17a1e85'e93461f4_u128}, - {Sign::NEG, -138, 0xc955a263'aaec6016'e3537584'da333fda_u128}, - {Sign::NEG, -138, 0xc265da65'6731ace5'00963177'f24682c2_u128}, - {Sign::NEG, -138, 0xbb75f6b3'ea801b1e'4ac03734'7bcfc50e_u128}, - {Sign::NEG, -138, 0xb485f74e'57997ec6'901a736a'4364cdfd_u128}, - {Sign::NEG, -138, 0xad95dc33'd1355117'bb550acc'3b9d7247_u128}, - {Sign::NEG, -138, 0xa6a5a563'7a00afdc'663cf2b2'7e8f1ffb_u128}, - {Sign::NEG, -138, 0x9fb552dc'749e5cca'5f89bd08'feb39952_u128}, - {Sign::NEG, -138, 0x98c4e49d'e3a6bcdd'23c2623c'73f494db_u128}, - {Sign::NEG, -138, 0x91d45aa6'e9a7d7b0'4937d3b5'485af61e_u128}, - {Sign::NEG, -138, 0x8ae3b4f6'a92556d9'df14214e'7a6d8111_u128}, - {Sign::NEG, -138, 0x83f2f38c'44988544'bf7cfc14'999fb4bc_u128}, - {Sign::NEG, -139, 0xfa042ccd'bce09d15'a990c0ee'569a8d51_u128}, - {Sign::NEG, -139, 0xec223b0b'32227c9e'a38463e9'd941e1c2_u128}, - {Sign::NEG, -139, 0xde4011cf'2daaff31'ba032453'0edaa03f_u128}, - {Sign::NEG, -139, 0xd05db117'f419b857'5e997a02'dad7ace7_u128}, - {Sign::NEG, -139, 0xc27b18e3'c9f977c7'4a14676d'4d0f817e_u128}, - {Sign::NEG, -139, 0xb4984930'f3c0481c'857c002e'e7a1e473_u128}, - {Sign::NEG, -139, 0xa6b541fd'b5cf6d89'5923b2eb'72d8012a_u128}, - {Sign::NEG, -139, 0x98d20348'5473648b'21cde8f8'5ca1f9fd_u128}, - {Sign::NEG, -139, 0x8aee8d0f'13e3e09e'0be08e08'b1d212d4_u128}, - {Sign::NEG, -140, 0xfa15bea0'708795e1'69502399'8e6bd7b0_u128}, - {Sign::NEG, -140, 0xde4df414'0b42822f'634cea67'50617a92_u128}, - {Sign::NEG, -140, 0xc285ba75'7feb2781'fbd7e970'aef9dbb8_u128}, - {Sign::NEG, -140, 0xa6bd11c1'564a8ace'9aedc1c1'ba7d0695_u128}, - {Sign::NEG, -140, 0x8af3f9f4'1600120a'8d306ba2'07233c44_u128}, - {Sign::NEG, -141, 0xde54e614'8d030322'856a0a3a'00fcf3c1_u128}, - {Sign::NEG, -141, 0xa6c0fa00'de35f314'b3a2c140'7cf6d38d_u128}, - {Sign::NEG, -142, 0xde585f4c'5bbbcd3d'd791cf6a'70c3a504_u128}, - {Sign::NEG, -143, 0xde5a1bf6'27b1f68f'10a633f2'c4a8ea22_u128}, - {Sign::NEG, 0, 0_u128}, - {Sign::POS, -143, 0xde5d9565'8a729eab'ed4a68e5'e6e83ddf_u128}, - {Sign::POS, -142, 0xde5f522b'21e3e25a'3281f187'2cdbee94_u128}, - {Sign::POS, -141, 0xa6c8cb3b'7e5bbbfd'f1466eda'a96e356e_u128}, - {Sign::POS, -141, 0xde62cbd2'1e895473'8a607fd6'95dfc3d9_u128}, - {Sign::POS, -140, 0x8afed570'32bebc7c'c36b8713'ceefe2de_u128}, - {Sign::POS, -140, 0xa6ccb436'a3c72fa4'5c2e76c9'53e3e3e6_u128}, - {Sign::POS, -140, 0xc29b023f'dcb2dccf'8e4950fa'5c943bbf_u128}, - {Sign::POS, -140, 0xde69bf8f'58005dfc'20fa8a73'c585f634_u128}, - {Sign::POS, -140, 0xfa38ec28'905810a3'0aa106d9'b0a9717a_u128}, - {Sign::POS, -139, 0x8b044407'80460c2a'85d70e03'2de41aec_u128}, - {Sign::POS, -139, 0x98ec49a3'11cc30ab'beee21cb'b82a9a78_u128}, - {Sign::POS, -139, 0xa6d486e8'ba5151a0'abd7b0fd'd8efe6f6_u128}, - {Sign::POS, -139, 0xb4bcfbda'377d31cc'3221c56e'2c1aa912_u128}, - {Sign::POS, -139, 0xc2a5a879'470c7c37'57b795a3'6d9c5f19_u128}, - {Sign::POS, -139, 0xd08e8cc7'a6d0c580'131ec142'c053ac3b_u128}, - {Sign::POS, -139, 0xde77a8c7'14b08d28'35e3298f'4bb2aa0a_u128}, - {Sign::POS, -139, 0xec60fc79'4ea73ee4'7133dafd'fc44f160_u128}, - {Sign::POS, -139, 0xfa4a87e0'12c533eb'74b37d23'121c59d5_u128}, - {Sign::POS, -138, 0x841a257e'8f97da22'93bf5f42'07da8a4c_u128}, - {Sign::POS, -138, 0x8b0f22e9'19107c0c'fdb5990e'c6057f4e_u128}, - {Sign::POS, -138, 0x92043c30'84f41481'2d408a58'b1b202fe_u128}, - {Sign::POS, -138, 0x98f97155'b274b1ab'1759381b'61dfbf01_u128}, - {Sign::POS, -138, 0x9feec259'80cedbbe'41e90a05'4df4b9f1_u128}, - {Sign::POS, -138, 0xa6e42f3c'cf49959d'a1e66c62'03725d50_u128}, - {Sign::POS, -138, 0xadd9b800'7d365d83'8693d36a'b45bd7ce_u128}, - {Sign::POS, -138, 0xb4cf5ca5'69f12da9'91e25bb4'0ad3f098_u128}, - {Sign::POS, -138, 0xbbc51d2c'74e07cf0'bdf94392'c4cc7f6c_u128}, - {Sign::POS, -138, 0xc2baf996'7d753f89'6fe37973'354a82f9_u128}, - {Sign::POS, -138, 0xc9b0f1e4'632ae79b'97647b42'67bfd801_u128}, - {Sign::POS, -138, 0xd0a70617'058765ee'dbf5c32a'454f7bdf_u128}, - {Sign::POS, -138, 0xd79d362f'441b2a92'd6edfe04'c37ba916_u128}, - {Sign::POS, -138, 0xde93822d'fe812587'5ad3480c'cfbe9890_u128}, - {Sign::POS, -138, 0xe589ea14'145ec764'c7d9ac76'5be7e325_u128}, - {Sign::POS, -138, 0xec806de2'65640204'6d8f24b9'a3ca011b_u128}, - {Sign::POS, -138, 0xf3770d99'd14b4928'f9b65480'7dcdd5b2_u128}, - {Sign::POS, -138, 0xfa6dc93b'37d99326'f4513f47'45663028_u128}, - {Sign::POS, -137, 0x80b25063'bc6f2cc6'a46e9a72'd80da75f_u128}, - {Sign::POS, -137, 0x842dca1f'ba19cce6'ee60992b'51ffac4b_u128}, - {Sign::POS, -137, 0x87a951d2'04deeaf3'1977fa1c'786886b3_u128}, - {Sign::POS, -137, 0x8b24e77b'0cb60a84'0e5f7c52'cdf119d5_u128}, - {Sign::POS, -137, 0x8ea08b1b'419bf221'3bf9d70d'a1021a10_u128}, - {Sign::POS, -137, 0x921c3cb3'1392ab94'fd0406b0'7523b8e6_u128}, - {Sign::POS, -137, 0x9597fc42'f2a18441'0453ee32'c020f2a8_u128}, - {Sign::POS, -137, 0x9913c9cb'4ed50d72'cfb3ec22'066bf7f6_u128}, - {Sign::POS, -137, 0x9c8fa54c'983f1cb8'215c025b'd493ecf9_u128}, - {Sign::POS, -137, 0x9f2c9319'2e68232b'39c116b7'ee3a83ec_u128}, - {Sign::POS, -137, 0xa2a8870f'24ac5f66'f41f4b3e'de2782f0_u128}, - {Sign::POS, -137, 0xa62488ff'3c735799'61196927'723eb75c_u128}, - {Sign::POS, -137, 0xa9a098e9'e5e2a432'0e615e83'6cb1edab_u128}, - {Sign::POS, -137, 0xad1cb6cf'91252372'6981331c'5fc71cfc_u128}, - {Sign::POS, -137, 0xb098e2b0'ae6af9c2'5f6a4faa'054f11fa_u128}, - {Sign::POS, -137, 0xb4151c8d'ade99205'02a68bc6'81a74c28_u128}, - {Sign::POS, -137, 0xb7916466'ffdb9ded'382ba24d'90566403_u128}, - {Sign::POS, -137, 0xbb0dba3d'14811652'6ad1abe5'1dd22e00_u128}, - {Sign::POS, -137, 0xbe8a1e10'5c1f3b85'456d3f7f'59b13960_u128}, - {Sign::POS, -137, 0xc2068fe1'470095a4'738dd8b7'd66e9058_u128}, - {Sign::POS, -137, 0xc5830fb0'4574f4f1'68e123fe'd7ff11c6_u128}, - {Sign::POS, -137, 0xc8ff9d7d'c7d17225'2f3bd097'80c3aa11_u128}, - {Sign::POS, -137, 0xcc7c394a'3e706ec5'3b48887f'1ce36935_u128}, - {Sign::POS, -137, 0xcff8e316'19b19578'47ddae65'5ecc4633_u128}, - {Sign::POS, -137, 0xd3759ae1'c9f9da5b'37fa81ee'f4819c88_u128}, - {Sign::POS, -137, 0xd6f260ad'bfb37b55'ff6c4a8d'747c65ed_u128}, - {Sign::POS, -137, 0xda6f347a'6b4e0070'921c2949'3a33318c_u128}, - {Sign::POS, -137, 0xddec1648'3d3e3c27'da0631eb'65e731d8_u128}, - {Sign::POS, -137, 0xe1690617'a5fe4bc2'b3da6c07'd110babc_u128}, - {Sign::POS, -137, 0xe4e603e9'160d97a6'f2485c78'68b8835a_u128}, - {Sign::POS, -137, 0xe8630fbc'fdf0d3ae'67f5b7ed'01344055_u128}, - {Sign::POS, -137, 0xebe02993'ce31ff7b'f820df44'5b1d0622_u128}, - {Sign::POS, -137, 0xef5d516d'f76066d0'adefc674'b7eca5cd_u128}, - {Sign::POS, -137, 0xf2da874b'ea10a1e0'da6be6dc'057d3235_u128}, - {Sign::POS, -137, 0xf657cb2e'16dc95a9'392bdde1'52ab5ff5_u128}, - {Sign::POS, -137, 0xf9d51d14'ee637444'1bab58e2'ec99cf73_u128}, - {Sign::POS, -137, 0xfd527d00'e149bd3e'9b51ef7e'3388d692_u128}, - {Sign::POS, -136, 0x8067f579'301c9ef6'e914c6a7'f3f22fa2_u128}, - {Sign::POS, -136, 0x8226b374'edf088e2'0d22862e'b2081c94_u128}, - {Sign::POS, -136, 0x83e57873'e27ad153'29ebd0b4'76cd8fd8_u128}, - {Sign::POS, -136, 0x85a44476'461854a0'98feddc2'806d01ed_u128}, - {Sign::POS, -136, 0x8763177c'512896af'471bfc26'1a401854_u128}, - {Sign::POS, -136, 0x88b23a5b'61430a16'b6f89c19'b4cd1acd_u128}, - {Sign::POS, -136, 0x8a7119a8'5909ebe9'b39aaf34'163fb099_u128}, - {Sign::POS, -136, 0x8c2ffff9'9357e887'1665f0f8'21541c36_u128}, - {Sign::POS, -136, 0x8deeed4f'489679a6'a5051754'e049c1cb_u128}, - {Sign::POS, -136, 0x8fade1a9'b131c159'8c5a9a1c'57b2e986_u128}, - {Sign::POS, -136, 0x916cdd09'05988a35'1d844843'8a26a9ae_u128}, - {Sign::POS, -136, 0x932bdf6d'7e3c477d'8e3a0913'ecd2fd02_u128}, - {Sign::POS, -136, 0x94eae8d7'53911550'bc881a45'f47f1d36_u128}, - {Sign::POS, -136, 0x96a9f946'be0db8d0'f5e51c05'499b06d0_u128}, - {Sign::POS, -136, 0x986910bb'f62ba04f'c1a43be8'1a243fde_u128}, - {Sign::POS, -136, 0x9a282f37'3466e378'aec3cfeb'e971beb7_u128}, - {Sign::POS, -136, 0x9be754b8'b13e437c'2518b293'28614989_u128}, - {Sign::POS, -136, 0x9da68140'a5332b3a'39d6b147'cbe803a4_u128}, - {Sign::POS, -136, 0x9f65b4cf'48c9af6d'87765e30'04ae428d_u128}, - {Sign::POS, -136, 0xa124ef64'd4888ed6'08f896ab'28245bac_u128}, - {Sign::POS, -136, 0xa2e43101'80f93263'f8880fb5'ca630c87_u128}, - {Sign::POS, -136, 0xa4a379a5'86a7ad62'b179397c'f82e935c_u128}, - {Sign::POS, -136, 0xa662c951'1e22bda3'95a8cb71'7197ad81_u128}, - {Sign::POS, -136, 0xa8222004'7ffbcba8'f6394a34'b7f9a4a4_u128}, - {Sign::POS, -136, 0xa9e17dbf'e4c6ead0'ffafd8c2'b57884e8_u128}, - {Sign::POS, -136, 0xaba0e283'851ad980'a970a643'b8a6ac2b_u128}, - {Sign::POS, -136, 0xad604e4f'9991014e'a89b49fb'749d47e0_u128}, - {Sign::POS, -136, 0xaf1fc124'5ac5772e'66475ed2'ac983305_u128}, - {Sign::POS, -136, 0xb06f5be1'bf1918e7'b4fd6209'364bb36f_u128}, - {Sign::POS, -136, 0xb22edb06'36da31d6'8b5ce79b'0965962a_u128}, - {Sign::POS, -136, 0xb3ee6133'f7149769'6724232b'07396427_u128}, - {Sign::POS, -136, 0xb5adee6b'386e62ae'2f02b14d'cad8a49c_u128}, - {Sign::POS, -136, 0xb76d82ac'339058db'bd6443a8'1f792e07_u128}, - {Sign::POS, -136, 0xb92d1df7'2125eb7c'ea1cd962'5749939a_u128}, - {Sign::POS, -136, 0xbaecc04c'39dd389b'97775e31'42198913_u128}, - {Sign::POS, -136, 0xbcac69ab'b6670aeb'c2a701b8'09a2bc39_u128}, - {Sign::POS, -136, 0xbe6c1a15'cf76d9f6'979b990f'39e662e3_u128}, - {Sign::POS, -136, 0xc02bd18a'bdc2ca45'88395c46'3ddd82b2_u128}, - {Sign::POS, -136, 0xc1eb900a'ba03ad8d'66f451bd'9ba5ed05_u128}, - {Sign::POS, -136, 0xc3ab5595'fcf502d9'84cfb941'3f6437a6_u128}, - {Sign::POS, -136, 0xc56b222c'bf54f6b6'd2c1c8d3'2943ca42_u128}, - {Sign::POS, -136, 0xc72af5cf'39e4635f'067c0d1f'd95192e6_u128}, - {Sign::POS, -136, 0xc8ead07d'a566d0e3'c298bf9e'db6441f2_u128}, - {Sign::POS, -136, 0xcaaab238'3aa27559'c22d646a'ddde3910_u128}, - {Sign::POS, -136, 0xcc6a9aff'32603504'07c301e5'c7d1ca40_u128}, - {Sign::POS, -136, 0xce2a8ad2'c56ba27f'0fb44446'4df02505_u128}, - {Sign::POS, -136, 0xcfea81b3'2c92feec'05f1df35'91ae898f_u128}, - {Sign::POS, -136, 0xd13a7f7c'07506f7d'b43caf8e'7b891066_u128}, - {Sign::POS, -136, 0xd2fa82b3'6a610c4f'597fb13f'0d0fdf19_u128}, - {Sign::POS, -136, 0xd4ba8cf8'3dd2a06b'3c21f1c6'0a60b0d6_u128}, - {Sign::POS, -136, 0xd67a9e4a'ba7d7ce5'2b745590'9a0428a4_u128}, - {Sign::POS, -136, 0xd83ab6ab'193ca223'1438b605'73d2da10_u128}, - {Sign::POS, -136, 0xd9fad619'92edc008'49f86400'c5ab2b11_u128}, - {Sign::POS, -136, 0xdbbafc96'60713620'd3c313d1'48a23c35_u128}, - {Sign::POS, -136, 0xdd7b2a21'baaa13cc'bc568523'55e0f0d5_u128}, - }, - // -log10(r) for the third step, generated by SageMath with: - // - // for i in range(-80, 81): - // r = 2^-21 * round( 2^21 / (1 + i*2^(-21)) ); - // s, m, e = RealField(128)(r).log10().sign_mantissa_exponent(); - // print("{Sign::POS," if (s == -1) else "{Sign::NEG,", e, "," , - // format_hex(m), "},"); - /* .step_3 = */ - { - {Sign::NEG, -143, 0x8af8b9b3'22ba8c7d'54d7e498'98ca0093_u128}, - {Sign::NEG, -143, 0x893c0652'9deffc3d'c321bbf1'6665f29c_u128}, - {Sign::NEG, -143, 0x877f52e4'33ac7ec4'8246df71'40c3e4ae_u128}, - {Sign::NEG, -143, 0x85c29f67'e3ef35bc'1deaa9e8'5780e4c1_u128}, - {Sign::NEG, -143, 0x8405ebdd'aeb742cf'0cd8a512'1a9162d0_u128}, - {Sign::NEG, -143, 0x82493845'9403c7a7'b10486fa'4644308d_u128}, - {Sign::NEG, -143, 0x808c849f'93d3e5f0'578a2f61'eedd4be8_u128}, - {Sign::NEG, -144, 0xfd9fa1d7'5c4d7ea6'715b4a49'1790e8a7_u128}, - {Sign::NEG, -144, 0xfa263a53'c5f6eaf4'efb6273a'04c71573_u128}, - {Sign::NEG, -144, 0xf6acd2b4'64a25420'474d9015'60c17807_u128}, - {Sign::NEG, -144, 0xf3336af9'384dfd7c'6b9a5dec'eb80ec57_u128}, - {Sign::NEG, -144, 0xefba0322'40f82a5d'2665a32f'7cc64f79_u128}, - {Sign::NEG, -144, 0xec409b2f'7e9f1e16'17c8a673'16659363_u128}, - {Sign::NEG, -144, 0xe8c73320'f1411bfa'b62cdd3e'f5c8673d_u128}, - {Sign::NEG, -144, 0xe54dcaf6'98dc675e'4e4be6d5'a4a07422_u128}, - {Sign::NEG, -144, 0xe1d462b0'756f4394'032f86ff'08c92e22_u128}, - {Sign::NEG, -144, 0xde5afa4e'86f7f3ee'ce31a0d2'7359396f_u128}, - {Sign::NEG, -144, 0xdae191d0'cd74bbc1'7efc3180'aee36373_u128}, - {Sign::NEG, -144, 0xd7682937'48e3de5e'bb894b1e'0ce72fc4_u128}, - {Sign::NEG, -144, 0xd3eec081'f9439f19'00230f6c'7270f8be_u128}, - {Sign::NEG, -144, 0xd07557b0'de924142'9f63aaa5'63e9a399_u128}, - {Sign::NEG, -144, 0xccfbeec3'f8ce082d'c2354e44'1015e7eb_u128}, - {Sign::NEG, -144, 0xc98285bb'47f5372c'67d22bcf'5a452a4c_u128}, - {Sign::NEG, -144, 0xc6091c96'cc061190'65c46fa3'e3afea18_u128}, - {Sign::NEG, -144, 0xc28fb356'84fedaab'67e63bbe'1405c20d_u128}, - {Sign::NEG, -144, 0xbf1649fa'72ddd5ce'f061a284'212afbad_u128}, - {Sign::NEG, -144, 0xbb9ce082'95a1464c'57b0a190'1625b539_u128}, - {Sign::NEG, -144, 0xb82376ee'ed476f74'cc9d1c79'd93a9a1e_u128}, - {Sign::NEG, -144, 0xb4aa0d3f'79ce9499'5440d7a1'31392da8_u128}, - {Sign::NEG, -144, 0xb130a374'3b34f90a'ca0572f7'c9f7a7de_u128}, - {Sign::NEG, -144, 0xadb7398d'3178e019'dfa464cb'37fe6455_u128}, - {Sign::NEG, -144, 0xaa3dcf8a'5c988d17'1d26f48e'fb62e2e0_u128}, - {Sign::NEG, -144, 0xa6c4656b'bc924352'e0e635a6'81d259e2_u128}, - {Sign::NEG, -144, 0xa34afb31'5164461d'5f8b022f'27cbda35_u128}, - {Sign::NEG, -144, 0x9fd190db'1b0cd8c6'a40df5ca'390a0465_u128}, - {Sign::NEG, -144, 0x9c582669'198a3e9e'8fb76866'f01c4f2d_u128}, - {Sign::NEG, -144, 0x98debbdb'4cdabaf4'da1f690c'752fdeff_u128}, - {Sign::NEG, -144, 0x95655131'b4fc9119'112db8a3'dc07ee78_u128}, - {Sign::NEG, -144, 0x91ebe66c'51ee045a'9919c4c2'2125c79e_u128}, - {Sign::NEG, -144, 0x8e727b8b'23ad5808'ac6aa272'26204db3_u128}, - {Sign::NEG, -144, 0x8af9108e'2a38cf72'5bf708fe'ad2b1780_u128}, - {Sign::NEG, -144, 0x877fa575'658eade6'8ee54cbc'53cd19ed_u128}, - {Sign::NEG, -144, 0x84063a40'd5ad36b4'02ab59d3'8cc6e2c5_u128}, - {Sign::NEG, -144, 0x808ccef0'7a92ad29'4b0eaf0a'99286378_u128}, - {Sign::NEG, -145, 0xfa26c708'a87aa929'a448b11f'012c975c_u128}, - {Sign::NEG, -145, 0xf333eff8'c556e089'b0a1d584'117de73b_u128}, - {Sign::NEG, -145, 0xec4118b1'4bb6870e'e890f9fb'57fdabb6_u128}, - {Sign::NEG, -145, 0xe54e4132'3b962355'261d48c7'1e693130_u128}, - {Sign::NEG, -145, 0xde5b697b'94f23bf7'efecdd48'ed894c32_u128}, - {Sign::NEG, -145, 0xd768918d'57c75792'7944b995'7598a88a_u128}, - {Sign::NEG, -145, 0xd075b967'8411fcbf'a208bc08'75093645_u128}, - {Sign::NEG, -145, 0xc982e10a'19ceb219'f6bb94d8'9da8b432_u128}, - {Sign::NEG, -145, 0xc2900875'18f9fe3b'b07ebbab'782457b0_u128}, - {Sign::NEG, -145, 0xbb9d2fa8'819067be'b5126529'45eb9165_u128}, - {Sign::NEG, -145, 0xb4aa56a4'538e753c'96d57890'e171eea5_u128}, - {Sign::NEG, -145, 0xadb77d68'8ef0ad4e'94c5854b'9cd01726_u128}, - {Sign::NEG, -145, 0xa6c4a3f5'33b3968d'9a7eb881'1ec3e6bb_u128}, - {Sign::NEG, -145, 0x9fd1ca4a'41d3b792'403bd2ab'3e0fa2d7_u128}, - {Sign::NEG, -145, 0x98def067'b94d96f4'cad61d29'db384b6b_u128}, - {Sign::NEG, -145, 0x91ec164d'9a1dbb4d'2bc55fd6'b8a306ec_u128}, - {Sign::NEG, -145, 0x8af93bfb'e440ab33'011fd699'5111a927_u128}, - {Sign::NEG, -145, 0x84066172'97b2ed3d'959a26fa'ac7e5494_u128}, - {Sign::NEG, -146, 0xfa270d63'68e21007'c10eab72'66ac6bc0_u128}, - {Sign::NEG, -146, 0xec415772'74ef0439'0bb178b9'0026b2b2_u128}, - {Sign::NEG, -146, 0xde5ba112'5385c43b'ac3bfd92'5e6b33e1_u128}, - {Sign::NEG, -146, 0xd075ea43'049f5d3b'9d0a01a9'5b355319_u128}, - {Sign::NEG, -146, 0xc2903304'8834dc64'31b3b7b2'0a6a6496_u128}, - {Sign::NEG, -146, 0xb4aa7b56'de3f4ee0'170da891'504620f4_u128}, - {Sign::NEG, -146, 0xa6c4c33a'06b7c1d9'53289e84'744549cb_u128}, - {Sign::NEG, -146, 0x98df0aae'01974279'45519048'b0ce7e7f_u128}, - {Sign::NEG, -146, 0x8af951b2'ced6dde8'a6118c42'bf99407e_u128}, - {Sign::NEG, -147, 0xfa273090'dcdf429f'0e5b474c'c5a64cf6_u128}, - {Sign::NEG, -147, 0xde5bbcdd'c0b533aa'a74dab3b'd6067bc7_u128}, - {Sign::NEG, -147, 0xc290484c'4921a941'9f73f4e3'7357341b_u128}, - {Sign::NEG, -147, 0xa6c4d2dc'7616bdb0'31bf5d5f'815220e7_u128}, - {Sign::NEG, -147, 0x8af95c8e'47868b41'4b987ca5'fca242d7_u128}, - {Sign::NEG, -148, 0xde5bcac3'7ac6587d'19be3fab'd93832c5_u128}, - {Sign::NEG, -148, 0xa6c4daad'af3d75e0'8fd43f0c'9ce444d3_u128}, - {Sign::NEG, -149, 0xde5bd1b6'58ad4676'061cd853'e796bc2c_u128}, - {Sign::NEG, -150, 0xde5bd52f'c7d8545f'87d6afab'fba0644f_u128}, - {Sign::POS, 0, 0_u128}, - {Sign::POS, -150, 0xde5bdc22'a69d9e19'a9bf3200'1043629d_u128}, - {Sign::POS, -149, 0xde5bdf9c'1637d9ef'8014f0f3'60272d82_u128}, - {Sign::POS, -148, 0xa6c4ea50'24795bd2'fe94a02f'c639c0e3_u128}, - {Sign::POS, -148, 0xde5be68e'f5db7f99'bee710a5'ace7c8d4_u128}, - {Sign::POS, -147, 0x8af97245'3faf11e8'1a778d81'00437e4f_u128}, - {Sign::POS, -147, 0xa6c4f221'608e89fe'97d773f8'992f7051_u128}, - {Sign::POS, -147, 0xc29072db'dd9a0dd5'0c9ee584'1a3afa95_u128}, - {Sign::POS, -147, 0xde5bf474'b6df8331'7b644b13'993cf4ef_u128}, - {Sign::POS, -147, 0xfa2776eb'ec6ccfdb'3448f66e'2bd7a0ca_u128}, - {Sign::POS, -146, 0x8af97d20'bf27eccd'6a7ca5f1'a87a1a3c_u128}, - {Sign::POS, -146, 0x98df3f3a'b64b431d'245675fe'3061108f_u128}, - {Sign::POS, -146, 0xa6c501c3'dba75dc2'64136e97'019d0a3b_u128}, - {Sign::POS, -146, 0xb4aac4bc'2f432fa3'6cdadac4'd6925bd4_u128}, - {Sign::POS, -146, 0xc2908823'b125aba7'2899e237'91d29632_u128}, - {Sign::POS, -146, 0xd0764bfa'6155c4b5'28039e1f'0323a4c1_u128}, - {Sign::POS, -146, 0xde5c1040'3fda6db5'a2912e03'afc8cc28_u128}, - {Sign::POS, -146, 0xec41d4f5'4cba9991'7681cc9f'9e0d89f9_u128}, - {Sign::POS, -146, 0xfa279a19'87fd3b32'28dae4b7'241255e1_u128}, - {Sign::POS, -145, 0x8406afd6'78d4a2c0'f2b412f8'dceda28e_u128}, - {Sign::POS, -145, 0x8af992d7'c4e2d5b5'bf5dccd9'67504857_u128}, - {Sign::POS, -145, 0x91ec7610'a82cafed'3716dbf9'50b07f85_u128}, - {Sign::POS, -145, 0x98df5981'22b5aadd'69eebe0b'8e5b18e1_u128}, - {Sign::POS, -145, 0x9fd23d29'34813ffc'bb583ce6'5af56beb_u128}, - {Sign::POS, -145, 0xa6c52108'dd92e8c1'e22978ef'a7a962a0_u128}, - {Sign::POS, -145, 0xadb80520'1dee1ea3'e89bf389'8ef27836_u128}, - {Sign::POS, -145, 0xb4aae96e'f5965b1a'2c4c997e'c90bab0b_u128}, - {Sign::POS, -145, 0xbb9dcdf5'648f179c'5e3bcd6f'21fe6224_u128}, - {Sign::POS, -145, 0xc290b2b3'6adbcda2'82cd723b'f1524680_u128}, - {Sign::POS, -145, 0xc98397a9'087ff6a4'f1c8f574'935e109b_u128}, - {Sign::POS, -145, 0xd0767cd6'3d7f0c1c'565959c2'e4394a59_u128}, - {Sign::POS, -145, 0xd769623b'09dc8781'af0d4157'bc4f05be_u128}, - {Sign::POS, -145, 0xde5c47d7'6d9be24e'4dd6f857'6e9188b8_u128}, - {Sign::POS, -145, 0xe54f2dab'68c095fb'd80c7f46'484eee3d_u128}, - {Sign::POS, -145, 0xec4213b6'fb4e1c04'46679575'12a6bd26_u128}, - {Sign::POS, -145, 0xf334f9fa'2547ede1'e505c36d'95a074fa_u128}, - {Sign::POS, -145, 0xfa27e074'e6b1850f'5368655f'1ce3110b_u128}, - {Sign::POS, -144, 0x808d6393'9fc72d83'c23a5ac5'7f06c112_u128}, - {Sign::POS, -144, 0x8406d708'97f0f4a2'df39eb58'90580f93_u128}, - {Sign::POS, -144, 0x87804a99'5bd7d4a2'cd896f3e'43f38669_u128}, - {Sign::POS, -144, 0x8af9be45'eb7d8a41'83b16ff7'eecace8c_u128}, - {Sign::POS, -144, 0x8e73320e'46e3d23d'21ec7ae8'ffa1531d_u128}, - {Sign::POS, -144, 0x91eca5f2'6e0c6953'f227268d'464ae907_u128}, - {Sign::POS, -144, 0x956619f2'60f90c44'680017af'3bbaf2d3_u128}, - {Sign::POS, -144, 0x98df8e0e'1fab77cd'20c8069e'4ae400de_u128}, - {Sign::POS, -144, 0x9c590245'aa2568ac'e381c465'1a67ee13_u128}, - {Sign::POS, -144, 0x9fd27699'00689ba2'a0e23fff'd718794e_u128}, - {Sign::POS, -144, 0xa34beb08'2276cd6d'73508b92'7f485b97_u128}, - {Sign::POS, -144, 0xa6c55f93'1051bacc'9ee5e19f'2eecdb55_u128}, - {Sign::POS, -144, 0xaa3ed439'c9fb207f'916daa3c'6c8fdc9d_u128}, - {Sign::POS, -144, 0xadb848fc'4f74bb45'e265804b'77126ed3_u128}, - {Sign::POS, -144, 0xb131bdda'a0c047df'52fd36ae'943fd7b4_u128}, - {Sign::POS, -144, 0xb4ab32d4'bddf830b'ce16dd7f'60311bf6_u128}, - {Sign::POS, -144, 0xb824a7ea'a6d4298b'6846c745'1d8105ac_u128}, - {Sign::POS, -144, 0xbb9e1d1c'5b9ff81e'5fd38e2b'0650a884_u128}, - {Sign::POS, -144, 0xbf179269'dc44ab85'1cb61936'9e1c641f_u128}, - {Sign::POS, -144, 0xc29107d3'28c40080'3099a17e'0461648c_u128}, - {Sign::POS, -144, 0xc60a7d58'411fb3d0'56dbb75e'4813a12b_u128}, - {Sign::POS, -144, 0xc983f2f9'25598236'748c47b1'bbe45a07_u128}, - {Sign::POS, -144, 0xccfd68b5'd5732873'986da106'4b5913e1_u128}, - {Sign::POS, -144, 0xd076de8e'516e6348'faf478d3'd0b31300_u128}, - {Sign::POS, -144, 0xd3f05482'994cef77'fe47f0b2'6ba754ff_u128}, - {Sign::POS, -144, 0xd769ca92'ad1089c2'2e419b90'd8e709b7_u128}, - {Sign::POS, -144, 0xdae340be'8cbaeee9'406d82ea'ca788b6f_u128}, - {Sign::POS, -144, 0xde5cb706'384ddbaf'140a2bff'40e0d670_u128}, - {Sign::POS, -144, 0xe1d62d69'afcb0cd5'b2089d06'e51d8034_u128}, - {Sign::POS, -144, 0xe54fa3e8'f3343f1f'4d0c626a'636f2e4f_u128}, - {Sign::POS, -144, 0xe8c91a84'028b2f4e'416b93f8'c6f48d30_u128}, - {Sign::POS, -144, 0xec42913a'ddd19a25'152eda1d'd615c6f5_u128}, - {Sign::POS, -144, 0xefbc080d'85093c66'78117318'6fc07a66_u128}, - {Sign::POS, -144, 0xf3357efb'f833d2d5'43813830'e974324d_u128}, - {Sign::POS, -144, 0xf6aef606'37531a34'7a9ea2ef'6e1f5d41_u128}, - {Sign::POS, -144, 0xfa286d2c'4268cf47'4a3cd252'5dccc623_u128}, - {Sign::POS, -144, 0xfda1e46e'1976aed1'08e19004'ae218d5d_u128}, - {Sign::POS, -143, 0x808dade5'de3f3aca'9b62aaca'25d5d18a_u128}, - {Sign::POS, -143, 0x824a69a2'95c0f02b'bee9a8d4'3e00613c_u128}, - {Sign::POS, -143, 0x8407256d'334155ed'd8d4b69c'2056f729_u128}, - {Sign::POS, -143, 0x85c3e145'b6c14a72'e7cc2860'5d7bb77e_u128}, - {Sign::POS, -143, 0x87809d2c'2041ac1c'ff51b4bd'c834a8f1_u128}, - {Sign::POS, -143, 0x893d5920'6fc3594e'47c0774a'a81c3561_u128}, - {Sign::POS, -143, 0x8afa1522'a5473068'fe4cf331'ecb9eb62_u128}, - }, - // -log10(r) for the fourth step, generated by SageMath with: - // - // for i in range(-65, 65): - // r = 2^-28 * round( 2^28 / (1 + i*2^(-28)) ); - // s, m, e = RealField(128)(r).log10().sign_mantissa_exponent(); - // print("{Sign::POS," if (s == -1) else "{Sign::NEG,", e, ",", - // format_hex(m), "},"); - /* .step_4 = */ - { - {Sign::NEG, -151, 0xe1d54641'22cf95a4'e471a82b'bedbe0ae_u128}, - {Sign::NEG, -151, 0xde5bd6ec'7f7bc110'af6e93be'8e4c1764_u128}, - {Sign::NEG, -151, 0xdae26797'a490f80e'e44848f0'a5779499_u128}, - {Sign::NEG, -151, 0xd768f842'920f3a98'90205533'f4e70566_u128}, - {Sign::NEG, -151, 0xd3ef88ed'47f688a6'c01844ac'e3729e48_u128}, - {Sign::NEG, -151, 0xd0761997'c646e232'8151a232'4e41c7c4_u128}, - {Sign::NEG, -151, 0xccfcaa42'0d004734'e0edf74d'88cacafd_u128}, - {Sign::NEG, -151, 0xc9833aec'1c22b7a6'ec0ecc3a'5cd27e58_u128}, - {Sign::NEG, -151, 0xc609cb95'f3ae3381'afd5a7e7'0a6bf214_u128}, - {Sign::NEG, -151, 0xc2905c3f'93a2babe'39640ff4'47f81ceb_u128}, - {Sign::NEG, -151, 0xbf16ece8'fc004d55'95db88b5'422588b1_u128}, - {Sign::NEG, -151, 0xbb9d7d92'2cc6eb40'd25d952f'9beffeec_u128}, - {Sign::NEG, -151, 0xb8240e3b'25f69478'fc0bb71b'6ea03578_u128}, - {Sign::NEG, -151, 0xb4aa9ee3'e78f48f7'20076ee3'49cb7b20_u128}, - {Sign::NEG, -151, 0xb1312f8c'719108b4'4b723ba4'3353643d_u128}, - {Sign::NEG, -151, 0xadb7c034'c3fbd3a9'8b6d9b2d'a7657754_u128}, - {Sign::NEG, -151, 0xaa3e50dc'decfa9cf'ed1b0a01'987ad9b4_u128}, - {Sign::NEG, -151, 0xa6c4e184'c20c8b20'7d9c0354'6f57fc11_u128}, - {Sign::NEG, -151, 0xa34b722c'6db27794'4a12010d'0b0c4727_u128}, - {Sign::NEG, -151, 0x9fd202d3'e1c16f24'5f9e7bc4'c0f1c851_u128}, - {Sign::NEG, -151, 0x9c58937b'1e3971c9'cb62eac7'5cacde29_u128}, - {Sign::NEG, -151, 0x98df2422'231a7f7d'9a80c413'202be52a_u128}, - {Sign::NEG, -151, 0x9565b4c8'f0649838'da197c58'c3a6e445_u128}, - {Sign::NEG, -151, 0x91ec456f'8617bbf4'974e86fb'759f3988_u128}, - {Sign::NEG, -151, 0x8e72d615'e433eaa9'df415610'dadf46b3_u128}, - {Sign::NEG, -151, 0x8af966bc'0ab92451'bf135a61'0e7a1ddc_u128}, - {Sign::NEG, -151, 0x877ff761'f9a768e5'43e60366'a1cb2e09_u128}, - {Sign::NEG, -151, 0x84068807'b0feb85d'7adabf4e'9c75efce_u128}, - {Sign::NEG, -151, 0x808d18ad'30bf12b3'7112faf8'7c6591ee_u128}, - {Sign::NEG, -152, 0xfa2752a4'f1d0efc0'676043ec'6b994be5_u128}, - {Sign::NEG, -152, 0xf33473ef'12f5cfb9'9fa73d18'6649999d_u128}, - {Sign::NEG, -152, 0xec419538'c4ecc544'a53db362'aa5cc6f0_u128}, - {Sign::NEG, -152, 0xe54eb682'07b5d053'9266761d'e5e05f13_u128}, - {Sign::NEG, -152, 0xde5bd7ca'db50f0d8'81645201'b36e17ba_u128}, - {Sign::NEG, -152, 0xd768f913'3fbe26c5'8c7a112a'9a2b2a52_u128}, - {Sign::NEG, -152, 0xd0761a5b'34fd720c'cdea7b1a'0dc7ad42_u128}, - {Sign::NEG, -152, 0xc9833ba2'bb0ed2a0'5ff854b6'6e7ded1f_u128}, - {Sign::NEG, -152, 0xc2905ce9'd1f24872'5ce6604b'0911c5ed_u128}, - {Sign::NEG, -152, 0xbb9d7e30'79a7d374'def75d88'16cffc59_u128}, - {Sign::NEG, -152, 0xb4aa9f76'b22f739a'006e0982'bd8d96ef_u128}, - {Sign::NEG, -152, 0xadb7c0bc'7b8928d3'db8d1eb5'0fa7375c_u128}, - {Sign::NEG, -152, 0xa6c4e201'd5b4f314'8a9754fe'0c0073a7_u128}, - {Sign::NEG, -152, 0x9fd20346'c0b2d24e'27cf61a1'9e032f69_u128}, - {Sign::NEG, -152, 0x98df248b'3c82c672'cd77f748'9d9ef50b_u128}, - {Sign::NEG, -152, 0x91ec45cf'4924cf74'95d3c600'cf484f03_u128}, - {Sign::NEG, -152, 0x8af96712'e698ed45'9b257b3c'e3f82109_u128}, - {Sign::NEG, -152, 0x84068856'14df1fd7'f7afc1d4'792b015a_u128}, - {Sign::NEG, -153, 0xfa275331'a7eece3b'8b6a8408'31c123d8_u128}, - {Sign::NEG, -153, 0xec4195b6'47c38612'3ef142da'7335b35a_u128}, - {Sign::NEG, -153, 0xde5bd83a'093c6718'3e79062c'7cbb3b7d_u128}, - {Sign::NEG, -153, 0xd0761abc'ec597131'be870ed4'ed5b755b_u128}, - {Sign::NEG, -153, 0xc2905d3e'f11aa442'f3a09874'3d20fb64_u128}, - {Sign::NEG, -153, 0xb4aa9fc0'17800030'124ad974'bd15fbca_u128}, - {Sign::NEG, -153, 0xa6c4e240'5f8984dd'4f0b030a'9742eb00_u128}, - {Sign::NEG, -153, 0x98df24bf'c937322e'de664133'cead362d_u128}, - {Sign::NEG, -153, 0x8af9673e'54890808'f4e1bab8'3f55f5a1_u128}, - {Sign::NEG, -154, 0xfa275378'02fe0c9f'8e052253'3c713e98_u128}, - {Sign::NEG, -154, 0xde5bd871'a03259cf'129bc1c6'f293726e_u128}, - {Sign::NEG, -154, 0xc2905d69'80aef768'e0918216'6eeb17eb_u128}, - {Sign::NEG, -154, 0xa6c4e25f'a473e535'60f08720'313daa3f_u128}, - {Sign::NEG, -154, 0x8af96754'0b8122fc'fcc2ea56'6b3af38b_u128}, - {Sign::NEG, -155, 0xde5bd88d'6bad6110'3a25757e'00f4e3a0_u128}, - {Sign::NEG, -155, 0xa6c4e26f'46e91b3e'55d3f9e7'0cf177b8_u128}, - {Sign::NEG, -156, 0xde5bd89b'516ae82a'3d4aac85'125398d0_u128}, - {Sign::NEG, -157, 0xde5bd8a2'4449ac95'9ab5a849'a06f400d_u128}, - {Sign::POS, 0, 0_u128}, - {Sign::POS, -157, 0xde5bd8b0'2a073729'0d3cc88f'd4ef34c2_u128}, - {Sign::POS, -156, 0xde5bd8b7'1ce5fd51'225916c2'b3f33c90_u128}, - {Sign::POS, -155, 0xa6c4e28e'8bd3930a'17847f98'acf08d54_u128}, - {Sign::POS, -155, 0xde5bd8c5'02a38b5e'04439783'0931fddd_u128}, - {Sign::POS, -154, 0x8af9677f'79717409'c2ab3859'13176984_u128}, - {Sign::POS, -154, 0xa6c4e29e'2e48d4cc'e454dec8'2bde52e5_u128}, - {Sign::POS, -154, 0xc2905dbe'9fd7e82f'fe1522b0'470d7d7f_u128}, - {Sign::POS, -154, 0xde5bd8e0'ce1eae6a'a6e2721f'2afc3cce_u128}, - {Sign::POS, -154, 0xfa275404'b91d27b4'75b3458e'ec3c106c_u128}, - {Sign::POS, -153, 0x8af96795'3069aa22'80bf0ff2'f6cd9f93_u128}, - {Sign::POS, -153, 0x98df2528'e2a09a29'f09cc73b'7013b906_u128}, - {Sign::POS, -153, 0xa6c4e2bd'7333640c'55ee1480'619827c4_u128}, - {Sign::POS, -153, 0xb4aaa052'e22207e5'7c2e48d7'72250b3c_u128}, - {Sign::POS, -153, 0xc2905de9'2f6c85d1'2ed8ba8c'6fa81c98_u128}, - {Sign::POS, -153, 0xd0761b80'5b12ddeb'3968c521'4f33fc4f_u128}, - {Sign::POS, -153, 0xde5bd918'6515104f'6759c94e'2d017fad_u128}, - {Sign::POS, -153, 0xec4196b1'4d731d19'84272d01'4c70fe58_u128}, - {Sign::POS, -153, 0xfa27544b'142d0465'5b4c5b5f'180b9fe1_u128}, - {Sign::POS, -152, 0x840688f2'dca16327'5c226261'10c254a4_u128}, - {Sign::POS, -152, 0x8af967c0'9e5a3178'b345ef5d'90dd6545_u128}, - {Sign::POS, -152, 0x91ec468e'cf40ed34'98ce9208'7c5cb614_u128}, - {Sign::POS, -152, 0x98df255d'6f559668'f27a0a60'56dcfe57_u128}, - {Sign::POS, -152, 0x9fd2042c'7e982d23'a6061afe'b7929f24_u128}, - {Sign::POS, -152, 0xa6c4e2fb'fd08b172'99308918'494a4a20_u128}, - {Sign::POS, -152, 0xadb7c1cb'eaa72363'b1b71c7c'ca69a844_u128}, - {Sign::POS, -152, 0xb4aaa09c'47738304'd5579f97'0cf000a9_u128}, - {Sign::POS, -152, 0xbb9d7f6d'136dd063'e9cfdf6c'f676df42_u128}, - {Sign::POS, -152, 0xc2905e3e'4e960b8e'd4ddab9f'8032bbab_u128}, - {Sign::POS, -152, 0xc9833d0f'f8ec3493'7c3ed66a'b6f39fe9_u128}, - {Sign::POS, -152, 0xd0761be2'12704b7f'c5b134a5'bb25cf2e_u128}, - {Sign::POS, -152, 0xd768fab4'9b225061'96f29dc2'c0d26ca0_u128}, - {Sign::POS, -152, 0xde5bd987'93024346'd5c0ebcf'0fa0221e_u128}, - {Sign::POS, -152, 0xe54eb85a'fa10243d'67d9fb73'02d3c705_u128}, - {Sign::POS, -152, 0xec41972e'd04bf353'32fbabf2'095106f1_u128}, - {Sign::POS, -152, 0xf3347603'15b5b096'1ce3df2a'a59b0889_u128}, - {Sign::POS, -152, 0xfa2754d7'ca4d5c14'0b507996'6dd5143e_u128}, - {Sign::POS, -151, 0x808d19d6'77097aed'71ffb125'05e19d89_u128}, - {Sign::POS, -151, 0x84068941'40833efc'4657417a'9e657eae_u128}, - {Sign::POS, -151, 0x877ff8ac'4193fa3d'758de3f1'68f9f8c9_u128}, - {Sign::POS, -151, 0x8af96817'7a3bacb7'f2828ffc'57f43581_u128}, - {Sign::POS, -151, 0x8e72d782'ea7a5672'b0143e5b'e77b1053_u128}, - {Sign::POS, -151, 0x91ec46ee'924ff774'a121e91e'1d8769ef_u128}, - {Sign::POS, -151, 0x9565b65a'71bc8fc4'b88a8b9e'89e47b9c_u128}, - {Sign::POS, -151, 0x98df25c6'88c01f69'e92d2286'46302a9c_u128}, - {Sign::POS, -151, 0x9c589532'd75aa66b'25e8abcb'f5db5b8c_u128}, - {Sign::POS, -151, 0x9fd2049f'5d8c24cf'619c26b3'c62a45c8_u128}, - {Sign::POS, -151, 0xa34b740c'1b549a9d'8f2693cf'6e34c6cc_u128}, - {Sign::POS, -151, 0xa6c4e379'10b407dc'a166f4fe'2ee6b59a_u128}, - {Sign::POS, -151, 0xaa3e52e6'3daa6c93'8b3c4d6c'd3003616_u128}, - {Sign::POS, -151, 0xadb7c253'a237c8c9'3f85a195'af160c71_u128}, - {Sign::POS, -151, 0xb13131c1'3e5c1c84'b121f740'a191f084_u128}, - {Sign::POS, -151, 0xb4aaa12f'121767cc'd2f05583'12b2e136_u128}, - {Sign::POS, -151, 0xb824109d'1d69aaa8'97cfc4bf'f48d77de_u128}, - {Sign::POS, -151, 0xbb9d800b'6052e51e'f29f4ea7'c30c3ba5_u128}, - {Sign::POS, -151, 0xbf16ef79'dad31736'd63dfe38'83eff4e9_u128}, - {Sign::POS, -151, 0xc2905ee8'8cea40f7'358adfbd'c6d0009f_u128}, - {Sign::POS, -151, 0xc609ce57'76986267'036500d0'a51aa3b6_u128}, - {Sign::POS, -151, 0xc9833dc6'97dd7b8d'32ab7057'c2155e78_u128}, - {Sign::POS, -151, 0xccfcad35'f0b98c70'b63d3e87'4add3ff0_u128}, - {Sign::POS, -151, 0xd0761ca5'812c9518'80f97ce0'f6673948_u128}, - {Sign::POS, -151, 0xd3ef8c15'4936958b'85bf3e34'0580712d_u128}, - {Sign::POS, -151, 0xd768fb85'48d78dd0'b76d969d'42ce9734_u128}, - {Sign::POS, -151, 0xdae26af5'800f7def'08e39b87'02d0373a_u128}, - {Sign::POS, -151, 0xde5bda65'eede65ed'6d0063a9'23dd0cc6_u128}, - }}; - -// > P = fpminimax(log10(1 + x)/x, 3, [|128...|], [-0x1.0002143p-29 , 0x1p-29]); -// > P; -// > dirtyinfnorm(log10(1 + x)/x - P, [-0x1.0002143p-29 , 0x1p-29]); -// 0x1.64fb8...p-123 -constexpr Float128 BIG_COEFFS[4]{ - {Sign::NEG, -131, 0xde5bd8a9'373f89a7'6903c4ce'1582517d_u128}, - {Sign::POS, -130, 0x943d3b1b'7a1af679'b8a21791'624e2e8a_u128}, - {Sign::NEG, -130, 0xde5bd8a9'37287195'355baaaf'abc25990_u128}, - {Sign::POS, -129, 0xde5bd8a9'37287195'355baaaf'ad33dbd9_u128}, -}; - -// Reuse the output of the fast pass range reduction. -// -2^-8 <= m_x < 2^-7 -double log10_accurate(int e_x, int index, double m_x) { - - Float128 e_x_f128(static_cast<float>(e_x)); - Float128 sum = fputil::quick_mul(LOG10_2, e_x_f128); - sum = fputil::quick_add(sum, LOG10_TABLE.step_1[index]); - - Float128 v_f128 = log_range_reduction(m_x, LOG10_TABLE, sum); - - // Polynomial approximation - Float128 p = fputil::quick_mul(v_f128, BIG_COEFFS[0]); - p = fputil::quick_mul(v_f128, fputil::quick_add(p, BIG_COEFFS[1])); - p = fputil::quick_mul(v_f128, fputil::quick_add(p, BIG_COEFFS[2])); - p = fputil::quick_mul(v_f128, fputil::quick_add(p, BIG_COEFFS[3])); - - Float128 r = fputil::quick_add(sum, p); - - return static_cast<double>(r); -} -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS - -} // namespace - -LLVM_LIBC_FUNCTION(double, log10, (double x)) { - using namespace common_constants_internal; - using FPBits_t = typename fputil::FPBits<double>; - - FPBits_t xbits(x); - uint64_t x_u = xbits.uintval(); - - int x_e = -FPBits_t::EXP_BIAS; - - if (LIBC_UNLIKELY(xbits == FPBits_t::one())) { - // log10(1.0) = +0.0 - return 0.0; - } - - if (LIBC_UNLIKELY(xbits.uintval() < FPBits_t::min_normal().uintval() || - xbits.uintval() > FPBits_t::max_normal().uintval())) { - if (x == 0.0) { - // return -Inf and raise FE_DIVBYZERO. - fputil::set_errno_if_required(ERANGE); - fputil::raise_except_if_required(FE_DIVBYZERO); - return FPBits_t::inf(Sign::NEG).get_val(); - } - if (xbits.is_neg() && !xbits.is_nan()) { - fputil::set_errno_if_required(EDOM); - fputil::raise_except_if_required(FE_INVALID); - return FPBits_t::quiet_nan().get_val(); - } - if (xbits.is_inf_or_nan()) { - return x; - } - // Normalize denormal inputs. - xbits = FPBits_t(x * 0x1.0p52); - x_e -= 52; - x_u = xbits.uintval(); - } - - // log10(x) = log10(2^x_e * x_m) - // = x_e * log10(2) + log10(x_m) - - // Range reduction for log10(x_m): - // For each x_m, we would like to find r such that: - // -2^-8 <= r * x_m - 1 < 2^-7 - int shifted = static_cast<int>(x_u >> 45); - int index = shifted & 0x7F; - double r = RD[index]; - - // Add unbiased exponent. Add an extra 1 if the 8 leading fractional bits are - // all 1's. - x_e += static_cast<int>((x_u + (1ULL << 45)) >> 52); - double e_x = static_cast<double>(x_e); - - // hi is exact - double hi = fputil::multiply_add(e_x, LOG_2_HI, LOG_R_DD[index].hi); - // lo errors ~ e_x * LSB(LOG_2_LO) + LSB(LOG_R[index].lo) + rounding err - // <= 2 * (e_x * LSB(LOG_2_LO) + LSB(LOG_R[index].lo)) - double lo = fputil::multiply_add(e_x, LOG_2_LO, LOG_R_DD[index].lo); - - // Set m = 1.mantissa. - uint64_t x_m = (x_u & 0x000F'FFFF'FFFF'FFFFULL) | 0x3FF0'0000'0000'0000ULL; - double m = FPBits_t(x_m).get_val(); - - double u, u_sq; - fputil::DoubleDouble r1; - - // Perform exact range reduction -#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE - u = fputil::multiply_add(r, m, -1.0); // exact -#else - uint64_t c_m = x_m & 0x3FFF'E000'0000'0000ULL; - double c = FPBits_t(c_m).get_val(); - u = fputil::multiply_add(r, m - c, CD[index]); // exact -#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE - - // Error of u_sq = ulp(u^2); - u_sq = u * u; - // Degree-7 minimax polynomial - double p0 = fputil::multiply_add(u, LOG_COEFFS[1], LOG_COEFFS[0]); - double p1 = fputil::multiply_add(u, LOG_COEFFS[3], LOG_COEFFS[2]); - double p2 = fputil::multiply_add(u, LOG_COEFFS[5], LOG_COEFFS[4]); - double p = fputil::polyeval(u_sq, lo, p0, p1, p2); - - // Exact sum: - // r1.hi + r1.lo = e_x * log(2)_hi - log(r)_hi + u - r1 = fputil::exact_add(hi, u); - r1.lo += p; - - // Quick double-double multiplication: - // r2.hi + r2.lo ~ r1 * log10(e), - // with error bounded by: - // 4*ulp( ulp(r2.hi) ) - fputil::DoubleDouble r2 = fputil::quick_mult(r1, LOG10_E); - -#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - return r2.hi + r2.lo; -#else - // Technicallly error of r1.lo is bounded by: - // |hi|*ulp(log(2)_lo) + C*ulp(u^2) - // To simplify the error computation a bit, we replace |hi|*ulp(log(2)_lo) - // with the upper bound: 2^11 * ulp(log(2)_lo) = 2^-85. - // Total error is bounded by ~ C * ulp(u^2) + 2^-85. - double err = fputil::multiply_add(u_sq, P_ERR, HI_ERR); - - // Lower bound from the result - double left = r2.hi + (r2.lo - err); - // Upper bound from the result - double right = r2.hi + (r2.lo + err); - - // Ziv's test if fast pass is accurate enough. - if (left == right) - return left; - - // Exact cases: - if (LIBC_UNLIKELY((x_u & 0x3FFFFF) == 0)) { - switch (x_u) { - case 0x4024000000000000: // x = 10.0 - return 1.0; - case 0x4059000000000000: // x = 10^2 - return 2.0; - case 0x408f400000000000: // x = 10^3 - return 3.0; - case 0x40c3880000000000: // x = 10^4 - return 4.0; - case 0x40f86a0000000000: // x = 10^5 - return 5.0; - case 0x412e848000000000: // x = 10^6 - return 6.0; - case 0x416312d000000000: // x = 10^7 - return 7.0; - case 0x4197d78400000000: // x = 10^8 - return 8.0; - case 0x41cdcd6500000000: // x = 10^9 - return 9.0; - case 0x4202a05f20000000: // x = 10^10 - return 10.0; - case 0x42374876e8000000: // x = 10^11 - return 11.0; - case 0x426d1a94a2000000: // x = 10^12 - return 12.0; - case 0x42a2309ce5400000: // x = 10^13 - return 13.0; - } - } else { - switch (x_u) { - case 0x42d6bcc41e900000: // x = 10^14 - return 14.0; - case 0x430c6bf526340000: // x = 10^15 - return 15.0; - case 0x4341c37937e08000: // x = 10^16 - return 16.0; - case 0x4376345785d8a000: // x = 10^17 - return 17.0; - case 0x43abc16d674ec800: // x = 10^18 - return 18.0; - case 0x43e158e460913d00: // x = 10^19 - return 19.0; - case 0x4415af1d78b58c40: // x = 10^20 - return 20.0; - case 0x444b1ae4d6e2ef50: // x = 10^21 - return 21.0; - case 0x4480f0cf064dd592: // x = 10^22 - return 22.0; - } - } - - return log10_accurate(x_e, index, u); -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS -} +LLVM_LIBC_FUNCTION(double, log10, (double x)) { return math::log10(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/log1p.cpp b/libc/src/math/generic/log1p.cpp index ddac3c2..f4179a6 100644 --- a/libc/src/math/generic/log1p.cpp +++ b/libc/src/math/generic/log1p.cpp @@ -7,1057 +7,9 @@ //===----------------------------------------------------------------------===// #include "src/math/log1p.h" -#include "src/__support/FPUtil/FEnvImpl.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/PolyEval.h" -#include "src/__support/FPUtil/double_double.h" -#include "src/__support/FPUtil/dyadic_float.h" -#include "src/__support/FPUtil/multiply_add.h" -#include "src/__support/common.h" -#include "src/__support/integer_literals.h" -#include "src/__support/macros/config.h" -#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY - -#include "src/__support/math/common_constants.h" +#include "src/__support/math/log1p.h" namespace LIBC_NAMESPACE_DECL { - -// 128-bit precision dyadic floating point numbers. -using Float128 = typename fputil::DyadicFloat<128>; - -using LIBC_NAMESPACE::operator""_u128; - -namespace { - -using namespace common_constants_internal; - -// R1[i] = 2^-8 * nearestint( 2^8 / (1 + i * 2^-7) ) -constexpr double R1[129] = { - 0x1p0, 0x1.fcp-1, 0x1.f8p-1, 0x1.f4p-1, 0x1.fp-1, 0x1.ecp-1, 0x1.eap-1, - 0x1.e6p-1, 0x1.e2p-1, 0x1.dep-1, 0x1.dap-1, 0x1.d8p-1, 0x1.d4p-1, 0x1.dp-1, - 0x1.cep-1, 0x1.cap-1, 0x1.c8p-1, 0x1.c4p-1, 0x1.cp-1, 0x1.bep-1, 0x1.bap-1, - 0x1.b8p-1, 0x1.b4p-1, 0x1.b2p-1, 0x1.bp-1, 0x1.acp-1, 0x1.aap-1, 0x1.a6p-1, - 0x1.a4p-1, 0x1.a2p-1, 0x1.9ep-1, 0x1.9cp-1, 0x1.9ap-1, 0x1.98p-1, 0x1.94p-1, - 0x1.92p-1, 0x1.9p-1, 0x1.8ep-1, 0x1.8ap-1, 0x1.88p-1, 0x1.86p-1, 0x1.84p-1, - 0x1.82p-1, 0x1.8p-1, 0x1.7ep-1, 0x1.7ap-1, 0x1.78p-1, 0x1.76p-1, 0x1.74p-1, - 0x1.72p-1, 0x1.7p-1, 0x1.6ep-1, 0x1.6cp-1, 0x1.6ap-1, 0x1.68p-1, 0x1.66p-1, - 0x1.64p-1, 0x1.62p-1, 0x1.6p-1, 0x1.5ep-1, 0x1.5cp-1, 0x1.5ap-1, 0x1.58p-1, - 0x1.58p-1, 0x1.56p-1, 0x1.54p-1, 0x1.52p-1, 0x1.5p-1, 0x1.4ep-1, 0x1.4cp-1, - 0x1.4ap-1, 0x1.4ap-1, 0x1.48p-1, 0x1.46p-1, 0x1.44p-1, 0x1.42p-1, 0x1.42p-1, - 0x1.4p-1, 0x1.3ep-1, 0x1.3cp-1, 0x1.3cp-1, 0x1.3ap-1, 0x1.38p-1, 0x1.36p-1, - 0x1.36p-1, 0x1.34p-1, 0x1.32p-1, 0x1.3p-1, 0x1.3p-1, 0x1.2ep-1, 0x1.2cp-1, - 0x1.2cp-1, 0x1.2ap-1, 0x1.28p-1, 0x1.28p-1, 0x1.26p-1, 0x1.24p-1, 0x1.24p-1, - 0x1.22p-1, 0x1.2p-1, 0x1.2p-1, 0x1.1ep-1, 0x1.1cp-1, 0x1.1cp-1, 0x1.1ap-1, - 0x1.1ap-1, 0x1.18p-1, 0x1.16p-1, 0x1.16p-1, 0x1.14p-1, 0x1.14p-1, 0x1.12p-1, - 0x1.12p-1, 0x1.1p-1, 0x1.0ep-1, 0x1.0ep-1, 0x1.0cp-1, 0x1.0cp-1, 0x1.0ap-1, - 0x1.0ap-1, 0x1.08p-1, 0x1.08p-1, 0x1.06p-1, 0x1.06p-1, 0x1.04p-1, 0x1.04p-1, - 0x1.02p-1, 0x1.02p-1, 0x1p-1, -}; - -// Extra constants for exact range reduction when FMA instructions are not -// available: -// r * c - 1 for r = 2^-8 * nearestint( 2^8 / (1 + i * 2^-7)) -// and c = 1 + i * 2^-7 -// with i = 0..128. -[[maybe_unused]] constexpr double RCM1[129] = { - 0.0, -0x1p-14, -0x1p-12, -0x1.2p-11, -0x1p-10, -0x1.9p-10, - 0x1.fp-10, 0x1.28p-10, 0x1p-12, -0x1.9p-11, -0x1.fp-10, 0x1.2p-10, - -0x1p-12, -0x1.cp-10, 0x1.1p-10, -0x1.5p-11, 0x1p-9, 0x1p-14, - -0x1p-9, 0x1.ap-12, -0x1.ep-10, 0x1.8p-12, -0x1.1p-9, -0x1p-15, - 0x1p-9, -0x1.ap-11, 0x1.1p-10, -0x1.f8p-10, -0x1p-12, 0x1.68p-10, - -0x1.fp-10, -0x1.cp-12, 0x1p-10, 0x1.3p-9, -0x1.6p-10, -0x1.4p-13, - 0x1p-10, 0x1.0cp-9, -0x1.08p-9, -0x1.2p-10, -0x1p-12, 0x1.2p-11, - 0x1.5p-10, 0x1p-9, 0x1.5p-9, -0x1.1cp-9, -0x1.cp-10, -0x1.58p-10, - -0x1p-10, -0x1.7p-11, -0x1p-11, -0x1.6p-12, -0x1p-12, -0x1.cp-13, - -0x1p-12, -0x1.6p-12, -0x1p-11, -0x1.7p-11, -0x1p-10, -0x1.58p-10, - -0x1.cp-10, -0x1.1cp-9, -0x1.6p-9, 0x1.5p-9, 0x1p-9, 0x1.5p-10, - 0x1.2p-11, -0x1p-12, -0x1.2p-10, -0x1.08p-9, -0x1.88p-9, 0x1.0cp-9, - 0x1p-10, -0x1.4p-13, -0x1.6p-10, -0x1.54p-9, 0x1.3p-9, 0x1p-10, - -0x1.cp-12, -0x1.fp-10, 0x1.8p-9, 0x1.68p-10, -0x1p-12, -0x1.f8p-10, - 0x1.7p-9, 0x1.1p-10, -0x1.ap-11, -0x1.6p-9, 0x1p-9, -0x1p-15, - -0x1.1p-9, 0x1.48p-9, 0x1.8p-12, -0x1.ep-10, 0x1.6p-9, 0x1.ap-12, - -0x1p-9, 0x1.48p-9, 0x1p-14, -0x1.4p-9, 0x1p-9, -0x1.5p-11, - -0x1.bp-9, 0x1.1p-10, -0x1.cp-10, 0x1.54p-9, -0x1p-12, -0x1.9cp-9, - 0x1.2p-10, -0x1.fp-10, 0x1.3p-9, -0x1.9p-11, 0x1.cp-9, 0x1p-12, - -0x1.88p-9, 0x1.28p-10, -0x1.2p-9, 0x1.fp-10, -0x1.9p-10, 0x1.4cp-9, - -0x1p-10, 0x1.9p-9, -0x1.2p-11, 0x1.c4p-9, -0x1p-12, 0x1.e8p-9, - -0x1p-14, 0x1.fcp-9, 0.0, -}; - -// Generated by Sollya with: -// for i from 0 to 128 do { -// r = 2^-8 * nearestint( 2^8 / (1 + i*2^-7) ); -// b = nearestint(log(r)*2^43) * 2^-43; -// c = round(log(r) - b, D, RN); -// print("{", -c, ",", -b, "},"); -// }; -// We replace LOG_R1_DD[128] with log(1.0) == 0.0 -alignas(16) constexpr fputil::DoubleDouble LOG_R1_DD[129] = { - {0.0, 0.0}, - {-0x1.0c76b999d2be8p-46, 0x1.010157589p-7}, - {-0x1.3dc5b06e2f7d2p-45, 0x1.0205658938p-6}, - {-0x1.aa0ba325a0c34p-45, 0x1.8492528c9p-6}, - {0x1.111c05cf1d753p-47, 0x1.0415d89e74p-5}, - {-0x1.c167375bdfd28p-45, 0x1.466aed42ep-5}, - {-0x1.29efbec19afa2p-47, 0x1.67c94f2d4cp-5}, - {0x1.0fc1a353bb42ep-45, 0x1.aaef2d0fbp-5}, - {-0x1.e113e4fc93b7bp-47, 0x1.eea31c006cp-5}, - {-0x1.5325d560d9e9bp-45, 0x1.1973bd1466p-4}, - {0x1.cc85ea5db4ed7p-45, 0x1.3bdf5a7d1ep-4}, - {-0x1.53a2582f4e1efp-48, 0x1.4d3115d208p-4}, - {0x1.c1e8da99ded32p-49, 0x1.700d30aeacp-4}, - {0x1.3115c3abd47dap-45, 0x1.9335e5d594p-4}, - {-0x1.e42b6b94407c8p-47, 0x1.a4e7640b1cp-4}, - {0x1.646d1c65aacd3p-45, 0x1.c885801bc4p-4}, - {0x1.a89401fa71733p-46, 0x1.da72763844p-4}, - {-0x1.534d64fa10afdp-45, 0x1.fe89139dbep-4}, - {0x1.1ef78ce2d07f2p-45, 0x1.1178e8227ep-3}, - {0x1.ca78e44389934p-45, 0x1.1aa2b7e23fp-3}, - {0x1.39d6ccb81b4a1p-47, 0x1.2d1610c868p-3}, - {0x1.62fa8234b7289p-51, 0x1.365fcb0159p-3}, - {0x1.5837954fdb678p-45, 0x1.4913d8333bp-3}, - {0x1.633e8e5697dc7p-45, 0x1.527e5e4a1bp-3}, - {-0x1.27023eb68981cp-46, 0x1.5bf406b544p-3}, - {-0x1.5118de59c21e1p-45, 0x1.6f0128b757p-3}, - {-0x1.c661070914305p-46, 0x1.7898d85445p-3}, - {-0x1.73d54aae92cd1p-47, 0x1.8beafeb39p-3}, - {0x1.7f22858a0ff6fp-47, 0x1.95a5adcf7p-3}, - {0x1.9904d6865817ap-45, 0x1.9f6c407089p-3}, - {-0x1.c358d4eace1aap-47, 0x1.b31d8575bdp-3}, - {-0x1.d4bc4595412b6p-45, 0x1.bd087383bep-3}, - {-0x1.1ec72c5962bd2p-48, 0x1.c6ffbc6f01p-3}, - {-0x1.84a7e75b6f6e4p-47, 0x1.d1037f2656p-3}, - {0x1.212276041f43p-51, 0x1.e530effe71p-3}, - {-0x1.a211565bb8e11p-51, 0x1.ef5ade4ddp-3}, - {0x1.bcbecca0cdf3p-46, 0x1.f991c6cb3bp-3}, - {-0x1.6f08c1485e94ap-46, 0x1.01eae5626c8p-2}, - {0x1.7188b163ceae9p-45, 0x1.0c42d67616p-2}, - {-0x1.c210e63a5f01cp-45, 0x1.1178e8227e8p-2}, - {0x1.b9acdf7a51681p-45, 0x1.16b5ccbacf8p-2}, - {0x1.ca6ed5147bdb7p-45, 0x1.1bf99635a68p-2}, - {0x1.a87deba46baeap-47, 0x1.214456d0eb8p-2}, - {0x1.c93c1df5bb3b6p-45, 0x1.269621134d8p-2}, - {0x1.a9cfa4a5004f4p-45, 0x1.2bef07cdc9p-2}, - {0x1.16ecdb0f177c8p-46, 0x1.36b6776be1p-2}, - {0x1.83b54b606bd5cp-46, 0x1.3c25277333p-2}, - {0x1.8e436ec90e09dp-47, 0x1.419b423d5e8p-2}, - {-0x1.f27ce0967d675p-45, 0x1.4718dc271c8p-2}, - {-0x1.e20891b0ad8a4p-45, 0x1.4c9e09e173p-2}, - {0x1.ebe708164c759p-45, 0x1.522ae0738ap-2}, - {0x1.fadedee5d40efp-46, 0x1.57bf753c8dp-2}, - {-0x1.a0b2a08a465dcp-47, 0x1.5d5bddf596p-2}, - {-0x1.db623e731aep-45, 0x1.630030b3abp-2}, - {0x1.0a0d32756ebap-45, 0x1.68ac83e9c68p-2}, - {0x1.721657c222d87p-46, 0x1.6e60ee6af18p-2}, - {0x1.d8b0949dc60b3p-45, 0x1.741d876c678p-2}, - {0x1.9ec7d2efd1778p-45, 0x1.79e26687cf8p-2}, - {-0x1.72090c812566ap-45, 0x1.7fafa3bd818p-2}, - {0x1.fd56f3333778ap-45, 0x1.85855776dc8p-2}, - {-0x1.05ae1e5e7047p-45, 0x1.8b639a88b3p-2}, - {-0x1.766b52ee6307dp-46, 0x1.914a8635bf8p-2}, - {-0x1.52313a502d9fp-46, 0x1.973a3431358p-2}, - {-0x1.52313a502d9fp-46, 0x1.973a3431358p-2}, - {-0x1.6279e10d0c0bp-45, 0x1.9d32bea15fp-2}, - {0x1.3c6457f9d79f5p-45, 0x1.a33440224f8p-2}, - {0x1.e36f2bea77a5dp-46, 0x1.a93ed3c8ad8p-2}, - {-0x1.17cc552774458p-45, 0x1.af5295248dp-2}, - {0x1.095252d841995p-46, 0x1.b56fa044628p-2}, - {0x1.7d85bf40a666dp-45, 0x1.bb9611b80ep-2}, - {0x1.cec807fe8e18p-45, 0x1.c1c60693fap-2}, - {0x1.cec807fe8e18p-45, 0x1.c1c60693fap-2}, - {-0x1.9b6ddc15249aep-45, 0x1.c7ff9c74558p-2}, - {-0x1.797c33ec7a6bp-47, 0x1.ce42f180648p-2}, - {0x1.35bafe9a767a8p-45, 0x1.d490246def8p-2}, - {-0x1.ea42d60dc616ap-46, 0x1.dae75484c98p-2}, - {-0x1.ea42d60dc616ap-46, 0x1.dae75484c98p-2}, - {-0x1.326b207322938p-46, 0x1.e148a1a2728p-2}, - {-0x1.465505372bd08p-45, 0x1.e7b42c3ddbp-2}, - {0x1.f27f45a470251p-45, 0x1.ee2a156b41p-2}, - {0x1.f27f45a470251p-45, 0x1.ee2a156b41p-2}, - {0x1.2cde56f014a8bp-46, 0x1.f4aa7ee0318p-2}, - {0x1.085fa3c164935p-47, 0x1.fb358af7a48p-2}, - {-0x1.53ba3b1727b1cp-47, 0x1.00e5ae5b208p-1}, - {-0x1.53ba3b1727b1cp-47, 0x1.00e5ae5b208p-1}, - {-0x1.4c45fe79539ep-47, 0x1.04360be7604p-1}, - {0x1.6812241edf5fdp-45, 0x1.078bf0533c4p-1}, - {0x1.f486b887e7e27p-46, 0x1.0ae76e2d054p-1}, - {0x1.f486b887e7e27p-46, 0x1.0ae76e2d054p-1}, - {0x1.c299807801742p-46, 0x1.0e4898611ccp-1}, - {-0x1.58647bb9ddcb2p-45, 0x1.11af823c75cp-1}, - {-0x1.58647bb9ddcb2p-45, 0x1.11af823c75cp-1}, - {-0x1.edd97a293ae49p-45, 0x1.151c3f6f298p-1}, - {0x1.4cc4ef8ab465p-46, 0x1.188ee40f23cp-1}, - {0x1.4cc4ef8ab465p-46, 0x1.188ee40f23cp-1}, - {0x1.cacdeed70e667p-51, 0x1.1c07849ae6p-1}, - {-0x1.a7242c9fe81d3p-45, 0x1.1f8635fc618p-1}, - {-0x1.a7242c9fe81d3p-45, 0x1.1f8635fc618p-1}, - {0x1.2fc066e48667bp-46, 0x1.230b0d8bebcp-1}, - {-0x1.b61f10522625p-47, 0x1.269621134dcp-1}, - {-0x1.b61f10522625p-47, 0x1.269621134dcp-1}, - {0x1.06d2be797882dp-45, 0x1.2a2786d0ecp-1}, - {-0x1.7a6e507b9dc11p-46, 0x1.2dbf557b0ep-1}, - {-0x1.7a6e507b9dc11p-46, 0x1.2dbf557b0ep-1}, - {-0x1.74e93c5a0ed9cp-45, 0x1.315da443408p-1}, - {-0x1.74e93c5a0ed9cp-45, 0x1.315da443408p-1}, - {0x1.0b83f9527e6acp-46, 0x1.35028ad9d8cp-1}, - {-0x1.18b7abb5569a4p-45, 0x1.38ae2171978p-1}, - {-0x1.18b7abb5569a4p-45, 0x1.38ae2171978p-1}, - {-0x1.2b7367cfe13c2p-47, 0x1.3c6080c36cp-1}, - {-0x1.2b7367cfe13c2p-47, 0x1.3c6080c36cp-1}, - {-0x1.6ce7930f0c74cp-45, 0x1.4019c2125ccp-1}, - {-0x1.6ce7930f0c74cp-45, 0x1.4019c2125ccp-1}, - {-0x1.d984f481051f7p-48, 0x1.43d9ff2f924p-1}, - {-0x1.2cb6af94d60aap-45, 0x1.47a1527e8a4p-1}, - {-0x1.2cb6af94d60aap-45, 0x1.47a1527e8a4p-1}, - {0x1.f7115ed4c541cp-49, 0x1.4b6fd6f970cp-1}, - {0x1.f7115ed4c541cp-49, 0x1.4b6fd6f970cp-1}, - {-0x1.e6c516d93b8fbp-45, 0x1.4f45a835a5p-1}, - {-0x1.e6c516d93b8fbp-45, 0x1.4f45a835a5p-1}, - {0x1.5ccc45d257531p-47, 0x1.5322e268678p-1}, - {0x1.5ccc45d257531p-47, 0x1.5322e268678p-1}, - {0x1.9980bff3303ddp-47, 0x1.5707a26bb8cp-1}, - {0x1.9980bff3303ddp-47, 0x1.5707a26bb8cp-1}, - {0x1.dfa63ac10c9fbp-45, 0x1.5af405c3648p-1}, - {0x1.dfa63ac10c9fbp-45, 0x1.5af405c3648p-1}, - {0x1.202380cda46bep-45, 0x1.5ee82aa2418p-1}, - {0x1.202380cda46bep-45, 0x1.5ee82aa2418p-1}, - {0.0, 0.0}, -}; - -// Degree-7 minimax polynomial log(1 + v) ~ v - v^2 / 2 + ... -// generated by Sollya with: -// > P = fpminimax(log(1 + x)/x, 6, [|1, 1, D...|], -// [-0x1.69000000000edp-8, 0x1.7f00000000081p-8]); -constexpr double P_COEFFS[6] = {-0x1p-1, - 0x1.5555555555166p-2, - -0x1.fffffffdb7746p-3, - 0x1.99999a8718a6p-3, - -0x1.555874ce8ce22p-3, - 0x1.24335555ddbe5p-3}; - -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS -// Extra errors from P is from using x^2 to reduce evaluation latency and -// directional rounding. -constexpr double P_ERR = 0x1.0p-49; - -// log(2) with 128-bit precision generated by SageMath with: -// def format_hex(value): -// l = hex(value)[2:] -// n = 8 -// x = [l[i:i + n] for i in range(0, len(l), n)] -// return "0x" + "'".join(x) + "_u128" -// (s, m, e) = RealField(128)(2).log().sign_mantissa_exponent(); -// print(format_hex(m)); -constexpr Float128 LOG_2(Sign::POS, /*exponent=*/-128, /*mantissa=*/ - 0xb17217f7'd1cf79ab'c9e3b398'03f2f6af_u128); - -// -log(r1) with 128-bit precision generated by SageMath with: -// -// for i in range(129): -// r = 2^-8 * round( 2^8 / (1 + i*2^(-7)) ); -// s, m, e = RealField(128)(r).log().sign_mantissa_exponent(); -// print("{Sign::POS,", e, ", format_hex(m), "},"); -constexpr Float128 LOG_R1[129] = { - {Sign::POS, 0, 0_u128}, - {Sign::POS, -134, 0x8080abac'46f38946'662d417c'ed007a46_u128}, - {Sign::POS, -133, 0x8102b2c4'9ac23a4f'91d082dc'e3ddcd38_u128}, - {Sign::POS, -133, 0xc2492946'4655f45c'da5f3cc0'b3251dbd_u128}, - {Sign::POS, -132, 0x820aec4f'3a222380'b9e3aea6'c444ef07_u128}, - {Sign::POS, -132, 0xa33576a1'6f1f4c64'521016bd'904dc968_u128}, - {Sign::POS, -132, 0xb3e4a796'a5dac208'27cca0bc'c06c2f92_u128}, - {Sign::POS, -132, 0xd5779687'd887e0d1'a9dda170'56e45ed5_u128}, - {Sign::POS, -132, 0xf7518e00'35c3dd83'606d8909'3278a939_u128}, - {Sign::POS, -131, 0x8cb9de8a'32ab368a'a7c98595'30a45153_u128}, - {Sign::POS, -131, 0x9defad3e'8f73217a'976d3b5b'45f6ca0b_u128}, - {Sign::POS, -131, 0xa6988ae9'03f562ed'3e858f08'597b3a69_u128}, - {Sign::POS, -131, 0xb8069857'560707a3'6a677b4c'8bec22e1_u128}, - {Sign::POS, -131, 0xc99af2ea'ca4c4570'eaf51f66'692844ba_u128}, - {Sign::POS, -131, 0xd273b205'8de1bd49'46bbf837'b4d320c6_u128}, - {Sign::POS, -131, 0xe442c00d'e2591b47'196ab34c'e0bccd12_u128}, - {Sign::POS, -131, 0xed393b1c'22351280'3f4e2e66'0317d55f_u128}, - {Sign::POS, -131, 0xff4489ce'deab2ca6'c17bd40d'8d9291ec_u128}, - {Sign::POS, -130, 0x88bc7411'3f23def1'9c5a0fe3'96f40f1e_u128}, - {Sign::POS, -130, 0x8d515bf1'1fb94f1c'88713268'840cbcc0_u128}, - {Sign::POS, -130, 0x968b0864'3409ceb6'65c0da50'6a088484_u128}, - {Sign::POS, -130, 0x9b2fe580'ac80b17d'411a5b94'4aca8708_u128}, - {Sign::POS, -130, 0xa489ec19'9dab06f2'a9fb6cf0'ecb411b7_u128}, - {Sign::POS, -130, 0xa93f2f25'0dac67d1'cad2fb8d'48054ae0_u128}, - {Sign::POS, -130, 0xadfa035a'a1ed8fdc'149767e4'10316d2c_u128}, - {Sign::POS, -130, 0xb780945b'ab55dce4'34c7bc3d'32750fde_u128}, - {Sign::POS, -130, 0xbc4c6c2a'226399ef'8f6ebcfb'2016a439_u128}, - {Sign::POS, -130, 0xc5f57f59'c7f46155'aa8b6997'a402bf30_u128}, - {Sign::POS, -130, 0xcad2d6e7'b80bf914'2c507fb7'a3d0bf6a_u128}, - {Sign::POS, -130, 0xcfb62038'44b3209a'd0cb02f3'3f79c16c_u128}, - {Sign::POS, -130, 0xd98ec2ba'de71e539'58a98f2a'd65bee9b_u128}, - {Sign::POS, -130, 0xde8439c1'dec56877'4d57da94'5b5d0aaa_u128}, - {Sign::POS, -130, 0xe37fde37'807b84e3'4e9a750b'6b68781d_u128}, - {Sign::POS, -130, 0xe881bf93'2af3dac0'c524848e'3443e040_u128}, - {Sign::POS, -130, 0xf29877ff'38809091'3b020fa1'820c9492_u128}, - {Sign::POS, -130, 0xf7ad6f26'e7ff2ef7'54d2238f'75f969b1_u128}, - {Sign::POS, -130, 0xfcc8e365'9d9bcbec'ca0cdf30'1431b60f_u128}, - {Sign::POS, -129, 0x80f572b1'363487b9'f5bd0b5b'3479d5f4_u128}, - {Sign::POS, -129, 0x86216b3b'0b17188b'163ceae8'8f720f1e_u128}, - {Sign::POS, -129, 0x88bc7411'3f23def1'9c5a0fe3'96f40f1e_u128}, - {Sign::POS, -129, 0x8b5ae65d'67db9acd'f7a51681'26a58b9a_u128}, - {Sign::POS, -129, 0x8dfccb1a'd35ca6ed'5147bdb6'ddcaf59c_u128}, - {Sign::POS, -129, 0x90a22b68'75c6a1f7'ae91aeba'609c8877_u128}, - {Sign::POS, -129, 0x934b1089'a6dc93c1'df5bb3b6'0554e152_u128}, - {Sign::POS, -129, 0x95f783e6'e49a9cfa'4a5004f3'ef063313_u128}, - {Sign::POS, -129, 0x9b5b3bb5'f088b766'd878bbe3'd392be25_u128}, - {Sign::POS, -129, 0x9e1293b9'998c1daa'5b035eae'273a855f_u128}, - {Sign::POS, -129, 0xa0cda11e'af46390d'bb243827'3918db7e_u128}, - {Sign::POS, -129, 0xa38c6e13'8e20d831'f698298a'dddd7f32_u128}, - {Sign::POS, -129, 0xa64f04f0'b961df76'e4f5275c'2d15c21f_u128}, - {Sign::POS, -129, 0xa9157039'c51ebe70'8164c759'686a2209_u128}, - {Sign::POS, -129, 0xabdfba9e'468fd6f6'f72ea077'49ce6bd3_u128}, - {Sign::POS, -129, 0xaeadeefa'caf97d35'7dd6e688'ebb13b03_u128}, - {Sign::POS, -129, 0xb1801859'd56249dc'18ce51ff'f99479cd_u128}, - {Sign::POS, -129, 0xb45641f4'e350a0d3'2756eba0'0bc33978_u128}, - {Sign::POS, -129, 0xb7307735'78cb90b2'be1116c3'466beb6d_u128}, - {Sign::POS, -129, 0xba0ec3b6'33dd8b09'49dc60b2'b059a60b_u128}, - {Sign::POS, -129, 0xbcf13343'e7d9ec7d'2efd1778'1bb3afec_u128}, - {Sign::POS, -129, 0xbfd7d1de'c0a8df6f'37eda996'244bccb0_u128}, - {Sign::POS, -129, 0xc2c2abbb'6e5fd56f'33337789'd592e296_u128}, - {Sign::POS, -129, 0xc5b1cd44'596fa51e'1a18fb8f'9f9ef280_u128}, - {Sign::POS, -129, 0xc8a5431a'dfb44ca5'688ce7c1'a75e341a_u128}, - {Sign::POS, -129, 0xcb9d1a18'9ab56e76'2d7e9307'c70c0668_u128}, - {Sign::POS, -129, 0xcb9d1a18'9ab56e76'2d7e9307'c70c0668_u128}, - {Sign::POS, -129, 0xce995f50'af69d861'ef2f3f4f'861ad6a9_u128}, - {Sign::POS, -129, 0xd19a2011'27d3c645'7f9d79f5'1dcc7301_u128}, - {Sign::POS, -129, 0xd49f69e4'56cf1b79'5f53bd2e'406e66e7_u128}, - {Sign::POS, -129, 0xd7a94a92'466e833a'ad88bba7'd0cee8e0_u128}, - {Sign::POS, -129, 0xdab7d022'31484a92'96c20cca'6efe2ac5_u128}, - {Sign::POS, -129, 0xddcb08dc'0717d85b'f40a666c'87842843_u128}, - {Sign::POS, -129, 0xe0e30349'fd1cec80'7fe8e180'2aba24d6_u128}, - {Sign::POS, -129, 0xe0e30349'fd1cec80'7fe8e180'2aba24d6_u128}, - {Sign::POS, -129, 0xe3ffce3a'2aa64922'3eadb651'b49ac53a_u128}, - {Sign::POS, -129, 0xe72178c0'323a1a0f'304e1653'e71d9973_u128}, - {Sign::POS, -129, 0xea481236'f7d35baf'e9a767a8'0d6d97e8_u128}, - {Sign::POS, -129, 0xed73aa42'64b0ade9'4f91cf4b'33e42998_u128}, - {Sign::POS, -129, 0xed73aa42'64b0ade9'4f91cf4b'33e42998_u128}, - {Sign::POS, -129, 0xf0a450d1'39366ca6'fc66eb64'08ff6433_u128}, - {Sign::POS, -129, 0xf3da161e'ed6b9aaf'ac8d42f7'8d3e65d3_u128}, - {Sign::POS, -129, 0xf7150ab5'a09f27f4'5a470250'd40ebe90_u128}, - {Sign::POS, -129, 0xf7150ab5'a09f27f4'5a470250'd40ebe90_u128}, - {Sign::POS, -129, 0xfa553f70'18c966f2'b780a545'a1b54dcf_u128}, - {Sign::POS, -129, 0xfd9ac57b'd244217e'8f05924d'258c14c5_u128}, - {Sign::POS, -128, 0x8072d72d'903d588b'89d1b09c'70c4010a_u128}, - {Sign::POS, -128, 0x8072d72d'903d588b'89d1b09c'70c4010a_u128}, - {Sign::POS, -128, 0x821b05f3'b01d6774'030d58c3'f7e2ea1f_u128}, - {Sign::POS, -128, 0x83c5f829'9e2b4091'20f6fafe'8fbb68b9_u128}, - {Sign::POS, -128, 0x8573b716'82a7d21a'e21f9f89'c1ab80b2_u128}, - {Sign::POS, -128, 0x8573b716'82a7d21a'e21f9f89'c1ab80b2_u128}, - {Sign::POS, -128, 0x87244c30'8e670a66'01e005d0'6dbfa8f8_u128}, - {Sign::POS, -128, 0x88d7c11e'3ad53cdc'223111a7'07b6de2c_u128}, - {Sign::POS, -128, 0x88d7c11e'3ad53cdc'223111a7'07b6de2c_u128}, - {Sign::POS, -128, 0x8a8e1fb7'94b09134'2eb628db'a173c82d_u128}, - {Sign::POS, -128, 0x8c477207'91e53313'be2ad194'15fe25a5_u128}, - {Sign::POS, -128, 0x8c477207'91e53313'be2ad194'15fe25a5_u128}, - {Sign::POS, -128, 0x8e03c24d'73003959'bddae1cc'ce247838_u128}, - {Sign::POS, -128, 0x8fc31afe'30b2c6de'9b00bf16'7e95da67_u128}, - {Sign::POS, -128, 0x8fc31afe'30b2c6de'9b00bf16'7e95da67_u128}, - {Sign::POS, -128, 0x918586c5'f5e4bf01'9b92199e'd1a4bab1_u128}, - {Sign::POS, -128, 0x934b1089'a6dc93c1'df5bb3b6'0554e152_u128}, - {Sign::POS, -128, 0x934b1089'a6dc93c1'df5bb3b6'0554e152_u128}, - {Sign::POS, -128, 0x9513c368'76083695'f3cbc416'a2418012_u128}, - {Sign::POS, -128, 0x96dfaabd'86fa1646'be1188fb'c94e2f15_u128}, - {Sign::POS, -128, 0x96dfaabd'86fa1646'be1188fb'c94e2f15_u128}, - {Sign::POS, -128, 0x98aed221'a03458b6'1d2f8932'1647b358_u128}, - {Sign::POS, -128, 0x98aed221'a03458b6'1d2f8932'1647b358_u128}, - {Sign::POS, -128, 0x9a81456c'ec642e0f'e549f9aa'ea3cb5e1_u128}, - {Sign::POS, -128, 0x9c5710b8'cbb73a42'a2554b2d'd4619e63_u128}, - {Sign::POS, -128, 0x9c5710b8'cbb73a42'a2554b2d'd4619e63_u128}, - {Sign::POS, -128, 0x9e304061'b5fda919'30603d87'b6df81ad_u128}, - {Sign::POS, -128, 0x9e304061'b5fda919'30603d87'b6df81ad_u128}, - {Sign::POS, -128, 0xa00ce109'2e5498c3'67879c5a'30cd1242_u128}, - {Sign::POS, -128, 0xa00ce109'2e5498c3'67879c5a'30cd1242_u128}, - {Sign::POS, -128, 0xa1ecff97'c91e267b'0b7efae0'8e597e16_u128}, - {Sign::POS, -128, 0xa3d0a93f'45169a4a'83594fab'088c0d65_u128}, - {Sign::POS, -128, 0xa3d0a93f'45169a4a'83594fab'088c0d65_u128}, - {Sign::POS, -128, 0xa5b7eb7c'b860fb88'af6a62a0'dec6e073_u128}, - {Sign::POS, -128, 0xa5b7eb7c'b860fb88'af6a62a0'dec6e073_u128}, - {Sign::POS, -128, 0xa7a2d41a'd270c9d7'49362382'a768847a_u128}, - {Sign::POS, -128, 0xa7a2d41a'd270c9d7'49362382'a768847a_u128}, - {Sign::POS, -128, 0xa9917134'33c2b998'8ba4aea6'14d05701_u128}, - {Sign::POS, -128, 0xa9917134'33c2b998'8ba4aea6'14d05701_u128}, - {Sign::POS, -128, 0xab83d135'dc633301'7fe6607b'a902ef3c_u128}, - {Sign::POS, -128, 0xab83d135'dc633301'7fe6607b'a902ef3c_u128}, - {Sign::POS, -128, 0xad7a02e1'b24efd31'd60864fd'949b4bd3_u128}, - {Sign::POS, -128, 0xad7a02e1'b24efd31'd60864fd'949b4bd3_u128}, - {Sign::POS, -128, 0xaf741551'20c9011c'066d235e'e63073dd_u128}, - {Sign::POS, -128, 0xaf741551'20c9011c'066d235e'e63073dd_u128}, - {Sign::POS, 0, 0_u128}, -}; - -// Logarithm range reduction - Step 2: -// s(k) = 2^-18 round( 2^18 / (1 + k*2^-14) ) - 1 for k = -91 .. 96 -// Output range: -// [-0x1.1037c00000040271p-15 , 0x1.108480000008096cp-15] -constexpr double S2[198] = { - 0x1.6ep-8, 0x1.6ap-8, 0x1.66p-8, 0x1.62p-8, 0x1.5dcp-8, - 0x1.59cp-8, 0x1.55cp-8, 0x1.51cp-8, 0x1.4dcp-8, 0x1.49cp-8, - 0x1.458p-8, 0x1.418p-8, 0x1.3d8p-8, 0x1.398p-8, 0x1.358p-8, - 0x1.318p-8, 0x1.2d8p-8, 0x1.294p-8, 0x1.254p-8, 0x1.214p-8, - 0x1.1d4p-8, 0x1.194p-8, 0x1.154p-8, 0x1.114p-8, 0x1.0dp-8, - 0x1.09p-8, 0x1.05p-8, 0x1.01p-8, 0x1.fap-9, 0x1.f2p-9, - 0x1.eap-9, 0x1.e2p-9, 0x1.d98p-9, 0x1.d18p-9, 0x1.c98p-9, - 0x1.c18p-9, 0x1.b98p-9, 0x1.b18p-9, 0x1.a98p-9, 0x1.a18p-9, - 0x1.998p-9, 0x1.91p-9, 0x1.89p-9, 0x1.81p-9, 0x1.79p-9, - 0x1.71p-9, 0x1.69p-9, 0x1.61p-9, 0x1.59p-9, 0x1.51p-9, - 0x1.49p-9, 0x1.41p-9, 0x1.388p-9, 0x1.308p-9, 0x1.288p-9, - 0x1.208p-9, 0x1.188p-9, 0x1.108p-9, 0x1.088p-9, 0x1.008p-9, - 0x1.f1p-10, 0x1.e1p-10, 0x1.d1p-10, 0x1.c1p-10, 0x1.b1p-10, - 0x1.a1p-10, 0x1.91p-10, 0x1.81p-10, 0x1.71p-10, 0x1.6p-10, - 0x1.5p-10, 0x1.4p-10, 0x1.3p-10, 0x1.2p-10, 0x1.1p-10, - 0x1p-10, 0x1.ep-11, 0x1.cp-11, 0x1.ap-11, 0x1.8p-11, - 0x1.6p-11, 0x1.4p-11, 0x1.2p-11, 0x1p-11, 0x1.cp-12, - 0x1.8p-12, 0x1.4p-12, 0x1p-12, 0x1.8p-13, 0x1p-13, - 0x1p-14, 0.0, -0x1p-14, -0x1p-13, -0x1.8p-13, - -0x1p-12, -0x1.4p-12, -0x1.8p-12, -0x1.cp-12, -0x1p-11, - -0x1.2p-11, -0x1.4p-11, -0x1.6p-11, -0x1.8p-11, -0x1.ap-11, - -0x1.cp-11, -0x1.ep-11, -0x1p-10, -0x1.1p-10, -0x1.2p-10, - -0x1.3p-10, -0x1.4p-10, -0x1.5p-10, -0x1.6p-10, -0x1.6fp-10, - -0x1.7fp-10, -0x1.8fp-10, -0x1.9fp-10, -0x1.afp-10, -0x1.bfp-10, - -0x1.cfp-10, -0x1.dfp-10, -0x1.efp-10, -0x1.ffp-10, -0x1.078p-9, - -0x1.0f8p-9, -0x1.178p-9, -0x1.1f8p-9, -0x1.278p-9, -0x1.2f8p-9, - -0x1.378p-9, -0x1.3fp-9, -0x1.47p-9, -0x1.4fp-9, -0x1.57p-9, - -0x1.5fp-9, -0x1.67p-9, -0x1.6fp-9, -0x1.77p-9, -0x1.7fp-9, - -0x1.87p-9, -0x1.8fp-9, -0x1.968p-9, -0x1.9e8p-9, -0x1.a68p-9, - -0x1.ae8p-9, -0x1.b68p-9, -0x1.be8p-9, -0x1.c68p-9, -0x1.ce8p-9, - -0x1.d68p-9, -0x1.dep-9, -0x1.e6p-9, -0x1.eep-9, -0x1.f6p-9, - -0x1.fep-9, -0x1.03p-8, -0x1.07p-8, -0x1.0bp-8, -0x1.0fp-8, - -0x1.12cp-8, -0x1.16cp-8, -0x1.1acp-8, -0x1.1ecp-8, -0x1.22cp-8, - -0x1.26cp-8, -0x1.2acp-8, -0x1.2e8p-8, -0x1.328p-8, -0x1.368p-8, - -0x1.3a8p-8, -0x1.3e8p-8, -0x1.428p-8, -0x1.464p-8, -0x1.4a4p-8, - -0x1.4e4p-8, -0x1.524p-8, -0x1.564p-8, -0x1.5a4p-8, -0x1.5ep-8, - -0x1.62p-8, -0x1.66p-8, -0x1.6ap-8, -0x1.6ep-8, -0x1.72p-8, - -0x1.75cp-8, -0x1.79cp-8, -0x1.7dcp-8, -}; - -// -log(r) for the second step, generated by SageMath with: -// -// for i in range(-91, 97): -// r = 2^-18 * round( 2^18 / (1 + i*2^(-14)) ); -// s, m, e = RealField(128)(r).log().sign_mantissa_exponent(); -// print("{Sign::POS," if (s == -1) else "{Sign::NEG,", e, ", -// format_hex(m), "},"); -constexpr Float128 LOG_R2[198] = { - {Sign::NEG, -135, 0xb67dab2a'1a5742a4'a0e061c5'f7431c5e_u128}, - {Sign::NEG, -135, 0xb4807f24'af682939'5d5bfe7b'969ed6ec_u128}, - {Sign::NEG, -135, 0xb2834b35'b4d54d5f'4d08702d'dfabc23f_u128}, - {Sign::NEG, -135, 0xb0860f5c'eba9be95'd4d36650'8b9953df_u128}, - {Sign::NEG, -135, 0xae68f71a'a09e8847'ac18a289'f8f214a9_u128}, - {Sign::NEG, -135, 0xac6baaee'd676e8f1'd5b42054'abb88c45_u128}, - {Sign::NEG, -135, 0xaa6e56d8'7cd632d6'09809d58'ee484964_u128}, - {Sign::NEG, -135, 0xa870fad7'54bb8791'b9e6fc7c'72f06d73_u128}, - {Sign::NEG, -135, 0xa67396eb'1f231892'6f78d6d0'105c00e2_u128}, - {Sign::NEG, -135, 0xa4762b13'9d0626e7'028f7126'29209148_u128}, - {Sign::NEG, -135, 0xa258dfd1'0aedaa67'c98d898e'f172df02_u128}, - {Sign::NEG, -135, 0xa05b63a3'73e60a83'fcc37c3c'3062bfa1_u128}, - {Sign::NEG, -135, 0x9e5ddf89'cf42f501'3eb450db'05763c36_u128}, - {Sign::NEG, -135, 0x9c605383'ddf1b88c'7146a86f'd458b775_u128}, - {Sign::NEG, -135, 0x9a62bf91'60dcb286'c20a0c92'81474436_u128}, - {Sign::NEG, -135, 0x986523b2'18eb4ed6'cdc57316'ec4aebc3_u128}, - {Sign::NEG, -135, 0x96677fe5'c70207b9'c060dad7'4cef4273_u128}, - {Sign::NEG, -135, 0x9449f92d'2ff44633'ed8def1a'3e433499_u128}, - {Sign::NEG, -135, 0x924c4507'3220b5e0'3ce7a1f8'5c27b4fc_u128}, - {Sign::NEG, -135, 0x904e88f3'68fea63f'f2ca8934'49f7f2cb_u128}, - {Sign::NEG, -135, 0x8e50c4f1'956699ed'8d77d9fa'bd2853cf_u128}, - {Sign::NEG, -135, 0x8c52f901'782e20ec'93e828d7'5b58ded4_u128}, - {Sign::NEG, -135, 0x8a552522'd227d87a'9f9605b0'53c5acf0_u128}, - {Sign::NEG, -135, 0x88574955'64236ae0'62a14939'3bca7241_u128}, - {Sign::NEG, -135, 0x86398719'b66bac7c'aea6b56c'e89203d4_u128}, - {Sign::NEG, -135, 0x843b9aef'044e4dcc'0242bd86'd00609b2_u128}, - {Sign::NEG, -135, 0x823da6d4'c89c6927'daabf927'74bac84e_u128}, - {Sign::NEG, -135, 0x803faaca'c419abf2'a1c6f3fc'242ef8d0_u128}, - {Sign::NEG, -136, 0xfc834da1'6f0d9f57'a225ebc0'2e6d9dd4_u128}, - {Sign::NEG, -136, 0xf88735cc'c7433381'c33f6ad3'40ae18a9_u128}, - {Sign::NEG, -136, 0xf48b0e17'1249b6bc'70b2a4d3'8a242244_u128}, - {Sign::NEG, -136, 0xf08ed67f'd190e280'1d548190'48b811b0_u128}, - {Sign::NEG, -136, 0xec52ca07'ed95f236'9c21b650'afe9ede0_u128}, - {Sign::NEG, -136, 0xe85671ad'ecd28aac'935519c9'6d30e463_u128}, - {Sign::NEG, -136, 0xe45a0970'dc912ca7'ba88f6f2'e2672cfe_u128}, - {Sign::NEG, -136, 0xe05d9150'3e298bc8'0b1a8b84'657ae069_u128}, - {Sign::NEG, -136, 0xdc61094b'92ed70ef'ea3bff8d'197b20a1_u128}, - {Sign::NEG, -136, 0xd8647162'5c28b9e5'cdbb931d'6fecc249_u128}, - {Sign::NEG, -136, 0xd467c994'1b2158f5'd971d560'd5f00820_u128}, - {Sign::NEG, -136, 0xd06b11e0'51175493'75563561'244c090b_u128}, - {Sign::NEG, -136, 0xcc6e4a46'7f44c6fa'dc393c9a'3f3b380f_u128}, - {Sign::NEG, -136, 0xc831a4c6'f6fa709d'e6abe6e9'e4ee2096_u128}, - {Sign::NEG, -136, 0xc434bc61'24a0f16e'3ce3c822'8583a66e_u128}, - {Sign::NEG, -136, 0xc037c413'c61bfd93'b96a79f5'c5a4963a_u128}, - {Sign::NEG, -136, 0xbc3abbde'5c8d9bde'aaef2733'7008679f_u128}, - {Sign::NEG, -136, 0xb83da3c0'6911e509'a49a3fca'ddc8bc5a_u128}, - {Sign::NEG, -136, 0xb4407bb9'6cbf035a'e0254feb'785362fa_u128}, - {Sign::NEG, -136, 0xb04343c8'e8a53245'9893a4e2'5ab9dc95_u128}, - {Sign::NEG, -136, 0xac45fbee'5dcebe0b'5d8b0f40'a3708915_u128}, - {Sign::NEG, -136, 0xa848a429'4d40035d'5f4c11c2'c7a58c69_u128}, - {Sign::NEG, -136, 0xa44b3c79'37f76efd'b348cc5d'f706ffba_u128}, - {Sign::NEG, -136, 0xa04dc4dd'9eed7d60'9159f2c5'5a18befd_u128}, - {Sign::NEG, -136, 0x9c106456'3058bef3'bdfdee41'fe6a5a02_u128}, - {Sign::NEG, -136, 0x9812cbe3'46475a24'4580ddf8'9853254d_u128}, - {Sign::NEG, -136, 0x94152383'53489ffb'ac75e10d'61fc3ee8_u128}, - {Sign::NEG, -136, 0x90176b35'd83ce8e2'cad9b30b'29736155_u128}, - {Sign::NEG, -136, 0x8c19a2fa'55fe9b14'6f881deb'98fc45f3_u128}, - {Sign::NEG, -136, 0x881bcad0'4d622a3e'70a04b63'b7248c96_u128}, - {Sign::NEG, -136, 0x841de2b7'3f361722'b4823fb4'8035eddd_u128}, - {Sign::NEG, -136, 0x801feaae'ac42ef38'3364ccb5'b13cd47f_u128}, - {Sign::NEG, -137, 0xf843c56c'2a969897'e306977b'049f0ad5_u128}, - {Sign::NEG, -137, 0xf0479599'f617a843'e3c4d9e9'619bc045_u128}, - {Sign::NEG, -137, 0xe84b45e5'bc76702c'4356d525'b5e6432d_u128}, - {Sign::NEG, -137, 0xe04ed64e'7f14697a'7839dcd7'989339ab_u128}, - {Sign::NEG, -137, 0xd85246d3'3f47230b'4e21f045'ecb76f23_u128}, - {Sign::NEG, -137, 0xd0559772'fe5840b0'902e248d'd4ba9b28_u128}, - {Sign::NEG, -137, 0xc858c82c'bd857a72'a4444906'7ef92e01_u128}, - {Sign::NEG, -137, 0xc05bd8ff'7e009bd2'17926207'cc22e4e6_u128}, - {Sign::NEG, -137, 0xb85ec9ea'40ef8309'1c349622'f3fa5d82_u128}, - {Sign::NEG, -137, 0xafe1c6ec'e1a058dd'97fa2fd0'c9dc723e_u128}, - {Sign::NEG, -137, 0xa7e47606'048b1a65'983e8089'7cf1e60f_u128}, - {Sign::NEG, -137, 0x9fe70534'1d236102'7199cd06'ae5d39b3_u128}, - {Sign::NEG, -137, 0x97e97476'2c5e8f58'43cd18a7'2a051a96_u128}, - {Sign::NEG, -137, 0x8febc3cb'332616ff'7b6d1248'c3e1fd40_u128}, - {Sign::NEG, -137, 0x87edf332'325777c5'f5572a88'14c703af_u128}, - {Sign::NEG, -138, 0xffe00554'55887de0'26828c92'649a3a39_u128}, - {Sign::NEG, -138, 0xefe3e464'3a640cf3'82c550bd'1216d82a_u128}, - {Sign::NEG, -138, 0xdfe78392'14b4e8ae'da6959f7'f0e01bf0_u128}, - {Sign::NEG, -138, 0xcfeae2db'e5d6736d'da93e2fa'85a8f214_u128}, - {Sign::NEG, -138, 0xbfee023f'af0c2480'b47505bf'a5a03b06_u128}, - {Sign::NEG, -138, 0xaff0e1bb'718186ad'b1475a51'80a43520_u128}, - {Sign::NEG, -138, 0x9ff3814d'2e4a36b2'a8740b91'c95df537_u128}, - {Sign::NEG, -138, 0x8ff5e0f2'e661e1c6'57d895d3'5921b59c_u128}, - {Sign::NEG, -139, 0xfff00155'35588833'3c56c598'c659c2a3_u128}, - {Sign::NEG, -139, 0xdff3c0e4'97ea4eb1'2ef8ec33'ed9d782a_u128}, - {Sign::NEG, -139, 0xbff7008f'f5e0c257'379eba7e'6465ff63_u128}, - {Sign::NEG, -139, 0x9ff9c053'5073a370'3f972b78'3fcab757_u128}, - {Sign::NEG, -140, 0xfff80055'51558885'de026e27'1ee0549d_u128}, - {Sign::NEG, -140, 0xbffb8023'febc0c25'eceb47ea'01f6c632_u128}, - {Sign::NEG, -141, 0xfffc0015'54d55888'7333c578'57e1ed52_u128}, - {Sign::NEG, -142, 0xfffe0005'55455588'87dde026'fa704374_u128}, - {Sign::POS, 0, 0_u128}, - {Sign::POS, -141, 0x80010002'aab2aac4'44999abe'2fe2cc65_u128}, - {Sign::POS, -140, 0x8002000a'aaeaac44'4eef3815'81464ccb_u128}, - {Sign::POS, -140, 0xc0048024'01440c26'dfeb4850'85f6f454_u128}, - {Sign::POS, -139, 0x8004002a'acaac445'99abe3be'3a1c6e93_u128}, - {Sign::POS, -139, 0xa0064053'5a37a37a'6bc1e20e'ac8448b4_u128}, - {Sign::POS, -139, 0xc0090090'0a20c275'979eedc0'64c242fd_u128}, - {Sign::POS, -139, 0xe00c40e4'bd6e4efd'c72446cc'1bf728bd_u128}, - {Sign::POS, -138, 0x800800aa'baac446e'f381b821'bbb569e5_u128}, - {Sign::POS, -138, 0x900a20f3'19a3e273'569b26aa'a485ea5c_u128}, - {Sign::POS, -138, 0xa00c814d'7c6a37f8'2dcf56c8'3c80b028_u128}, - {Sign::POS, -138, 0xb00f21bb'e3e388ee'5f697682'84463b9b_u128}, - {Sign::POS, -138, 0xc0120240'510c284c'b48ea6c0'5e2773a1_u128}, - {Sign::POS, -138, 0xd01522dc'c4f87991'14d9d761'96d8043a_u128}, - {Sign::POS, -138, 0xe0188393'40d4f241'e016a611'a4415d72_u128}, - {Sign::POS, -138, 0xf01c2465'c5e61b6f'661e135f'49a47c40_u128}, - {Sign::POS, -137, 0x801002ab'2ac4499a'be6bf0fa'435e8383_u128}, - {Sign::POS, -137, 0x88121333'7898871e'9a31ba0c'bc030353_u128}, - {Sign::POS, -137, 0x901443cc'cd362c9f'54b57dfe'0c4c840f_u128}, - {Sign::POS, -137, 0x98169478'296fad41'7ad1e9c3'15328f7e_u128}, - {Sign::POS, -137, 0xa0190536'8e2389b3'1f3f686c'f3d6be22_u128}, - {Sign::POS, -137, 0xa81b9608'fc3c50ec'f105b66e'c4703ede_u128}, - {Sign::POS, -137, 0xb01e46f0'74b0a0f3'610848c6'8df4d233_u128}, - {Sign::POS, -137, 0xb7a0e9ed'7613acb0'2e0efddf'33a20464_u128}, - {Sign::POS, -137, 0xbfa3d900'8e042ffb'c2cdb3c7'50f127b4_u128}, - {Sign::POS, -137, 0xc7a6e82b'a36a7073'bd953378'6d3f4c49_u128}, - {Sign::POS, -137, 0xcfaa176f'b76c8eb1'82e237c9'a4d450e3_u128}, - {Sign::POS, -137, 0xd7ad66cd'cb3cbe14'c00b46a4'd0e3dfd0_u128}, - {Sign::POS, -137, 0xdfb0d646'e0194584'ea999c0d'f8546710_u128}, - {Sign::POS, -137, 0xe7b465db'f74c8032'cec6c2a9'ad974f4f_u128}, - {Sign::POS, -137, 0xefb8158e'122cde5a'2d2045da'1570a07c_u128}, - {Sign::POS, -137, 0xf7bbe55e'321ce603'6752e9b2'381e3edc_u128}, - {Sign::POS, -137, 0xffbfd54d'588b33c5'3c1ed527'28e00e40_u128}, - {Sign::POS, -136, 0x83e1f2ae'43793dc3'493b0d87'3fb9a340_u128}, - {Sign::POS, -136, 0x87e40ac6'5f6cc4a0'29e38750'c9d26893_u128}, - {Sign::POS, -136, 0x8be632ef'80e9a0df'aab9e832'7258ac3f_u128}, - {Sign::POS, -136, 0x8fe86b2a'28bf51b3'28bc403d'8a5f3c63_u128}, - {Sign::POS, -136, 0x93eab376'd7c36377'f720c1c9'7227fcdc_u128}, - {Sign::POS, -136, 0x97ed0bd6'0ed17018'6ad9a3e3'd11b66c1_u128}, - {Sign::POS, -136, 0x9bef7448'4ecb1f6c'edb27b79'c90b4019_u128}, - {Sign::POS, -136, 0x9fb1c4cd'27012e19'a092a0d7'ab21722a_u128}, - {Sign::POS, -136, 0xa3b44c65'b71c2d85'535d52f0'939a4d02_u128}, - {Sign::POS, -136, 0xa7b6e412'cadcb3dc'90a57e11'edc1864e_u128}, - {Sign::POS, -136, 0xabb98bd4'e33c4381'68e9c901'60031159_u128}, - {Sign::POS, -136, 0xafbc43ac'813a6ea3'bf60594f'929adeb8_u128}, - {Sign::POS, -136, 0xb3bf0b9a'25dcd7a2'8a421588'86775205_u128}, - {Sign::POS, -136, 0xb7c1e39e'522f316d'1ab45417'663dee9e_u128}, - {Sign::POS, -136, 0xbbc4cbb9'87433fe4'6c51ae3c'e1aea68a_u128}, - {Sign::POS, -136, 0xbfc7c3ec'4630d83c'7c52ae8b'40ebabb7_u128}, - {Sign::POS, -136, 0xc3cacc37'1015e15d'a857126f'7cfaaa67_u128}, - {Sign::POS, -136, 0xc7cde49a'66165446'14d05662'cd29464a_u128}, - {Sign::POS, -136, 0xcb90da16'44d29bb7'8379db06'ef3cd6bb_u128}, - {Sign::POS, -136, 0xcf9411aa'99ddb7de'9025f4c6'7dd38bb6_u128}, - {Sign::POS, -136, 0xd3975958'f681086d'd6f8a61c'892032ee_u128}, - {Sign::POS, -136, 0xd79ab121'dbf8714c'9a2f20b4'e2332d47_u128}, - {Sign::POS, -136, 0xdb9e1905'cb85ea59'3c767d61'f51d375b_u128}, - {Sign::POS, -136, 0xdfa19105'46717fca'd4b2bd65'bb25493c_u128}, - {Sign::POS, -136, 0xe3a51920'ce095292'c96c1254'a30ef91f_u128}, - {Sign::POS, -136, 0xe7a8b158'e3a198be'73e324ce'0946b214_u128}, - {Sign::POS, -136, 0xebac59ae'08949dd8'cacd125a'12bac62c_u128}, - {Sign::POS, -136, 0xef6fd620'b2b7a503'cafdc272'27b71eaa_u128}, - {Sign::POS, -136, 0xf3739daf'959aaafc'688d4282'f6026aa3_u128}, - {Sign::POS, -136, 0xf777755d'03f4e0b6'e54e9e38'04464cdd_u128}, - {Sign::POS, -136, 0xfb7b5d29'7f388a12'cb78b383'f4b59dce_u128}, - {Sign::POS, -136, 0xff7f5515'88de024f'ee055fc5'15062c04_u128}, - {Sign::POS, -135, 0x81c1ae90'd131de38'207812b4'3382acdd_u128}, - {Sign::POS, -135, 0x83c3baa7'26a721cc'dc90c4c4'b61f3a87_u128}, - {Sign::POS, -135, 0x85c5cece'05941dbc'1a03f13f'b2c978b1_u128}, - {Sign::POS, -135, 0x87c7eb05'aec1304f'b36f282e'83a7dc36_u128}, - {Sign::POS, -135, 0x89a9eccd'56a980c0'd82a4661'6d4c393f_u128}, - {Sign::POS, -135, 0x8bac18a6'40185360'bc6ff847'13c9babd_u128}, - {Sign::POS, -135, 0x8dae4c90'b22574f4'9f7942a5'16fc2d8a_u128}, - {Sign::POS, -135, 0x8fb0888c'eda546ab'15e50cfd'9b29b427_u128}, - {Sign::POS, -135, 0x91b2cc9b'336f3718'9f465296'ae7dd49a_u128}, - {Sign::POS, -135, 0x93b518bb'c45dc268'b49c1eb9'b348e6e4_u128}, - {Sign::POS, -135, 0x95b76cee'e14e728e'daa320cd'64c9d9c7_u128}, - {Sign::POS, -135, 0x9799a333'de49b963'75a91950'ffe1e3b5_u128}, - {Sign::POS, -135, 0x999c070b'a32068cd'5c6abcbf'43f03f14_u128}, - {Sign::POS, -135, 0x9b9e72f6'b295ad4f'5a9e7f26'5d1ed157_u128}, - {Sign::POS, -135, 0x9da0e6f5'4d9318fd'efeb98d0'2a195c17_u128}, - {Sign::POS, -135, 0x9fa36307'b5054ca8'2aa503a3'110ab5a7_u128}, - {Sign::POS, -135, 0xa1a5e72e'29dbf808'd0fe7e05'869eb825_u128}, - {Sign::POS, -135, 0xa3884a68'a750cb10'e80a28f4'e1e500d2_u128}, - {Sign::POS, -135, 0xa58ade36'aeef9f0b'53106415'1ca6e30b_u128}, - {Sign::POS, -135, 0xa78d7a19'82c4b08f'27c01ffa'8e2e3c4b_u128}, - {Sign::POS, -135, 0xa9901e11'63cbbbf5'7ba9408d'c857d568_u128}, - {Sign::POS, -135, 0xab92ca1e'93038d76'104d1e33'31d3b4fa_u128}, - {Sign::POS, -135, 0xad957e41'516e0158'9343c846'fcdf9137_u128}, - {Sign::POS, -135, 0xaf780e79'b2514889'3977e89a'ec59bfa2_u128}, - {Sign::POS, -135, 0xb17ad246'ef3713bc'913d4e3d'c55c3e6e_u128}, - {Sign::POS, -135, 0xb37d9e2a'7a56b09d'777b52a9'e70d8bcc_u128}, - {Sign::POS, -135, 0xb5807224'94be0c91'55de916f'd30591de_u128}, - {Sign::POS, -135, 0xb7834e35'7f7e2600'e79cfb37'be2861e4_u128}, - {Sign::POS, -135, 0xb986325d'7bab0c89'90983104'd3805389_u128}, - {Sign::POS, -135, 0xbb68ef9c'254aa378'59e3b2ec'71ce64f4_u128}, - {Sign::POS, -135, 0xbd6be371'8c77636f'e83183bf'3dd612ef_u128}, - {Sign::POS, -135, 0xbf6edf5e'c44d9d35'c4e3b0ac'2fd52b7f_u128}, -}; - -// Logarithm range reduction - Step 3: -// s(k) = 2^-21 round( 2^21 / (1 + k*2^-21) ) - 1 for k = -69 .. 69 -// Output range: -// [-0x1.012bb800000800114p-22, 0x1p-22 ] -constexpr double S3[139] = { - 0x1.14p-15, 0x1.1p-15, 0x1.0cp-15, 0x1.08p-15, 0x1.04p-15, 0x1p-15, - 0x1.f8p-16, 0x1.fp-16, 0x1.e8p-16, 0x1.ep-16, 0x1.d8p-16, 0x1.dp-16, - 0x1.c8p-16, 0x1.cp-16, 0x1.b8p-16, 0x1.bp-16, 0x1.a8p-16, 0x1.ap-16, - 0x1.98p-16, 0x1.9p-16, 0x1.88p-16, 0x1.8p-16, 0x1.78p-16, 0x1.7p-16, - 0x1.68p-16, 0x1.6p-16, 0x1.58p-16, 0x1.5p-16, 0x1.48p-16, 0x1.4p-16, - 0x1.38p-16, 0x1.3p-16, 0x1.28p-16, 0x1.2p-16, 0x1.18p-16, 0x1.1p-16, - 0x1.08p-16, 0x1p-16, 0x1.fp-17, 0x1.ep-17, 0x1.dp-17, 0x1.cp-17, - 0x1.bp-17, 0x1.ap-17, 0x1.9p-17, 0x1.8p-17, 0x1.7p-17, 0x1.6p-17, - 0x1.5p-17, 0x1.4p-17, 0x1.3p-17, 0x1.2p-17, 0x1.1p-17, 0x1p-17, - 0x1.ep-18, 0x1.cp-18, 0x1.ap-18, 0x1.8p-18, 0x1.6p-18, 0x1.4p-18, - 0x1.2p-18, 0x1p-18, 0x1.cp-19, 0x1.8p-19, 0x1.4p-19, 0x1p-19, - 0x1.8p-20, 0x1p-20, 0x1p-21, 0.0, -0x1p-21, -0x1p-20, - -0x1.8p-20, -0x1p-19, -0x1.4p-19, -0x1.8p-19, -0x1.cp-19, -0x1p-18, - -0x1.2p-18, -0x1.4p-18, -0x1.6p-18, -0x1.8p-18, -0x1.ap-18, -0x1.cp-18, - -0x1.ep-18, -0x1p-17, -0x1.1p-17, -0x1.2p-17, -0x1.3p-17, -0x1.4p-17, - -0x1.5p-17, -0x1.6p-17, -0x1.7p-17, -0x1.8p-17, -0x1.9p-17, -0x1.ap-17, - -0x1.bp-17, -0x1.cp-17, -0x1.dp-17, -0x1.ep-17, -0x1.fp-17, -0x1p-16, - -0x1.08p-16, -0x1.1p-16, -0x1.18p-16, -0x1.2p-16, -0x1.28p-16, -0x1.3p-16, - -0x1.38p-16, -0x1.4p-16, -0x1.48p-16, -0x1.5p-16, -0x1.58p-16, -0x1.6p-16, - -0x1.68p-16, -0x1.7p-16, -0x1.78p-16, -0x1.8p-16, -0x1.88p-16, -0x1.9p-16, - -0x1.98p-16, -0x1.ap-16, -0x1.a8p-16, -0x1.bp-16, -0x1.b8p-16, -0x1.cp-16, - -0x1.c8p-16, -0x1.dp-16, -0x1.d8p-16, -0x1.ep-16, -0x1.e8p-16, -0x1.fp-16, - -0x1.f8p-16, -0x1p-15, -0x1.04p-15, -0x1.08p-15, -0x1.0cp-15, -0x1.1p-15, - -0x1.14p-15, -}; - -// -log(r) for the third step, generated by SageMath with: -// -// for i in range(-69, 70): -// r = 2^-21 * round( 2^21 / (1 + i*2^(-21)) ); -// s, m, e = RealField(128)(r).log().sign_mantissa_exponent(); -// print("{Sign::POS," if (s == -1) else "{Sign::NEG,", e, ", -// format_hex(m), "},"); -constexpr Float128 LOG_R3[139] = { - {Sign::NEG, -142, 0x89ff6b38'd5de2622'e39d3faf'42340ed7_u128}, - {Sign::NEG, -142, 0x87ff6f80'ccb40f16'7ff33266'82c02485_u128}, - {Sign::NEG, -142, 0x85ff73b8'c3cdf731'5caf4fbe'343cf928_u128}, - {Sign::NEG, -142, 0x83ff77e0'bb2ade79'cdb6e554'348f7fe8_u128}, - {Sign::NEG, -142, 0x81ff7bf8'b2c9c4f6'0ef009c2'457de25d_u128}, - {Sign::NEG, -143, 0xffff0001'55535558'8883333c'57b57c74_u128}, - {Sign::NEG, -143, 0xfbff07f1'45931f44'f32668f3'9c70d183_u128}, - {Sign::NEG, -143, 0xf7ff0fc1'3650e7bd'459a73c6'a6486fe3_u128}, - {Sign::NEG, -143, 0xf3ff1771'278aaecd'37b18cca'7dd3a29f_u128}, - {Sign::NEG, -143, 0xefff1f01'193e7480'513f610d'21bcfc78_u128}, - {Sign::NEG, -143, 0xebff2671'0b6a38e1'ea190b95'c0690b7b_u128}, - {Sign::NEG, -143, 0xe7ff2dc0'fe0bfbfd'2a150f64'f0ad1743_u128}, - {Sign::NEG, -143, 0xe3ff34f0'f121bddd'090b5174'e995e9d1_u128}, - {Sign::NEG, -143, 0xdfff3c00'e4a97e8c'4ed512b9'b93ea2bf_u128}, - {Sign::NEG, -143, 0xdbff42f0'd8a13e15'934cea21'7ab794a2_u128}, - {Sign::NEG, -143, 0xd7ff49c0'cd06fc83'3e4ebe94'8afd2c76_u128}, - {Sign::NEG, -143, 0xd3ff5070'c1d8b9df'87b7c0f5'bcfee2e1_u128}, - {Sign::NEG, -143, 0xcfff5700'b7147634'77666622'8cb6371b_u128}, - {Sign::NEG, -143, 0xcbff5d70'acb8318b'e53a60f3'514db358_u128}, - {Sign::NEG, -143, 0xc7ff63c0'a2c1ebef'79149c3b'6e57fa86_u128}, - {Sign::NEG, -143, 0xc3ff69f0'992fa568'aad734c9'8416df2a_u128}, - {Sign::NEG, -143, 0xbfff7000'8fff5e00'c2657367'9ed28334_u128}, - {Sign::NEG, -143, 0xbbff75f0'872f15c0'd7a3c6db'6540809f_u128}, - {Sign::NEG, -143, 0xb7ff7bc0'7ebcccb1'd277bde6'45fb1aad_u128}, - {Sign::NEG, -143, 0xb3ff8170'76a682dc'6ac80145'a4087793_u128}, - {Sign::NEG, -143, 0xafff8700'6eea3849'287c4db3'0271e265_u128}, - {Sign::NEG, -143, 0xabff8c70'6785ed00'637d6de4'2eeb151e_u128}, - {Sign::NEG, -143, 0xa7ff91c0'6077a10a'43b5348b'6b898a8c_u128}, - {Sign::NEG, -143, 0xa3ff96f0'59bd546e'c10e7657'978bd7f6_u128}, - {Sign::NEG, -143, 0x9fff9c00'53550735'a37503f4'57310e59_u128}, - {Sign::NEG, -143, 0x9bffa0f0'4d3cb966'82d5a40a'3aa022ff_u128}, - {Sign::NEG, -143, 0x97ffa5c0'47726b08'c71e0d3e'e3df5f4d_u128}, - {Sign::NEG, -143, 0x93ffaa70'41f41c23'a83ce035'2bdbd79b_u128}, - {Sign::NEG, -143, 0x8fffaf00'3cbfccbe'2e21a18d'4680e8e4_u128}, - {Sign::NEG, -143, 0x8bffb370'37d37cdf'30bcb3e4'e5dfbd28_u128}, - {Sign::NEG, -143, 0x87ffb7c0'332d2c8d'57ff51d7'5c66d64a_u128}, - {Sign::NEG, -143, 0x83ffbbf0'2ecadbcf'1bdb87fd'be299f43_u128}, - {Sign::NEG, -144, 0xffff8000'55551555'88885dde'02700703_u128}, - {Sign::NEG, -144, 0xf7ff87e0'4d94724c'd259ca80'3a0c1870_u128}, - {Sign::NEG, -144, 0xefff8f80'464fce8f'e5141308'51c7070a_u128}, - {Sign::NEG, -144, 0xe7ff96e0'3f832a2a'30a16898'f3073a64_u128}, - {Sign::NEG, -144, 0xdfff9e00'392a8526'c4ed6451'7b2949ce_u128}, - {Sign::NEG, -144, 0xd7ffa4e0'3341df90'51e4fb4e'32cf6350_u128}, - {Sign::NEG, -144, 0xcfffab80'2dc53971'277672a8'8350bcce_u128}, - {Sign::NEG, -144, 0xc7ffb1e0'28b092d3'35915377'2a490f06_u128}, - {Sign::NEG, -144, 0xbfffb800'23ffebc0'0c265ece'6b481a0e_u128}, - {Sign::NEG, -144, 0xb7ffbde0'1faf4440'db2781c0'3fa132f6_u128}, - {Sign::NEG, -144, 0xafffc380'1bba9c5e'7287c95c'845ada33_u128}, - {Sign::NEG, -144, 0xa7ffc8e0'181df421'423b56b1'263e5a77_u128}, - {Sign::NEG, -144, 0x9fffce00'14d54b91'5a3752ca'4c076fa3_u128}, - {Sign::NEG, -144, 0x97ffd2e0'11dca2b6'6a71e2b2'7eb3f573_u128}, - {Sign::NEG, -144, 0x8fffd780'0f2ff997'c2e21b72'cff39d8f_u128}, - {Sign::NEG, -144, 0x87ffdbe0'0ccb503c'537ff612'feb7ac9e_u128}, - {Sign::NEG, -145, 0xffffc000'15554d55'58888733'33c57c18_u128}, - {Sign::NEG, -145, 0xefffc7c0'1193f9d1'fa514218'42311c42_u128}, - {Sign::NEG, -145, 0xdfffcf00'0e4aa5fa'2c4ed6de'475b942c_u128}, - {Sign::NEG, -145, 0xcfffd5c0'0b7151d8'ce77678c'bb6fcb88_u128}, - {Sign::NEG, -145, 0xbfffdc00'08fffd78'00c26629'a679ed3b_u128}, - {Sign::NEG, -145, 0xafffe1c0'06eea8e1'23287cb9'd3072728_u128}, - {Sign::NEG, -145, 0x9fffe700'0535541c'd5a37540'fd057315_u128}, - {Sign::NEG, -145, 0x8fffebc0'03cbff32'f82e21c1'fce36810_u128}, - {Sign::NEG, -146, 0xffffe000'05555455'5588887d'dde02702_u128}, - {Sign::NEG, -146, 0xdfffe780'0392aa14'9ac4ed72'adf5b295_u128}, - {Sign::NEG, -146, 0xbfffee00'023fffaf'000c2664'8066b482_u128}, - {Sign::NEG, -146, 0x9ffff380'014d552e'455a3754'b292c077_u128}, - {Sign::NEG, -147, 0xfffff000'01555535'55588888'33333c58_u128}, - {Sign::NEG, -147, 0xbffff700'008ffff5'e000c266'5736679f_u128}, - {Sign::NEG, -148, 0xfffff800'00555551'55558888'85ddde02_u128}, - {Sign::NEG, -149, 0xfffffc00'00155554'd5555888'88733334_u128}, - {Sign::POS, 0, 0_u128}, - {Sign::POS, -148, 0x80000200'000aaaaa'eaaaac44'444eeeef_u128}, - {Sign::POS, -147, 0x80000400'002aaaac'aaaac444'459999ac_u128}, - {Sign::POS, -147, 0xc0000900'0090000a'2000c266'7596679f_u128}, - {Sign::POS, -146, 0x80000800'00aaaaba'aaac4444'6eeef381_u128}, - {Sign::POS, -146, 0xa0000c80'014d557c'655a3755'f81815cc_u128}, - {Sign::POS, -146, 0xc0001200'02400051'000c2668'4c66b482_u128}, - {Sign::POS, -146, 0xe0001880'0392ab40'bac4ed7c'40fb07eb_u128}, - {Sign::POS, -145, 0x80001000'02aaab2a'aac44449'999abe2c_u128}, - {Sign::POS, -145, 0x90001440'03cc00cd'082e21d7'9cbb6812_u128}, - {Sign::POS, -145, 0xa0001900'0535568d'd5a37569'adb01dc3_u128}, - {Sign::POS, -145, 0xb0001e40'06eeac74'33287d01'e8c9d1d9_u128}, - {Sign::POS, -145, 0xc0002400'09000288'00c266a3'2679ed48_u128}, - {Sign::POS, -145, 0xd0002a40'0b7158d1'de776851'22b2764b_u128}, - {Sign::POS, -145, 0xe0003100'0e4aaf5b'2c4ed810'a8063f03_u128}, - {Sign::POS, -145, 0xf0003840'1194062e'0a5143e7'be891c8f_u128}, - {Sign::POS, -144, 0x80002000'0aaaaeaa'ac4444ee'ef3813a1_u128}, - {Sign::POS, -144, 0x88002420'0ccb5a6e'5b7ff7fe'1339025b_u128}, - {Sign::POS, -144, 0x90002880'0f300668'42e21e26'caf39e33_u128}, - {Sign::POS, -144, 0x98002d20'11dcb29e'f271e66f'a5554bc6_u128}, - {Sign::POS, -144, 0xa0003200'14d55f19'5a3757e0'615cc676_u128}, - {Sign::POS, -144, 0xa8003720'181e0bde'ca3b5d82'10ca5cab_u128}, - {Sign::POS, -144, 0xb0003c80'1bbab8f6'f287d25f'3cb032bb_u128}, - {Sign::POS, -144, 0xb8004220'1faf6669'e3278d84'0be28cdb_u128}, - {Sign::POS, -144, 0xc0004800'24001440'0c266dfe'6b482076_u128}, - {Sign::POS, -144, 0xc8004e20'28b0c282'3d9166de'380a6d3d_u128}, - {Sign::POS, -144, 0xd0005480'2dc57139'a7768b35'6ba61e4b_u128}, - {Sign::POS, -144, 0xd8005b20'3342206f'd9e51a18'49db73c1_u128}, - {Sign::POS, -144, 0xe0006200'392ad02e'c4ed8a9d'907eb521_u128}, - {Sign::POS, -144, 0xe8006920'3f838080'b8a197de'a928acd7_u128}, - {Sign::POS, -144, 0xf0007080'46503170'65144cf7'dcc72d3b_u128}, - {Sign::POS, -144, 0xf8007820'4d94e308'da5a1108'890d9f6a_u128}, - {Sign::POS, -143, 0x80004000'2aaacaaa'c4445999'abe2ce2c_u128}, - {Sign::POS, -143, 0x84004410'2ecb2431'1fdbbb4f'3bffc832_u128}, - {Sign::POS, -143, 0x88004840'332d7e1d'97ff8f39'ec91b4ee_u128}, - {Sign::POS, -143, 0x8c004c90'37d3d876'74bcfcf0'b3f0a95d_u128}, - {Sign::POS, -143, 0x90005100'3cc03342'2e21f80c'a6813aff_u128}, - {Sign::POS, -143, 0x94005590'41f48e87'6c3d4629'170ce87f_u128}, - {Sign::POS, -143, 0x98005a40'4772ea4d'071e84e3'b80a8881_u128}, - {Sign::POS, -143, 0x9c005f10'4d3d469a'06d62fdc'bdd6bec3_u128}, - {Sign::POS, -143, 0xa0006400'5355a375'a375a6b7'01dc77c0_u128}, - {Sign::POS, -143, 0xa4006910'59be00e7'450f3318'26ad6b05_u128}, - {Sign::POS, -143, 0xa8006e40'60785ef6'83b60ea8'bd0aa459_u128}, - {Sign::POS, -143, 0xac007390'6786bdab'277e6914'69dd13f5_u128}, - {Sign::POS, -143, 0xb0007900'6eeb1d0d'287d6e0a'0d1e25eb_u128}, - {Sign::POS, -143, 0xb4007e90'76a77d24'aec94b3b'e9b060f5_u128}, - {Sign::POS, -143, 0xb8008440'7ebdddfa'1279365f'ce280cce_u128}, - {Sign::POS, -143, 0xbc008a10'87303f95'dba5732f'3e83e04a_u128}, - {Sign::POS, -143, 0xc0009000'9000a200'c2675967'9ed5b754_u128}, - {Sign::POS, -143, 0xc4009610'99310543'aed95aca'5edb5109_u128}, - {Sign::POS, -143, 0xc8009c40'a2c36967'b917091d'2687160f_u128}, - {Sign::POS, -143, 0xcc00a290'acb9ce76'293d1c2a'0378e75d_u128}, - {Sign::POS, -143, 0xd000a900'b7163478'776977bf'9766f5a7_u128}, - {Sign::POS, -143, 0xd400af90'c1da9b78'4bbb31b1'4776a18b_u128}, - {Sign::POS, -143, 0xd800b640'cd09037f'7e5297d7'6c8564ba_u128}, - {Sign::POS, -143, 0xdc00bd10'd8a36c98'1751360f'8461c447_u128}, - {Sign::POS, -143, 0xe000c400'e4abd6cc'4ed9dc3c'63f44c41_u128}, - {Sign::POS, -143, 0xe400cb10'f1244226'8d10a446'6a5894d5_u128}, - {Sign::POS, -143, 0xe800d240'fe0eaeb1'6a1af81b'b4e6510e_u128}, - {Sign::POS, -143, 0xec00d991'0b6d1c77'ae1f97b0'542a677a_u128}, - {Sign::POS, -143, 0xf000e101'19418b84'51469efe'81d014cc_u128}, - {Sign::POS, -143, 0xf400e891'278dfbe2'7bb98c06'd77a18b4_u128}, - {Sign::POS, -143, 0xf800f041'36546d9d'85a344d0'868bed17_u128}, - {Sign::POS, -143, 0xfc00f811'4596e0c0'f7301d69'90e307cc_u128}, - {Sign::POS, -142, 0x80008000'aaabaaac'4446eef3'8140138f_u128}, - {Sign::POS, -142, 0x82008408'b2cbe5b8'10f5e432'96105497_u128}, - {Sign::POS, -142, 0x84008820'bb2d2189'edbd4f83'ef63f730_u128}, - {Sign::POS, -142, 0x86008c48'c3d05e27'feb654fd'541c638e_u128}, - {Sign::POS, -142, 0x88009080'ccb69b98'7ffadeb8'882f7674_u128}, - {Sign::POS, -142, 0x8a0094c8'd5e0d9e1'c5a59fd3'6bd44397_u128}, -}; - -// Minimax polynomial generated by Sollya with: -// > P = fpminimax((log(1 + x) - x)/x^2, 3, [|1, 128...|], -// [-0x1.01928p-22 , 0x1p-22]); -// > P; -// > dirtyinfnorm(log(1 + x)/x - 1 - x*P, [-0x1.01928p-22 , 0x1p-22]); -// 0x1.ce1e...p-116 -constexpr Float128 BIG_COEFFS[4]{ - {Sign::POS, -130, 0xccccccd7'4818e397'7ed78465'd460315b_u128}, - {Sign::NEG, -129, 0x80000000'000478b0'c6388a23'871ce156_u128}, - {Sign::POS, -129, 0xaaaaaaaa'aaaaaaaa'aa807bd8'67763262_u128}, - {Sign::NEG, -128, 0x80000000'00000000'00000000'00000000_u128}, -}; - -[[maybe_unused]] LIBC_INLINE double log1p_accurate(int e_x, int index, - fputil::DoubleDouble m_x) { - Float128 e_x_f128(static_cast<float>(e_x)); - Float128 sum = fputil::quick_mul(LOG_2, e_x_f128); - sum = fputil::quick_add(sum, LOG_R1[index]); - - // fputil::DoubleDouble v4; - Float128 v = fputil::quick_add(Float128(m_x.hi), Float128(m_x.lo)); - - // Skip 2nd range reduction step if |m_x| <= 2^-15. - if (m_x.hi > 0x1p-15 || m_x.hi < -0x1p-15) { - // Range reduction - Step 2. - // For k such that: k * 2^-14 - 2^-15 <= m_x.hi < k * 2^-14 + 2^-15, - // Let s_k = 2^-18 * round( 2^18 / (1 + k*2^-14) ) - 1 - // Then the 2nd reduced argument is: - // (1 + s_k) * (1 + m_x) - 1 = - // = s_k + m_x + s_k * m_x - // Output range: - // -0x1.1037c00000040271p-15 <= v2.hi + v2.lo <= 0x1.108480000008096cp-15 - int idx2 = static_cast<int>(0x1p14 * (m_x.hi + (91 * 0x1p-14 + 0x1p-15))); - sum = fputil::quick_add(sum, LOG_R2[idx2]); - Float128 s2 = Float128(S2[idx2]); - v = fputil::quick_add(fputil::quick_add(v, s2), fputil::quick_mul(v, s2)); - } - - // Skip 3rd range reduction step if |v| <= 2^-22. - if (v.exponent > -150) { - // Range reduction - Step 3. - // For k such that: k * 2^-21 - 2^-22 <= v2.hi < k * 2^-21 + 2^-22, - // Let s_k = 2^-21 * round( 2^21 / (1 + k*2^-21) ) - 1 - // Then the 3rd reduced argument is: - // v3.hi + v3.lo ~ (1 + s_k) * (1 + v2.hi + v2.lo) - 1 - // Output range: - // -0x1.012bb800000800114p-22 <= v3.hi + v3.lo <= 0x1p-22 - int idx3 = - static_cast<int>(0x1p21 * (double(v) + (69 * 0x1p-21 + 0x1p-22))); - sum = fputil::quick_add(sum, LOG_R3[idx3]); - Float128 s3 = Float128(S3[idx3]); - v = fputil::quick_add(fputil::quick_add(v, s3), fputil::quick_mul(v, s3)); - } - - // Polynomial approximation - Float128 p = fputil::quick_mul(v, BIG_COEFFS[0]); - p = fputil::quick_mul(v, fputil::quick_add(p, BIG_COEFFS[1])); - p = fputil::quick_mul(v, fputil::quick_add(p, BIG_COEFFS[2])); - p = fputil::quick_mul(v, fputil::quick_add(p, BIG_COEFFS[3])); - p = fputil::quick_add(v, fputil::quick_mul(v, p)); - - Float128 r = fputil::quick_add(sum, p); - - return static_cast<double>(r); -} -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS - -} // namespace - -LLVM_LIBC_FUNCTION(double, log1p, (double x)) { - using FPBits_t = typename fputil::FPBits<double>; - - constexpr int EXP_BIAS = FPBits_t::EXP_BIAS; - constexpr int FRACTION_LEN = FPBits_t::FRACTION_LEN; - FPBits_t xbits(x); - uint64_t x_u = xbits.uintval(); - - fputil::DoubleDouble x_dd{0.0, 0.0}; - - uint16_t x_exp = xbits.get_biased_exponent(); - - if (x_exp >= EXP_BIAS) { - // |x| >= 1 - if (LIBC_UNLIKELY(x_u >= 0x4650'0000'0000'0000ULL)) { - // x >= 2^102 or x is negative, inf, or NaN - if (LIBC_UNLIKELY(x_u > FPBits_t::max_normal().uintval())) { - // x <= -1.0 or x is Inf or NaN - if (x_u == 0xbff0'0000'0000'0000ULL) { - // x = -1.0 - fputil::set_errno_if_required(ERANGE); - fputil::raise_except_if_required(FE_DIVBYZERO); - return FPBits_t::inf(Sign::NEG).get_val(); - } - if (xbits.is_neg() && !xbits.is_nan()) { - // x < -1.0 - fputil::set_errno_if_required(EDOM); - fputil::raise_except_if_required(FE_INVALID); - return FPBits_t::quiet_nan().get_val(); - } - // x is +Inf or NaN - if (xbits.is_inf() && xbits.is_pos()) - return x; - - if (xbits.is_signaling_nan()) - fputil::raise_except_if_required(FE_INVALID); - return FPBits_t::quiet_nan().get_val(); - } - x_dd.hi = x; - } else { - x_dd = fputil::exact_add(x, 1.0); - } - } else { - // |x| < 1 - if (LIBC_UNLIKELY(xbits.get_biased_exponent() < - EXP_BIAS - FRACTION_LEN - 1)) { - // Quick return when |x| < 2^-53. - // Since log(1 + x) = x - x^2/2 + x^3/3 - ..., - // for |x| < 2^-53, - // x > log(1 + x) > x - x^2 > x(1 - 2^-54) > x - ulp(x)/2 - // Thus, - // log(1 + x) = nextafter(x, -inf) for FE_DOWNWARD, or - // FE_TOWARDZERO and x > 0, - // = x otherwise. - if (x + x == 0.0) - return x + x; // Handle FTZ/DAZ correctly. - - volatile float tp = 1.0f; - volatile float tn = -1.0f; - bool rdp = (tp - 0x1p-25f != tp); - bool rdn = (tn - 0x1p-24f != tn); - - if (x > 0 && rdp) { - return FPBits_t(x_u - 1).get_val(); - } - - if (x < 0 && rdn) { - return FPBits_t(x_u + 1).get_val(); - } - - return x; - } - x_dd = fputil::exact_add(1.0, x); - } - - // At this point, x_dd is the exact sum of 1 + x: - // x_dd.hi + x_dd.lo = x + 1.0 exactly. - // |x_dd.hi| >= 2^-54 - // |x_dd.lo| < ulp(x_dd.hi) - - FPBits_t xhi_bits(x_dd.hi); - uint64_t xhi_frac = xhi_bits.get_mantissa(); - x_u = xhi_bits.uintval(); - // Range reduction: - // Find k such that |x_hi - k * 2^-7| <= 2^-8. - int idx = static_cast<int>((xhi_frac + (1ULL << (FRACTION_LEN - 8))) >> - (FRACTION_LEN - 7)); - int x_e = xhi_bits.get_exponent() + (idx >> 7); - double e_x = static_cast<double>(x_e); - - // hi is exact - // ulp(hi) = ulp(LOG_2_HI) = ulp(LOG_R1_DD[idx].hi) = 2^-43 - double hi = fputil::multiply_add(e_x, LOG_2_HI, LOG_R1_DD[idx].hi); - // lo errors < |e_x| * ulp(LOG_2_LO) + ulp(LOG_R1[idx].lo) - // <= 2^11 * 2^(-43-53) = 2^-85 - double lo = fputil::multiply_add(e_x, LOG_2_LO, LOG_R1_DD[idx].lo); - -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - // Error bound of e_x * log(2) - log(r1) - constexpr double ERR_HI[2] = {0x1.0p-85, 0.0}; - double err_hi = ERR_HI[hi == 0.0]; -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS - - // Scale x_dd by 2^(-xh_bits.get_exponent()). - int64_t s_u = static_cast<int64_t>(x_u & FPBits_t::EXP_MASK) - - (static_cast<int64_t>(EXP_BIAS) << FRACTION_LEN); - // Normalize arguments: - // 1 <= m_dd.hi < 2 - // |m_dd.lo| < 2^-52. - // This is exact. - uint64_t m_hi = FPBits_t::one().uintval() | xhi_frac; - - uint64_t m_lo = - FPBits_t(x_dd.lo).abs().get_val() > x_dd.hi * 0x1.0p-127 - ? static_cast<uint64_t>(cpp::bit_cast<int64_t>(x_dd.lo) - s_u) - : 0; - - fputil::DoubleDouble m_dd{FPBits_t(m_lo).get_val(), FPBits_t(m_hi).get_val()}; - - // Perform range reduction: - // r * m - 1 = r * (m_dd.hi + m_dd.lo) - 1 - // = (r * m_dd.hi - 1) + r * m_dd.lo - // = v_hi + (v_lo.hi + v_lo.lo) - // where: - // v_hi = r * m_dd.hi - 1 (exact) - // v_lo.hi + v_lo.lo = r * m_dd.lo (exact) - // Bounds on the values: - // -0x1.69000000000edp-8 < r * m - 1 < 0x1.7f00000000081p-8 - // |v_lo.hi| <= |r| * |m_dd.lo| < 2^-52 - // |v_lo.lo| < ulp(v_lo.hi) <= 2^(-52 - 53) = 2^(-105) - double r = R1[idx]; - double v_hi; - fputil::DoubleDouble v_lo = fputil::exact_mult(m_dd.lo, r); - - // Perform exact range reduction -#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE - v_hi = fputil::multiply_add(r, m_dd.hi, -1.0); // Exact. -#else - // c = 1 + idx * 2^-7. - double c = FPBits_t((static_cast<uint64_t>(idx) << (FRACTION_LEN - 7)) + - uint64_t(0x3FF0'0000'0000'0000ULL)) - .get_val(); - v_hi = fputil::multiply_add(r, m_dd.hi - c, RCM1[idx]); // Exact -#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE - - // Range reduction output: - // -0x1.69000000000edp-8 < v_hi + v_lo < 0x1.7f00000000081p-8 - // |v_dd.lo| < ulp(v_dd.hi) <= 2^(-7 - 53) = 2^-60 - fputil::DoubleDouble v_dd = fputil::exact_add(v_hi, v_lo.hi); - v_dd.lo += v_lo.lo; - - // Exact sum: - // r1.hi + r1.lo = e_x * log(2)_hi - log(r)_hi + u - fputil::DoubleDouble r1 = fputil::exact_add(hi, v_dd.hi); - - // Overall error is bounded by: - // C * ulp(v_sq) + err_hi - double v_sq = v_dd.hi * v_dd.hi; - double p0 = fputil::multiply_add(v_dd.hi, P_COEFFS[1], P_COEFFS[0]); - double p1 = fputil::multiply_add(v_dd.hi, P_COEFFS[3], P_COEFFS[2]); - double p2 = fputil::multiply_add(v_dd.hi, P_COEFFS[5], P_COEFFS[4]); - double p = fputil::polyeval(v_sq, (v_dd.lo + r1.lo) + lo, p0, p1, p2); - -#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - return r1.hi + p; -#else - double err = fputil::multiply_add(v_sq, P_ERR, err_hi); - - double left = r1.hi + (p - err); - double right = r1.hi + (p + err); - - // Ziv's test to see if fast pass is accurate enough. - if (left == right) - return left; - - return log1p_accurate(x_e, idx, v_dd); -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS -} +LLVM_LIBC_FUNCTION(double, log1p, (double x)) { return math::log1p(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/log2.cpp b/libc/src/math/generic/log2.cpp index ae7a658..e292a02 100644 --- a/libc/src/math/generic/log2.cpp +++ b/libc/src/math/generic/log2.cpp @@ -7,967 +7,9 @@ //===----------------------------------------------------------------------===// #include "src/math/log2.h" -#include "src/__support/FPUtil/FEnvImpl.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/PolyEval.h" -#include "src/__support/FPUtil/double_double.h" -#include "src/__support/FPUtil/dyadic_float.h" -#include "src/__support/FPUtil/multiply_add.h" -#include "src/__support/common.h" -#include "src/__support/integer_literals.h" -#include "src/__support/macros/config.h" -#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY - -#include "src/__support/math/common_constants.h" -#include "src/__support/math/log_range_reduction.h" +#include "src/__support/math/log2.h" namespace LIBC_NAMESPACE_DECL { - -// 128-bit precision dyadic floating point numbers. -using Float128 = typename fputil::DyadicFloat<128>; - -using LIBC_NAMESPACE::operator""_u128; - -namespace { - -using namespace common_constants_internal; -using namespace math::log_range_reduction_internal; - -constexpr fputil::DoubleDouble LOG2_E = {0x1.777d0ffda0d24p-56, - 0x1.71547652b82fep0}; - -alignas(16) const fputil::DoubleDouble LOG_R1[128] = { - {0.0, 0.0}, - {0x1.46662d417cedp-62, 0x1.010157588de71p-7}, - {0x1.27c8e8416e71fp-60, 0x1.0205658935847p-6}, - {-0x1.d192d0619fa67p-60, 0x1.8492528c8cabfp-6}, - {0x1.c05cf1d753622p-59, 0x1.0415d89e74444p-5}, - {-0x1.cdd6f7f4a137ep-59, 0x1.466aed42de3eap-5}, - {0x1.a8be97660a23dp-60, 0x1.894aa149fb343p-5}, - {-0x1.e48fb0500efd4p-59, 0x1.ccb73cdddb2ccp-5}, - {-0x1.dd7009902bf32p-58, 0x1.08598b59e3a07p-4}, - {-0x1.7558367a6acf6p-59, 0x1.1973bd1465567p-4}, - {0x1.7a976d3b5b45fp-59, 0x1.3bdf5a7d1ee64p-4}, - {0x1.f38745c5c450ap-58, 0x1.5e95a4d9791cbp-4}, - {-0x1.72566212cdd05p-61, 0x1.700d30aeac0e1p-4}, - {-0x1.478a85704ccb7p-58, 0x1.9335e5d594989p-4}, - {-0x1.0057eed1ca59fp-59, 0x1.b6ac88dad5b1cp-4}, - {0x1.a38cb559a6706p-58, 0x1.c885801bc4b23p-4}, - {-0x1.a2bf991780d3fp-59, 0x1.ec739830a112p-4}, - {-0x1.ac9f4215f9393p-58, 0x1.fe89139dbd566p-4}, - {-0x1.0e63a5f01c691p-58, 0x1.1178e8227e47cp-3}, - {-0x1.c6ef1d9b2ef7ep-59, 0x1.1aa2b7e23f72ap-3}, - {-0x1.499a3f25af95fp-58, 0x1.2d1610c86813ap-3}, - {0x1.7d411a5b944adp-58, 0x1.365fcb0159016p-3}, - {-0x1.0d5604930f135p-58, 0x1.4913d8333b561p-3}, - {-0x1.71a9682395bfdp-61, 0x1.527e5e4a1b58dp-3}, - {-0x1.d34f0f4621bedp-60, 0x1.6574ebe8c133ap-3}, - {-0x1.8de59c21e166cp-57, 0x1.6f0128b756abcp-3}, - {-0x1.1232ce70be781p-57, 0x1.823c16551a3c2p-3}, - {0x1.55aa8b6997a4p-58, 0x1.8beafeb38fe8cp-3}, - {0x1.142c507fb7a3dp-58, 0x1.95a5adcf7017fp-3}, - {0x1.bcafa9de97203p-57, 0x1.a93ed3c8ad9e3p-3}, - {-0x1.6353ab386a94dp-57, 0x1.b31d8575bce3dp-3}, - {0x1.dd355f6a516d7p-60, 0x1.bd087383bd8adp-3}, - {0x1.60629242471a2p-57, 0x1.d1037f2655e7bp-3}, - {0x1.aa11d49f96cb9p-58, 0x1.db13db0d4894p-3}, - {0x1.2276041f43042p-59, 0x1.e530effe71012p-3}, - {-0x1.08ab2ddc708ap-58, 0x1.ef5ade4dcffe6p-3}, - {0x1.f665066f980a2p-57, 0x1.f991c6cb3b379p-3}, - {0x1.cdb16ed4e9138p-56, 0x1.07138604d5862p-2}, - {0x1.162c79d5d11eep-58, 0x1.0c42d676162e3p-2}, - {-0x1.0e63a5f01c691p-57, 0x1.1178e8227e47cp-2}, - {0x1.66fbd28b40935p-56, 0x1.16b5ccbacfb73p-2}, - {-0x1.12aeb84249223p-57, 0x1.1bf99635a6b95p-2}, - {0x1.e0efadd9db02bp-56, 0x1.269621134db92p-2}, - {-0x1.82dad7fd86088p-56, 0x1.2bef07cdc9354p-2}, - {-0x1.3d69909e5c3dcp-56, 0x1.314f1e1d35ce4p-2}, - {-0x1.324f0e883858ep-58, 0x1.36b6776be1117p-2}, - {-0x1.2ad27e50a8ec6p-56, 0x1.3c25277333184p-2}, - {0x1.0dbb243827392p-57, 0x1.419b423d5e8c7p-2}, - {0x1.8fb4c14c56eefp-60, 0x1.4718dc271c41bp-2}, - {-0x1.123615b147a5dp-58, 0x1.4c9e09e172c3cp-2}, - {-0x1.8f7e9b38a6979p-57, 0x1.522ae0738a3d8p-2}, - {-0x1.0908d15f88b63p-57, 0x1.57bf753c8d1fbp-2}, - {-0x1.6541148cbb8a2p-56, 0x1.5d5bddf595f3p-2}, - {0x1.dc18ce51fff99p-57, 0x1.630030b3aac49p-2}, - {0x1.a64eadd740178p-58, 0x1.68ac83e9c6a14p-2}, - {0x1.657c222d868cdp-58, 0x1.6e60ee6af1972p-2}, - {0x1.84a4ee3059583p-56, 0x1.741d876c67bb1p-2}, - {-0x1.c168817443f22p-56, 0x1.79e26687cfb3ep-2}, - {-0x1.219024acd3b77p-58, 0x1.7fafa3bd8151cp-2}, - {-0x1.486666443b153p-56, 0x1.85855776dcbfbp-2}, - {-0x1.70f2f38238303p-56, 0x1.8b639a88b2df5p-2}, - {-0x1.ad4bb98c1f2c5p-56, 0x1.914a8635bf68ap-2}, - {-0x1.89d2816cf838fp-57, 0x1.973a3431356aep-2}, - {0x1.87bcbcfd3e187p-59, 0x1.9d32bea15ed3bp-2}, - {-0x1.ba8062860ae23p-57, 0x1.a33440224fa79p-2}, - {-0x1.ba8062860ae23p-57, 0x1.a33440224fa79p-2}, - {0x1.bcafa9de97203p-56, 0x1.a93ed3c8ad9e3p-2}, - {0x1.9d56c45dd3e86p-56, 0x1.af5295248cddp-2}, - {0x1.494b610665378p-56, 0x1.b56fa04462909p-2}, - {0x1.6fd02999b21e1p-59, 0x1.bb9611b80e2fbp-2}, - {-0x1.bfc00b8f3feaap-56, 0x1.c1c60693fa39ep-2}, - {-0x1.bfc00b8f3feaap-56, 0x1.c1c60693fa39ep-2}, - {0x1.223eadb651b4ap-57, 0x1.c7ff9c74554c9p-2}, - {0x1.0798270b29f39p-56, 0x1.ce42f18064743p-2}, - {0x1.d7f4d3b3d406bp-56, 0x1.d490246defa6bp-2}, - {-0x1.0b5837185a661p-56, 0x1.dae75484c9616p-2}, - {-0x1.ac81cc8a4dfb8p-56, 0x1.e148a1a2726cep-2}, - {-0x1.ac81cc8a4dfb8p-56, 0x1.e148a1a2726cep-2}, - {0x1.57d646a17bc6ap-56, 0x1.e7b42c3ddad73p-2}, - {-0x1.74b71fb5e57e3p-62, 0x1.ee2a156b413e5p-2}, - {-0x1.0d487f5aba5e5p-57, 0x1.f4aa7ee03192dp-2}, - {-0x1.0d487f5aba5e5p-57, 0x1.f4aa7ee03192dp-2}, - {0x1.7e8f05924d259p-57, 0x1.fb358af7a4884p-2}, - {0x1.1713a36138e19p-57, 0x1.00e5ae5b207abp-1}, - {-0x1.17f9e54e78104p-57, 0x1.04360be7603adp-1}, - {-0x1.17f9e54e78104p-57, 0x1.04360be7603adp-1}, - {0x1.2241edf5fd1f7p-57, 0x1.078bf0533c568p-1}, - {0x1.0d710fcfc4e0dp-55, 0x1.0ae76e2d054fap-1}, - {0x1.0d710fcfc4e0dp-55, 0x1.0ae76e2d054fap-1}, - {0x1.3300f002e836ep-55, 0x1.0e4898611cce1p-1}, - {-0x1.91eee7772c7c2p-55, 0x1.11af823c75aa8p-1}, - {-0x1.91eee7772c7c2p-55, 0x1.11af823c75aa8p-1}, - {0x1.342eb628dba17p-56, 0x1.151c3f6f29612p-1}, - {0x1.89df1568ca0bp-55, 0x1.188ee40f23ca6p-1}, - {0x1.89df1568ca0bp-55, 0x1.188ee40f23ca6p-1}, - {0x1.59bddae1ccce2p-56, 0x1.1c07849ae6007p-1}, - {-0x1.2164ff40e9817p-56, 0x1.1f8635fc61659p-1}, - {-0x1.2164ff40e9817p-56, 0x1.1f8635fc61659p-1}, - {-0x1.fcc8dbccc25cbp-57, 0x1.230b0d8bebc98p-1}, - {0x1.e0efadd9db02bp-55, 0x1.269621134db92p-1}, - {0x1.e0efadd9db02bp-55, 0x1.269621134db92p-1}, - {-0x1.6a0c343be95dcp-56, 0x1.2a2786d0ec107p-1}, - {-0x1.b941ee770436bp-56, 0x1.2dbf557b0df43p-1}, - {-0x1.b941ee770436bp-56, 0x1.2dbf557b0df43p-1}, - {0x1.6c3a5f12642c9p-57, 0x1.315da4434068bp-1}, - {0x1.6c3a5f12642c9p-57, 0x1.315da4434068bp-1}, - {-0x1.f01ab6065515cp-56, 0x1.35028ad9d8c86p-1}, - {0x1.21512aa596ea3p-55, 0x1.38ae2171976e7p-1}, - {0x1.21512aa596ea3p-55, 0x1.38ae2171976e7p-1}, - {0x1.1930603d87b6ep-56, 0x1.3c6080c36bfb5p-1}, - {0x1.1930603d87b6ep-56, 0x1.3c6080c36bfb5p-1}, - {0x1.86cf0f38b461ap-57, 0x1.4019c2125ca93p-1}, - {-0x1.84f481051f71ap-56, 0x1.43d9ff2f923c5p-1}, - {-0x1.84f481051f71ap-56, 0x1.43d9ff2f923c5p-1}, - {0x1.2541aca7d5844p-55, 0x1.47a1527e8a2d3p-1}, - {0x1.2541aca7d5844p-55, 0x1.47a1527e8a2d3p-1}, - {0x1.c457b531506f6p-55, 0x1.4b6fd6f970c1fp-1}, - {0x1.c457b531506f6p-55, 0x1.4b6fd6f970c1fp-1}, - {0x1.d749362382a77p-56, 0x1.4f45a835a4e19p-1}, - {0x1.d749362382a77p-56, 0x1.4f45a835a4e19p-1}, - {0x1.988ba4aea614dp-56, 0x1.5322e26867857p-1}, - {0x1.988ba4aea614dp-56, 0x1.5322e26867857p-1}, - {0x1.80bff3303dd48p-55, 0x1.5707a26bb8c66p-1}, - {0x1.80bff3303dd48p-55, 0x1.5707a26bb8c66p-1}, - {-0x1.6714fbcd8135bp-55, 0x1.5af405c3649ep-1}, - {-0x1.6714fbcd8135bp-55, 0x1.5af405c3649ep-1}, - {0x1.1c066d235ee63p-56, 0x1.5ee82aa24192p-1}, - {0.0, 0.0}, -}; - -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS -// Extra errors from P is from using x^2 to reduce evaluation latency. -constexpr double P_ERR = 0x1.0p-49; - -alignas(16) constexpr LogRR LOG2_TABLE = { - // -log2(r) with 128-bit precision generated by SageMath with: - // def format_hex(value): - // l = hex(value)[2:] - // n = 8 - // x = [l[i:i + n] for i in range(0, len(l), n)] - // return "0x" + "'".join(x) + "_u128" - // for i in range(1, 127): - // r = 2^-8 * ceil( 2^8 * (1 - 2^(-8)) / (1 + i*2^(-7)) ); - // s, m, e = RealField(128)(r).log2().sign_mantissa_exponent(); - // print("{Sign::POS,", e, ", format_hex(m), "},"); - /* .step_1 = */ { - {Sign::POS, 0, 0_u128}, - {Sign::POS, -134, 0xb963dd10'7b993ada'e8c25163'0adb856a_u128}, - {Sign::POS, -133, 0xba1f7430'f9aab1b2'a41b08fb'e05f82d0_u128}, - {Sign::POS, -132, 0x8c25c726'2b57c149'1f06c085'bc1b865d_u128}, - {Sign::POS, -132, 0xbb9ca64e'cac6aaef'2e1c07f0'438ebac0_u128}, - {Sign::POS, -132, 0xeb75e8f8'ff5ff022'aacc0e21'd6541224_u128}, - {Sign::POS, -131, 0x8dd99530'02a4e866'31514aef'39ce6303_u128}, - {Sign::POS, -131, 0xa62b07f3'457c4070'50799bea'aab2940c_u128}, - {Sign::POS, -131, 0xbeb024b6'7dda6339'da288fc6'15a727dc_u128}, - {Sign::POS, -131, 0xcb0657cd'5dbe4f6f'22dbbace'd44516ce_u128}, - {Sign::POS, -131, 0xe3da945b'878e27d0'd939dcee'cdd9ce05_u128}, - {Sign::POS, -131, 0xfce4aee0'e88b2749'9596a8e2'e84c8f45_u128}, - {Sign::POS, -130, 0x84bf1c67'3032495d'243efd93'25954cfe_u128}, - {Sign::POS, -130, 0x916d6e15'59a4b696'91d79938'e7226384_u128}, - {Sign::POS, -130, 0x9e37db28'66f2850b'22563c9e'd9462091_u128}, - {Sign::POS, -130, 0xa4a7c31d'c6f9a5d5'3a53ca11'81015ada_u128}, - {Sign::POS, -130, 0xb19d45fa'1be70855'3eb8023e'ed65d601_u128}, - {Sign::POS, -130, 0xb823018e'3cfc25f0'ce5cabbd'2d753d9b_u128}, - {Sign::POS, -130, 0xc544c055'fde99333'54dbf16f'b0695ee3_u128}, - {Sign::POS, -130, 0xcbe0e589'e3f6042d'5196a85a'067c6739_u128}, - {Sign::POS, -130, 0xd930124b'ea9a2c66'f349845e'48955078_u128}, - {Sign::POS, -130, 0xdfe33d3f'ffa66037'815ef705'cfaef035_u128}, - {Sign::POS, -130, 0xed61169f'220e97f2'2ba704dc'aa76f41d_u128}, - {Sign::POS, -130, 0xf42be9e9'b09b3def'2062f36b'c14d0d93_u128}, - {Sign::POS, -129, 0x80ecdde7'd30ea2ed'13288019'4144b02b_u128}, - {Sign::POS, -129, 0x845e706c'afd1bf61'54880de6'3812fd49_u128}, - {Sign::POS, -129, 0x8b4e029b'1f8ac391'a87c02ea'f36e2c29_u128}, - {Sign::POS, -129, 0x8ecc164e'a93841ae'9804237e'c8d9431d_u128}, - {Sign::POS, -129, 0x924e6958'9e6b6268'20f81ca9'5d9e7968_u128}, - {Sign::POS, -129, 0x995ff71b'8773432d'124bc6f1'acf95dc4_u128}, - {Sign::POS, -129, 0x9cef470a'acfb7bf9'5a5e8e21'bff3336b_u128}, - {Sign::POS, -129, 0xa08300be'1f651473'4e53fa33'29f65894_u128}, - {Sign::POS, -129, 0xa7b7dd96'762cc3c7'2742d729'6a39eed6_u128}, - {Sign::POS, -129, 0xab591735'abc724e4'f359c554'4bc5e134_u128}, - {Sign::POS, -129, 0xaefee78f'75707221'6b6c874d'd96e1d75_u128}, - {Sign::POS, -129, 0xb2a95a4c'c313bb59'21006678'c0a5c390_u128}, - {Sign::POS, -129, 0xb6587b43'2e47501b'6d40900b'25024b32_u128}, - {Sign::POS, -129, 0xbdc4f816'7955698f'89e2eb55'3b279b3d_u128}, - {Sign::POS, -129, 0xc1826c86'08fe9951'd58525aa'd392ca50_u128}, - {Sign::POS, -129, 0xc544c055'fde99333'54dbf16f'b0695ee3_u128}, - {Sign::POS, -129, 0xc90c0049'26e9dbfb'88d5eae3'326327bb_u128}, - {Sign::POS, -129, 0xccd83954'b6359379'46dfa05b'ddfded8c_u128}, - {Sign::POS, -129, 0xd47fcb8c'0852f0c0'bfe9dbeb'f2e8a45e_u128}, - {Sign::POS, -129, 0xd85b3fa7'a3407fa8'7b11f1c5'160c515c_u128}, - {Sign::POS, -129, 0xdc3be2bd'8d837f7f'1339e567'7ec44dd0_u128}, - {Sign::POS, -129, 0xe021c2cf'17ed9bdb'ea2b8c7b'b0ee9c8b_u128}, - {Sign::POS, -129, 0xe40cee16'a2ff21c4'aec56233'2791fe38_u128}, - {Sign::POS, -129, 0xe7fd7308'd6895b14'71682eba'cca79cfa_u128}, - {Sign::POS, -129, 0xebf36055'e1abc61e'a5ad5ce9'fb5a7bb6_u128}, - {Sign::POS, -129, 0xefeec4ea'c371584e'32251905'31a852c5_u128}, - {Sign::POS, -129, 0xf3efaff2'9c559a77'da8ad649'da21eab0_u128}, - {Sign::POS, -129, 0xf7f630d8'08fc2ada'4c3e2ea7'c15c3d1e_u128}, - {Sign::POS, -129, 0xfc025746'86680cc6'bcb9bfa9'852e0d35_u128}, - {Sign::POS, -128, 0x800a1995'f0019518'ce032f41'd1e774e8_u128}, - {Sign::POS, -128, 0x8215ea5c'd3e4c4c7'9b39ffee'bc29372a_u128}, - {Sign::POS, -128, 0x8424a633'5c777e0b'87f95f1b'efb6f806_u128}, - {Sign::POS, -128, 0x86365578'62acb7ce'b987b42e'3bb332a1_u128}, - {Sign::POS, -128, 0x884b00ae'f726cec5'139a7ba8'3bf2d136_u128}, - {Sign::POS, -128, 0x8a62b07f'3457c407'050799be'aaab2941_u128}, - {Sign::POS, -128, 0x8c7d6db7'169e0cda'8bd74461'7e9b7d52_u128}, - {Sign::POS, -128, 0x8e9b414b'5a92a606'046ad444'333ceb10_u128}, - {Sign::POS, -128, 0x90bc3458'61bf3d52'ef4c737f'ba4f5d66_u128}, - {Sign::POS, -128, 0x92e05023'1df57d6f'ae441c09'd761c549_u128}, - {Sign::POS, -128, 0x95079e1a'0382dc79'6e36aa9c'e90a3879_u128}, - {Sign::POS, -128, 0x973227d6'027ebd8a'0efca1a1'84e93809_u128}, - {Sign::POS, -128, 0x973227d6'027ebd8a'0efca1a1'84e93809_u128}, - {Sign::POS, -128, 0x995ff71b'8773432d'124bc6f1'acf95dc4_u128}, - {Sign::POS, -128, 0x9b9115db'83a3dd2d'352bea51'e58ea9e8_u128}, - {Sign::POS, -128, 0x9dc58e34'7d37696d'266d6cdc'959153bc_u128}, - {Sign::POS, -128, 0x9ffd6a73'a78eaf35'4527d82c'8214ddca_u128}, - {Sign::POS, -128, 0xa238b516'0413106e'404cabb7'6d600e3c_u128}, - {Sign::POS, -128, 0xa238b516'0413106e'404cabb7'6d600e3c_u128}, - {Sign::POS, -128, 0xa47778c9'8bcc86a1'cab7d2ec'23f0eef3_u128}, - {Sign::POS, -128, 0xa6b9c06e'6211646b'761c48dd'859de2d3_u128}, - {Sign::POS, -128, 0xa8ff9718'10a5e181'7fd3b7d7'e5d148bb_u128}, - {Sign::POS, -128, 0xab49080e'cda53208'c27c6780'd92b4d11_u128}, - {Sign::POS, -128, 0xad961ed0'cb91d406'db502402'c94092cd_u128}, - {Sign::POS, -128, 0xad961ed0'cb91d406'db502402'c94092cd_u128}, - {Sign::POS, -128, 0xafe6e713'93eeda29'3432ef6b'732b6843_u128}, - {Sign::POS, -128, 0xb23b6cc5'6cc84c99'bb324da7'e046e792_u128}, - {Sign::POS, -128, 0xb493bc0e'c9954243'b21709ce'430c8e24_u128}, - {Sign::POS, -128, 0xb493bc0e'c9954243'b21709ce'430c8e24_u128}, - {Sign::POS, -128, 0xb6efe153'c7e319f6'e91ad16e'cff10111_u128}, - {Sign::POS, -128, 0xb94fe935'b83e3eb5'ce31e481'cd797e79_u128}, - {Sign::POS, -128, 0xbbb3e094'b3d228d3'da3e961a'96c580fa_u128}, - {Sign::POS, -128, 0xbbb3e094'b3d228d3'da3e961a'96c580fa_u128}, - {Sign::POS, -128, 0xbe1bd491'3f3fda43'f396598a'ae91499a_u128}, - {Sign::POS, -128, 0xc087d28d'fb2febb8'ae4cceb0'f621941b_u128}, - {Sign::POS, -128, 0xc087d28d'fb2febb8'ae4cceb0'f621941b_u128}, - {Sign::POS, -128, 0xc2f7e831'632b6670'6c1855c4'2078f81b_u128}, - {Sign::POS, -128, 0xc56c2367'9b4d206e'169535fb'8bf577c8_u128}, - {Sign::POS, -128, 0xc56c2367'9b4d206e'169535fb'8bf577c8_u128}, - {Sign::POS, -128, 0xc7e49264'4d64237e'3b24cecc'60217942_u128}, - {Sign::POS, -128, 0xca6143a4'9626d820'3dc2687f'cf939696_u128}, - {Sign::POS, -128, 0xca6143a4'9626d820'3dc2687f'cf939696_u128}, - {Sign::POS, -128, 0xcce245f1'031e41fa'0a62e6ad'd1a901a0_u128}, - {Sign::POS, -128, 0xcf67a85f'a1f89a04'5bb6e231'38ad51e1_u128}, - {Sign::POS, -128, 0xcf67a85f'a1f89a04'5bb6e231'38ad51e1_u128}, - {Sign::POS, -128, 0xd1f17a56'21fb01ac'7fc60a51'03092bae_u128}, - {Sign::POS, -128, 0xd47fcb8c'0852f0c0'bfe9dbeb'f2e8a45e_u128}, - {Sign::POS, -128, 0xd47fcb8c'0852f0c0'bfe9dbeb'f2e8a45e_u128}, - {Sign::POS, -128, 0xd712ac0c'f811659d'8e2d7d37'8127d823_u128}, - {Sign::POS, -128, 0xd9aa2c3b'0ea3cbc1'5c1a7f14'b168b365_u128}, - {Sign::POS, -128, 0xd9aa2c3b'0ea3cbc1'5c1a7f14'b168b365_u128}, - {Sign::POS, -128, 0xdc465cd1'55a90942'b7579f0f'8d3d514b_u128}, - {Sign::POS, -128, 0xdc465cd1'55a90942'b7579f0f'8d3d514b_u128}, - {Sign::POS, -128, 0xdee74ee6'4b0c38d3'b087205e'b55aea85_u128}, - {Sign::POS, -128, 0xe18d13ee'805a4de3'424a2623'd60dfb16_u128}, - {Sign::POS, -128, 0xe18d13ee'805a4de3'424a2623'd60dfb16_u128}, - {Sign::POS, -128, 0xe437bdbf'5254459c'4d3a591a'e6854787_u128}, - {Sign::POS, -128, 0xe437bdbf'5254459c'4d3a591a'e6854787_u128}, - {Sign::POS, -128, 0xe6e75e91'b9cca551'8dcdb6b2'4c5c5cdf_u128}, - {Sign::POS, -128, 0xe99c0905'36ece983'33ac7d9e'bba8a53c_u128}, - {Sign::POS, -128, 0xe99c0905'36ece983'33ac7d9e'bba8a53c_u128}, - {Sign::POS, -128, 0xec55d022'd80e3d27'fb2eede4'b59d8959_u128}, - {Sign::POS, -128, 0xec55d022'd80e3d27'fb2eede4'b59d8959_u128}, - {Sign::POS, -128, 0xef14c760'5d60654c'308b4546'66de8f99_u128}, - {Sign::POS, -128, 0xef14c760'5d60654c'308b4546'66de8f99_u128}, - {Sign::POS, -128, 0xf1d902a3'7aaa5085'8383cb0c'e23bebd4_u128}, - {Sign::POS, -128, 0xf1d902a3'7aaa5085'8383cb0c'e23bebd4_u128}, - {Sign::POS, -128, 0xf4a29645'38813c67'64fc87b4'a41f7b70_u128}, - {Sign::POS, -128, 0xf4a29645'38813c67'64fc87b4'a41f7b70_u128}, - {Sign::POS, -128, 0xf7719715'7665f689'3f5d7d82'b65c5686_u128}, - {Sign::POS, -128, 0xf7719715'7665f689'3f5d7d82'b65c5686_u128}, - {Sign::POS, -128, 0xfa461a5e'8f4b759d'6476077b'9fbd41ae_u128}, - {Sign::POS, -128, 0xfa461a5e'8f4b759d'6476077b'9fbd41ae_u128}, - {Sign::POS, -128, 0xfd2035e9'221ef5d0'0e3909ff'd0d61778_u128}, - {Sign::POS, 0, 0_u128}, - }, - // -log2(r) for the second step, generated by SageMath with: - // - // for i in range(-2^6, 2^7 + 1): - // r = 2^-16 * round( 2^16 / (1 + i*2^(-14)) ); - // s, m, e = RealField(128)(r).log2().sign_mantissa_exponent(); - // print("{Sign::NEG," if s == 1 else "{Sign::POS,", e, ", - // format_hex(m), "},"); - /* .step_2 = */ - { - {Sign::NEG, -135, 0xb9061559'18954401'b5cfed58'337e848a_u128}, - {Sign::NEG, -135, 0xb6264958'a3c7fa2b'ffaf2ac1'b1d20910_u128}, - {Sign::NEG, -135, 0xb34671e4'39aa448e'52521a39'50ea2ed8_u128}, - {Sign::NEG, -135, 0xb0668efb'7ef48ab7'f87e1abd'ee10fd95_u128}, - {Sign::NEG, -135, 0xad86a09e'185af0e8'fbd43bbc'c24c5e43_u128}, - {Sign::NEG, -135, 0xaaa6a6cb'aa8d57ce'2f4f5d48'f9796742_u128}, - {Sign::NEG, -135, 0xa7c6a183'da375c3d'3477fd67'c1cab6b3_u128}, - {Sign::NEG, -135, 0xa4e690c6'4c0056f0'7b4d33eb'381fe558_u128}, - {Sign::NEG, -135, 0xa2067492'a48b5c43'3ce25e48'cb498dea_u128}, - {Sign::NEG, -135, 0x9f264ce8'88773bed'70b0fcc9'e4330983_u128}, - {Sign::NEG, -135, 0x9c4619c7'9c5e80bf'bc9e4267'd3189b22_u128}, - {Sign::NEG, -135, 0x9965db2f'84d7705f'5fb3d896'326615c4_u128}, - {Sign::NEG, -135, 0x9685911f'e6740b02'178b5831'1e96d323_u128}, - {Sign::NEG, -135, 0x93a53b98'65c20b2a'006bf8b6'cf73d847_u128}, - {Sign::NEG, -135, 0x90c4da98'a74ae561'7019f6e6'4a580a02_u128}, - {Sign::NEG, -135, 0x8de46e20'4f93c7f6'cb5733cf'0eb4191d_u128}, - {Sign::NEG, -135, 0x8b03f62f'031d9ab8'56148d4f'c5e415b6_u128}, - {Sign::NEG, -135, 0x882372c4'6664feaf'fe5370f4'25872623_u128}, - {Sign::NEG, -135, 0x8542e3e0'1de24ddf'21b72a14'57ee70d6_u128}, - {Sign::NEG, -135, 0x81aa211f'1e332fcf'abff4f89'968bed0b_u128}, - {Sign::NEG, -136, 0xfd92f0cf'88d75f24'86410a67'6480a5a7_u128}, - {Sign::NEG, -136, 0xf7d1886b'2a876289'44280889'021970e4_u128}, - {Sign::NEG, -136, 0xf2100910'6a42bc14'32eb139d'9812090d_u128}, - {Sign::NEG, -136, 0xec4e72be'90cd2d2d'bef9dd41'e8e42810_u128}, - {Sign::NEG, -136, 0xe68cc574'e6e1e5d7'689d08ca'6c7c3eb1_u128}, - {Sign::NEG, -136, 0xe0cb0132'b5338423'01ef259a'7f69821d_u128}, - {Sign::NEG, -136, 0xdb0925f7'446c13a9'e22cea71'b7bb8467_u128}, - {Sign::NEG, -136, 0xd54733c1'dd2d0d04'0e5bb273'03f542fe_u128}, - {Sign::NEG, -136, 0xcf852a91'c80f553f'57453c8d'5dc64ce1_u128}, - {Sign::NEG, -136, 0xc9c30a66'4da33d56'6cc7add1'fc09ef92_u128}, - {Sign::NEG, -136, 0xc400d33e'b67081a7'e678d728'0de1c07f_u128}, - {Sign::NEG, -136, 0xbe3e851a'4af6496d'419bbeb2'239bdc39_u128}, - {Sign::NEG, -136, 0xb87c1ff8'53ab2631'd4676d1d'81755809_u128}, - {Sign::NEG, -136, 0xb2b9a3d8'18fd1349'b69dfef7'ac2e2890_u128}, - {Sign::NEG, -136, 0xacf710b8'e3517548'9f72fa0a'8fccabc0_u128}, - {Sign::NEG, -136, 0xa7346699'fb051978'b8bfe6a3'addb988e_u128}, - {Sign::NEG, -136, 0xa171a57a'a86c3551'67862c8e'c9dcd60d_u128}, - {Sign::NEG, -136, 0x9baecd5a'33d265ee'09bd3370'909e28a6_u128}, - {Sign::NEG, -136, 0x95ebde37'e57aaf84'a96bc611'b991419b_u128}, - {Sign::NEG, -136, 0x9028d813'059f7cdc'a50bb80f'203f0d62_u128}, - {Sign::NEG, -136, 0x8a65baea'dc729ec5'4d36cd47'4f65a317_u128}, - {Sign::NEG, -136, 0x84a286be'b21d4b8c'779be241'ef4874a3_u128}, - {Sign::NEG, -137, 0xfdbe771b'9d803cea'0e76a962'fa65ace3_u128}, - {Sign::NEG, -137, 0xf237b2ae'f4e62e5a'd3d35627'464a5267_u128}, - {Sign::NEG, -137, 0xe6b0c035'fa8b328c'162ef4b0'e838c363_u128}, - {Sign::NEG, -137, 0xdb299faf'3e7cd74f'77bb10b9'76b3b9ca_u128}, - {Sign::NEG, -137, 0xcfa25119'50b77014'209853ce'e70bc58b_u128}, - {Sign::NEG, -137, 0xc41ad472'c12614d3'63f9b57c'baf2e58d_u128}, - {Sign::NEG, -137, 0xb89329ba'1fa2a0fd'4fca1c93'1bd6e6d6_u128}, - {Sign::NEG, -137, 0xad0b50ed'fbf5b265'26d26e43'4a53490a_u128}, - {Sign::NEG, -137, 0xa1834a0c'e5d6a82d'c55e0790'78dc86a0_u128}, - {Sign::NEG, -137, 0x95fb1515'6ceba1b5'f05b9d5b'd28f540b_u128}, - {Sign::NEG, -137, 0x8a72b206'20c97d84'8ef87f1a'11cdb727_u128}, - {Sign::NEG, -138, 0xfdd441bb'21e7b069'9d687011'4c1183cf_u128}, - {Sign::NEG, -138, 0xe6c2c334'99ba16c4'63d514ff'f97e86f3_u128}, - {Sign::NEG, -138, 0xcfb0e875'c7cc5929'11a38190'1eadd883_u128}, - {Sign::NEG, -138, 0xb89eb17b'cabe1857'a9d69d37'bc0a5bac_u128}, - {Sign::NEG, -138, 0xa18c1e43'c10c6898'2dc97c9f'fefd2497_u128}, - {Sign::NEG, -138, 0x8a792eca'c911cf92'0dcdc8af'cb2ac09a_u128}, - {Sign::NEG, -139, 0xe6cbc61c'020c8446'dd454eb3'a1489470_u128}, - {Sign::NEG, -139, 0xb8a47615'0dfe4470'87803586'4d84b319_u128}, - {Sign::NEG, -139, 0x8a7c6d7a'f1de7942'7ce595cc'53b8342c_u128}, - {Sign::NEG, -140, 0xb8a7588f'd29b1baa'4710b590'49899141_u128}, - {Sign::NEG, -141, 0xb8a8c9d8'be9ae994'5957f633'309d74e3_u128}, - {Sign::POS, 0, 0_u128}, - {Sign::POS, -141, 0xb8abac81'ab576f3b'8268aba0'30b1adf6_u128}, - {Sign::POS, -140, 0xb8ad1de1'ac9ea6a5'1511cba2'fb213a10_u128}, - {Sign::POS, -139, 0x8a82eb77'08262500'6379fb9f'd9bc6235_u128}, - {Sign::POS, -139, 0xb8b000b8'c65957cc'b6fe1bf6'01ee27d5_u128}, - {Sign::POS, -139, 0xe6ddcebb'd72d3f7f'8c6e6069'3a14e6d0_u128}, - {Sign::POS, -138, 0x8a862ac3'0095c084'e9bcfd0c'62eaa2ca_u128}, - {Sign::POS, -138, 0xa19dca8e'85918b6d'73b21420'9a5234a7_u128}, - {Sign::POS, -138, 0xb8b5c6c3'5e142a9b'347d4ca3'109fe4db_u128}, - {Sign::POS, -138, 0xcfce1f64'6dca7745'37a62c48'783bb066_u128}, - {Sign::POS, -138, 0xe6e6d474'9883fbe3'0794b643'7fb56344_u128}, - {Sign::POS, -138, 0xfdffe5f6'c232f658'1cb9a45e'd90318e6_u128}, - {Sign::POS, -137, 0x8a8ca9f6'e7762d0f'bc118e5d'bbef7dbc_u128}, - {Sign::POS, -137, 0x96198f2e'5173e93b'b4c0fb95'35907cf8_u128}, - {Sign::POS, -137, 0xa1a6a2a3'113fe246'c051d2c5'f00a9bb9_u128}, - {Sign::POS, -137, 0xad33e456'9918a8d5'55326987'8c1e5110_u128}, - {Sign::POS, -137, 0xb8c1544a'5b4e2caf'bc906750'b0ce372c_u128}, - {Sign::POS, -137, 0xc44ef27f'ca41bdd8'4c50eaa6'3be294b6_u128}, - {Sign::POS, -137, 0xcfdcbef8'58660da1'b6cb28db'8c065b44_u128}, - {Sign::POS, -137, 0xdb6ab9b5'783f2fc5'70479336'830ceb05_u128}, - {Sign::POS, -137, 0xe6f8e2b8'9c629b7a'2a458c83'1f6aeb49_u128}, - {Sign::POS, -137, 0xf2873a03'37772c8a'6489ba5b'd391e206_u128}, - {Sign::POS, -137, 0xfe15bf96'bc35246b'13f6fda5'10aeec3b_u128}, - {Sign::POS, -136, 0x84d239ba'4eb315a9'2f9a0ef9'e8250836_u128}, - {Sign::POS, -136, 0x8a99aacf'26f2a8a7'389019e8'22b70f1e_u128}, - {Sign::POS, -136, 0x9061330a'a04f87ae'308beeff'a12cf669_u128}, - {Sign::POS, -136, 0x9628d26d'7448a43f'9886a71b'25a2085d_u128}, - {Sign::POS, -136, 0x9bf088f8'5c65a56b'70ba9ceb'e0b969c3_u128}, - {Sign::POS, -136, 0xa1b856ac'1236e85b'cd855dc7'05ea2bea_u128}, - {Sign::POS, -136, 0xa7803b89'4f5580e0'7736196b'11afb331_u128}, - {Sign::POS, -136, 0xad483790'cd6339fa'94c99761'b8eab3d8_u128}, - {Sign::POS, -136, 0xb3104ac3'460a9668'6194b8c0'40814736_u128}, - {Sign::POS, -136, 0xb8d87521'72fed130'edde8d24'c7a999cc_u128}, - {Sign::POS, -136, 0xbea0b6ac'0dfbde2f'ea6b01eb'de42f1d0_u128}, - {Sign::POS, -136, 0xc4690f63'd0c66aa1'7ef732b6'9334cf50_u128}, - {Sign::POS, -136, 0xca317f49'752bddae'2ba86275'fcfc2d72_u128}, - {Sign::POS, -136, 0xcffa065d'b50258f6'b56ea44e'185bf99f_u128}, - {Sign::POS, -136, 0xd5c2a4a1'4a28b920'1d5c3bbe'b6902bfe_u128}, - {Sign::POS, -136, 0xdb8b5a14'ee86965f'a2f2bb9e'156b0f37_u128}, - {Sign::POS, -136, 0xe15426b9'5c0c4506'd166eb8d'a06ab5ef_u128}, - {Sign::POS, -136, 0xe71d0a8f'4cb2d60f'97dc7bae'4219de0f_u128}, - {Sign::POS, -136, 0xece60597'7a7c17a8'6c9a8e76'98f416c4_u128}, - {Sign::POS, -136, 0xf2af17d2'9f7295c0'7b3a20aa'5289695e_u128}, - {Sign::POS, -136, 0xf8784141'75a99a93'ddcf578e'e2c2897b_u128}, - {Sign::POS, -136, 0xfe4181e4'b73d2f37'e10ebd96'c3ec30ec_u128}, - {Sign::POS, -135, 0x82056cde'8f290e13'a9b7baec'b34ba577_u128}, - {Sign::POS, -135, 0x8430f56d'5e1edfd1'2da910dc'61c182da_u128}, - {Sign::POS, -135, 0x8715b5a8'f27bed90'faca09dc'7e0ba8b5_u128}, - {Sign::POS, -135, 0x89fa8180'19a2cace'0d723876'173c0947_u128}, - {Sign::POS, -135, 0x8cdf58f3'30b64515'4e6651df'154e8f8c_u128}, - {Sign::POS, -135, 0x8fc43c02'94dd8af3'ee54b77d'3bc34b6d_u128}, - {Sign::POS, -135, 0x92a92aae'a3442c3d'ad07dde9'b5f92cce_u128}, - {Sign::POS, -135, 0x958e24f7'b91a1a53'261aacf9'44b638f0_u128}, - {Sign::POS, -135, 0x98732ade'3393a868'232f5d64'a85b219d_u128}, - {Sign::POS, -135, 0x9b583c62'6fe98bc9'f3a958bb'706093fc_u128}, - {Sign::POS, -135, 0x9e3d5984'cb58dc25'c9eaa059'e7b0333a_u128}, - {Sign::POS, -135, 0xa1228245'a32313cf'1e154029'663243c0_u128}, - {Sign::POS, -135, 0xa407b6a5'548e1006'16515200'e283d006_u128}, - {Sign::POS, -135, 0xa6ecf6a4'3ce4113d'f498168a'3337ca4f_u128}, - {Sign::POS, -135, 0xa9d24242'b973bb63'8a04a89f'0548a10f_u128}, - {Sign::POS, -135, 0xacb79981'27901623'afaad01f'25772805_u128}, - {Sign::POS, -135, 0xaf9cfc5f'e4908d31'c4f47950'543fe0b8_u128}, - {Sign::POS, -135, 0xb2826adf'4dd0f08e'338655e6'77d0d3ec_u128}, - {Sign::POS, -135, 0xb567e4ff'c0b174cc'f8ac2ce1'9d009541_u128}, - {Sign::POS, -135, 0xb84d6ac1'9a96b35c'344d5e7d'd7b2f465_u128}, - {Sign::POS, -135, 0xbb32fc25'38e9aaca'bd6a217f'b4598ec7_u128}, - {Sign::POS, -135, 0xbe18992a'f917bf0e'bc21ff36'8f562b75_u128}, - {Sign::POS, -135, 0xc0fe41d3'3892b9cc'4944139c'cbf2cb9a_u128}, - {Sign::POS, -135, 0xc3e3f61e'54d0ca9c'1369970c'8b67e6b5_u128}, - {Sign::POS, -135, 0xc6c9b60c'ab4c8752'099b370e'2d04a530_u128}, - {Sign::POS, -135, 0xc9af819e'9984ec44'0b81c3d4'8aff589f_u128}, - {Sign::POS, -135, 0xcc9558d4'7cfd5c90'9f22b809'93be311b_u128}, - {Sign::POS, -135, 0xcf7b3bae'b33da265'ac29209c'8d8985ae_u128}, - {Sign::POS, -135, 0xd2612a2d'99d1ef47'3cbb6a52'0292351d_u128}, - {Sign::POS, -135, 0xd5472451'8e4adc56'43de9ae4'0507ef24_u128}, - {Sign::POS, -135, 0xd82d2a1a'ee3d6a97'69677b90'2ea4df3a_u128}, - {Sign::POS, -135, 0xdb133b8a'17430339'db7a3aff'74967bd5_u128}, - {Sign::POS, -135, 0xddf9589f'66f977de'25990c82'a0066ac6_u128}, - {Sign::POS, -135, 0xe0df815b'3b0302dd'0d424aac'f4babf55_u128}, - {Sign::POS, -135, 0xe30c278d'9936c595'f8e3e7eb'5a7bdebb_u128}, - {Sign::POS, -135, 0xe5f264ad'b62d5810'5ef8bf5a'df5deebe_u128}, - {Sign::POS, -135, 0xe8d8ad75'590bdf92'331d1996'5368fc82_u128}, - {Sign::POS, -135, 0xebbf01e4'df85219e'901c30c4'27e358b8_u128}, - {Sign::POS, -135, 0xeea561fc'a7504dc1'aeac7e98'57253b06_u128}, - {Sign::POS, -135, 0xf18bcdbd'0e28fdd7'e2113e58'93ab5b40_u128}, - {Sign::POS, -135, 0xf4724526'71cf3654'9a4efc80'ae977826_u128}, - {Sign::POS, -135, 0xf758c839'30076689'6bf3ba83'19332c9f_u128}, - {Sign::POS, -135, 0xfa3f56f5'a69a68ed'1d732d30'2e75018b_u128}, - {Sign::POS, -135, 0xfd25f15c'33558362'ba179c5d'bcceec01_u128}, - {Sign::POS, -134, 0x80064bb6'9a0533c0'5543f53b'8ad85039_u128}, - {Sign::POS, -134, 0x8179a494'8347996b'e971a556'5b93cb67_u128}, - {Sign::POS, -134, 0x82ed0348'045f379d'5b399644'ba714691_u128}, - {Sign::POS, -134, 0x846067d1'4c3b8982'5079f1e0'ec4b8496_u128}, - {Sign::POS, -134, 0x85d3d230'89ce40b0'6aba4990'a32e8873_u128}, - {Sign::POS, -134, 0x87474265'ec0b4548'e16770c3'a404291c_u128}, - {Sign::POS, -134, 0x88bab871'a1e8b61c'1edb7ffb'1d6b3eab_u128}, - {Sign::POS, -134, 0x8a2e3453'da5ee8cd'603243e1'ba7c7865_u128}, - {Sign::POS, -134, 0x8ba1b60c'c46869f6'57ea5c03'ea4621dd_u128}, - {Sign::POS, -134, 0x8d153d9c'8f01fd4a'd3534cbf'43bd7fd8_u128}, - {Sign::POS, -134, 0x8e88cb03'692a9dbc'62c8c807'5dc91cd5_u128}, - {Sign::POS, -134, 0x8ffc5e41'81e37d9e'04bb70a5'e3db7b85_u128}, - {Sign::POS, -134, 0x916ff757'083006c7'd3875ba3'2159547a_u128}, - {Sign::POS, -134, 0x9286adfc'a91ba28d'5c94c80e'7a8f66b1_u128}, - {Sign::POS, -134, 0x93fa514b'a0517623'52d313c4'7b4f91db_u128}, - {Sign::POS, -134, 0x956dfa72'866fc57d'80829e9f'3957a4c3_u128}, - {Sign::POS, -134, 0x96e1a971'8a824be5'1cd49179'72015ae7_u128}, - {Sign::POS, -134, 0x98555e48'db96fcd2'1af23c29'ef3032da_u128}, - {Sign::POS, -134, 0x99c918f8'a8be040e'e7f7bf24'0be67b80_u128}, - {Sign::POS, -134, 0x9b3cd981'2109c5dc'2bbe3cd4'f7d868fa_u128}, - {Sign::POS, -134, 0x9cb09fe2'738edf14'8c75d6a4'c5ae460d_u128}, - {Sign::POS, -134, 0x9e246c1c'cf642550'750fb989'c9a06186_u128}, - {Sign::POS, -134, 0x9f983e30'63a2a709'de787e24'4901bdf9_u128}, - {Sign::POS, -134, 0xa10c161d'5f65abc0'1ba3205f'f729efa4_u128}, - {Sign::POS, -134, 0xa27ff3e3'f1cab41b'a864d2a0'38fb19cd_u128}, - {Sign::POS, -134, 0xa3f3d784'49f17a11'fb21f083'a5fec56d_u128}, - {Sign::POS, -134, 0xa567c0fe'96fbf109'594c5552'bcc377f5_u128}, - {Sign::POS, -134, 0xa6dbb053'080e45fc'aeb35a35'3fc5a503_u128}, - {Sign::POS, -134, 0xa84fa581'cc4edf9f'67a5c051'30c0f330_u128}, - {Sign::POS, -134, 0xa9c3a08b'12e65e81'4de5cafd'e1caf46f_u128}, - {Sign::POS, -134, 0xab37a16f'0aff9d32'686fce3d'160e88fd_u128}, - {Sign::POS, -134, 0xacaba82d'e3c7b066'de1375b3'af6749a6_u128}, - {Sign::POS, -134, 0xadc2b114'c632da56'24356904'8ac4affe_u128}, - {Sign::POS, -134, 0xaf36c213'19b80ea2'd6796227'dcd39551_u128}, - {Sign::POS, -134, 0xb0aad8ec'cfb38d51'abc92653'86172074_u128}, - {Sign::POS, -134, 0xb21ef5a2'175ac65e'0caac9f1'7896f2ce_u128}, - {Sign::POS, -134, 0xb3931833'1fe56492'1c65a3c7'f828972b_u128}, - {Sign::POS, -134, 0xb50740a0'188d4daa'abdc6644'6a4286d9_u128}, - {Sign::POS, -134, 0xb67b6ee9'308ea27b'2f3bbe8e'8d72abec_u128}, - {Sign::POS, -134, 0xb7efa30e'9727bf11'b67dbdd7'f03d168c_u128}, - }, - // -log2(r) for the third step, generated by SageMath with: - // - // for i in range(-80, 81): - // r = 2^-21 * round( 2^21 / (1 + i*2^(-21)) ); - // s, m, e = RealField(128)(r).log2().sign_mantissa_exponent(); - // print("{Sign::NEG," if (s == 1) else "{Sign::POS,", e, ", - // format_hex(m), "},"); - /* .step_3 = */ - { - {Sign::NEG, -142, 0xe6d3a96b'978fc16e'26f2c63c'0827ccbb_u128}, - {Sign::NEG, -142, 0xe3f107a9'fbfc50ca'4b56fe66'7c8ec091_u128}, - {Sign::NEG, -142, 0xe10e65d1'4b937265'647d7618'1aec10fc_u128}, - {Sign::NEG, -142, 0xde2bc3e1'8653b4f5'99e8f4d5'379eca79_u128}, - {Sign::NEG, -142, 0xdb4921da'ac3ba730'f07da899'90c20623_u128}, - {Sign::NEG, -142, 0xd8667fbc'bd49d7cd'4a812184'8531851a_u128}, - {Sign::NEG, -142, 0xd583dd87'b97cd580'679a4d85'4ae13619_u128}, - {Sign::NEG, -142, 0xd2a13b3b'a0d32eff'e4d17407'2487a514_u128}, - {Sign::NEG, -142, 0xcfbe98d8'734b7301'3c90319d'969b54be_u128}, - {Sign::NEG, -142, 0xccdbf65e'30e43039'c6a173b0'9ba301e6_u128}, - {Sign::NEG, -142, 0xc9f953cc'd99bf55e'b8317428'd7d8d06b_u128}, - {Sign::NEG, -142, 0xc716b124'6d715125'23cdb51b'cc2061cd_u128}, - {Sign::NEG, -142, 0xc4340e64'ec62d241'f964fc78'084fd515_u128}, - {Sign::NEG, -142, 0xc1516b8e'566f076a'06474fb1'5ccbb015_u128}, - {Sign::NEG, -142, 0xbe6ec8a0'ab947f51'f525ef6d'0b75b1c3_u128}, - {Sign::NEG, -142, 0xbb8c259b'ebd1c8ae'4e13532d'f7ee8da7_u128}, - {Sign::NEG, -142, 0xb8a98280'17257233'76832500'd72a9027_u128}, - {Sign::NEG, -142, 0xb5c6df4d'2d8e0a95'b14a3d28'5e592ba0_u128}, - {Sign::NEG, -142, 0xb2e43c03'2f0a2089'1e9e9dc9'711f6e20_u128}, - {Sign::NEG, -142, 0xb00198a2'1b9842c1'bc176e97'4f255fac_u128}, - {Sign::NEG, -142, 0xad1ef529'f336fff3'64acf87f'c0f648e6_u128}, - {Sign::NEG, -142, 0xaa3c519a'b5e4e6d1'd0b8a157'4433e1f8_u128}, - {Sign::NEG, -142, 0xa759adf4'63a08610'95f4e785'371c69a9_u128}, - {Sign::NEG, -142, 0xa4770a36'fc686c63'277d5db0'0363a46f_u128}, - {Sign::NEG, -142, 0xa1946662'803b287c'd5cea669'485ec36c_u128}, - {Sign::NEG, -142, 0x9eb1c276'ef174910'cec66fda'04833322_u128}, - {Sign::NEG, -142, 0x9bcf1e74'48fb5cd2'1da36f6e'be3851db_u128}, - {Sign::NEG, -142, 0x98ec7a5a'8de5f273'ab055d83'abfc0d82_u128}, - {Sign::NEG, -142, 0x9609d629'bdd598a8'3cecf110'dbda68e9_u128}, - {Sign::NEG, -142, 0x932731e1'd8c8de22'76bbdb56'5a37e84b_u128}, - {Sign::NEG, -142, 0x90448d82'debe5194'd934c388'57eee4f3_u128}, - {Sign::NEG, -142, 0x8d61e90c'cfb481b1'c27b427b'4fbfc7db_u128}, - {Sign::NEG, -142, 0x8a7f447f'aba9fd2b'6e13de50'2b142b39_u128}, - {Sign::NEG, -142, 0x879c9fdb'729d52b3'f4e40620'6614e2ba_u128}, - {Sign::NEG, -142, 0x84b9fb20'248d10fd'4d320daa'3312ea6c_u128}, - {Sign::NEG, -142, 0x81d7564d'c177c6b9'4aa528fc'9d433c1a_u128}, - {Sign::NEG, -143, 0xfde962c8'92b80533'3c8ad047'559b1622_u128}, - {Sign::NEG, -143, 0xf82418c7'7870a69f'acf765a8'fc5bcc31_u128}, - {Sign::NEG, -143, 0xf25ece98'34168f1a'be238832'edd27f20_u128}, - {Sign::NEG, -143, 0xec99843a'c5a6dc07'02644bfc'a329b708_u128}, - {Sign::NEG, -143, 0xe6d439af'2d1eaac6'c6d05a78'8e614744_u128}, - {Sign::NEG, -143, 0xe10eeef5'6a7b18bc'133fe9cc'57a8c1d0_u128}, - {Sign::NEG, -143, 0xdb49a40d'7db94348'aa4cb429'195fb5dd_u128}, - {Sign::NEG, -143, 0xd58458f7'66d647ce'0951ef23'9abbb959_u128}, - {Sign::NEG, -143, 0xcfbf0db3'25cf43ad'686c430c'89143d35_u128}, - {Sign::NEG, -143, 0xc9f9c240'baa15447'ba79c248'afd42c12_u128}, - {Sign::NEG, -143, 0xc43476a0'254996fd'ad19e0a9'2f115327_u128}, - {Sign::NEG, -143, 0xbe6f2ad1'65c5292f'a8ad6ac3'b0c99520_u128}, - {Sign::NEG, -143, 0xb8a9ded4'7c11283d'd0567d4a'9cc5e6a1_u128}, - {Sign::NEG, -143, 0xb2e492a9'682ab188'01f87c65'4b231443_u128}, - {Sign::NEG, -143, 0xad1f4650'2a0ee26d'd6380b08'358051bc_u128}, - {Sign::NEG, -143, 0xa759f9c8'c1bad84e'a07b024d'26d391f6_u128}, - {Sign::NEG, -143, 0xa194ad13'2f2bb089'6ee868cb'69e3a7d8_u128}, - {Sign::NEG, -143, 0x9bcf602f'725e887d'0a6869ef'f6682f73_u128}, - {Sign::NEG, -143, 0x960a131d'8b507d87'f6a44d55'9ccf3f61_u128}, - {Sign::NEG, -143, 0x9044c5dd'79fead08'72066e1d'30a8e210_u128}, - {Sign::NEG, -143, 0x8a7f786f'3e66345c'75ba3245'b1b856af_u128}, - {Sign::NEG, -143, 0x84ba2ad2'd88430e1'b5ac0204'73ab198f_u128}, - {Sign::NEG, -144, 0xfde9ba10'90ab7feb'41127e3a'88eb6741_u128}, - {Sign::NEG, -144, 0xf25f1e1f'1baffdea'bf807875'22aca1c4_u128}, - {Sign::NEG, -144, 0xe6d481d1'5210167b'af00688b'14fa3adc_u128}, - {Sign::NEG, -144, 0xdb49e527'33c60457'4d72837c'8ab4d1e5_u128}, - {Sign::NEG, -144, 0xcfbf4820'c0cc0236'4e38ac27'bb252090_u128}, - {Sign::NEG, -144, 0xc434aabd'f91c4ad0'da3661f9'292f59e8_u128}, - {Sign::NEG, -144, 0xb8aa0cfe'dcb118de'8fd0af9b'dfd21488_u128}, - {Sign::NEG, -144, 0xad1f6ee3'6b84a716'82ee19a9'abf0bfa5_u128}, - {Sign::NEG, -144, 0xa194d06b'a591302f'3cf68d5b'5369a251_u128}, - {Sign::NEG, -144, 0x960a3197'8ad0eede'bcd34f38'c977647e_u128}, - {Sign::NEG, -144, 0x8a7f9267'1b3e1dda'76eee9c9'605e2143_u128}, - {Sign::NEG, -145, 0xfde9e5b4'ada5efae'aa6a3887'f0c803ab_u128}, - {Sign::NEG, -145, 0xe6d4a5e2'7b136f13'6e25927e'582ac191_u128}, - {Sign::NEG, -145, 0xcfbf6557'9eb92f4a'e2ebcac2'f3a8e9eb_u128}, - {Sign::NEG, -145, 0xb8aa2414'188ba5bb'9d9acc22'd5690751_u128}, - {Sign::NEG, -145, 0xa194e217'e87f47cb'1e12604b'6d4132ef_u128}, - {Sign::NEG, -145, 0x8a7f9f63'0e888add'cf340d2a'cb9b92a9_u128}, - {Sign::NEG, -146, 0xe6d4b7eb'1537c8ae'0dc5e49f'bde3c520_u128}, - {Sign::NEG, -146, 0xb8aa2f9e'b95b9332'0c074c95'57c01188_u128}, - {Sign::NEG, -146, 0x8a7fa5e1'09656009'f0f82818'ff9b654f_u128}, - {Sign::NEG, -147, 0xb8aa3564'0a7c33eb'd4cd6120'78bbe9b0_u128}, - {Sign::NEG, -148, 0xb8aa3846'b33aaecf'f08cf68f'42e09fa0_u128}, - {Sign::POS, 0, 0_u128}, - {Sign::POS, -148, 0xb8aa3e0c'0513f9b1'68bd0fac'df0ddaaf_u128}, - {Sign::POS, -147, 0xb8aa40ee'ae2ec9b3'192af653'dd41575b_u128}, - {Sign::POS, -146, 0x8a7fb2dd'018e4892'3b5c8984'2e540a51_u128}, - {Sign::POS, -146, 0xb8aa46b4'00c0bee3'34ad8ebd'd8b2750c_u128}, - {Sign::POS, -146, 0xe6d4dbfc'54c5dd1b'70b12bd6'98e5be74_u128}, - {Sign::POS, -145, 0x8a7fb95a'feda5c46'08c7e424'efbd90e1_u128}, - {Sign::POS, -145, 0xa1950570'7dd23344'31b8eba7'74a1de77_u128}, - {Sign::POS, -145, 0xb8aa523e'a755fe32'ee400e8c'68838733_u128}, - {Sign::POS, -145, 0xcfbf9fc5'7b7147be'0e71fa0b'5603bc2f_u128}, - {Sign::POS, -145, 0xe6d4ee04'fa2f9a92'7763c919'd8ac65f1_u128}, - {Sign::POS, -145, 0xfdea3cfd'239c815e'232b270b'b6046ec1_u128}, - {Sign::POS, -144, 0x8a7fc656'fbe1c368'106f3919'7e068972_u128}, - {Sign::POS, -144, 0x960a6e8b'bb581acc'4a4a6f40'12941bd9_u128}, - {Sign::POS, -144, 0xa195171c'd0370c34'5bb34c11'20b3e54b_u128}, - {Sign::POS, -144, 0xad1fc00a'3a845cf9'6bb67313'92a3147a_u128}, - {Sign::POS, -144, 0xb8aa6953'fa45d275'2be1268d'cee3c8fc_u128}, - {Sign::POS, -144, 0xc43512fa'0f813201'd84158d5'd50251a9_u128}, - {Sign::POS, -144, 0xcfbfbcfc'7a3c40fa'3765bda1'5d0ef0fa_u128}, - {Sign::POS, -144, 0xdb4a675b'3a7cc4b9'9a5ddb55'f9cc27d9_u128}, - {Sign::POS, -144, 0xe6d51216'5048829b'dcba1c59'3d918775_u128}, - {Sign::POS, -144, 0xf25fbd2d'bba53ffd'648be060'e1e30a95_u128}, - {Sign::POS, -144, 0xfdea68a1'7c98c23b'22658dc2'f1bcf6e8_u128}, - {Sign::POS, -143, 0x84ba8a38'c9946759'48ad5162'fb4a236e_u128}, - {Sign::POS, -143, 0x8a7fe04e'ffad9560'db7fe378'9405ce3a_u128}, - {Sign::POS, -143, 0x90453693'609acde3'91b56e2e'4f2e5ed8_u128}, - {Sign::POS, -143, 0x960a8d05'ec5ef390'f8998880'c3bb4d76_u128}, - {Sign::POS, -143, 0x9bcfe3a6'a2fce918'e2b87805'2f67efee_u128}, - {Sign::POS, -143, 0xa1953a75'8477912b'67df3991'93f707c0_u128}, - {Sign::POS, -143, 0xa75a9172'90d1ce78'e51b89e4'd5d095e1_u128}, - {Sign::POS, -143, 0xad1fe89d'c80e83b1'fcbbee4e'dbf9f47d_u128}, - {Sign::POS, -143, 0xb2e53ff7'2a309387'964fbd58'b168371b_u128}, - {Sign::POS, -143, 0xb8aa977e'b73ae0aa'dea7276c'a7acd135_u128}, - {Sign::POS, -143, 0xbe6fef34'6f304dcd'47d33f7e'7afc83a6_u128}, - {Sign::POS, -143, 0xc4354718'5213bda0'892603b3'77909123_u128}, - {Sign::POS, -143, 0xc9fa9f2a'5fe812d6'9f32660a'a06239fb_u128}, - {Sign::POS, -143, 0xcfbff76a'98b03021'cbcc5504'd7407f6c_u128}, - {Sign::POS, -143, 0xd5854fd8'fc6ef834'9608c44d'06402ebe_u128}, - {Sign::POS, -143, 0xdb4aa875'8b274dc1'ca3db560'4a863477_u128}, - {Sign::POS, -143, 0xe1100140'44dc137c'7a024036'206c37d6_u128}, - {Sign::POS, -143, 0xe6d55a39'29902c17'fc2e9be8'90ff7ee3_u128}, - {Sign::POS, -143, 0xec9ab360'39467a47'ecdc275c'60da1b53_u128}, - {Sign::POS, -143, 0xf2600cb5'7401e0c0'2d6571e9'4056607f_u128}, - {Sign::POS, -143, 0xf8256638'd9c54234'e4664401'fd1ca2a7_u128}, - {Sign::POS, -143, 0xfdeabfea'6a93815a'7dbba7dc'b50b3fd7_u128}, - {Sign::POS, -142, 0x81d80ce5'1337c072'd541f90d'853c794b_u128}, - {Sign::POS, -142, 0x84bab9ec'06ae11c5'b08f6539'2ce8b75b_u128}, - {Sign::POS, -142, 0x879d670a'0fae2600'6e969a29'f8462436_u128}, - {Sign::POS, -142, 0x8a80143f'2e396e7d'cfc8cbca'a2bf130c_u128}, - {Sign::POS, -142, 0x8d62c18b'62515c98'b737e48c'19421e68_u128}, - {Sign::POS, -142, 0x90456eee'abf761ac'2a9689b9'97c50c0b_u128}, - {Sign::POS, -142, 0x93281c69'0b2cef13'52381fcc'c774d66b_u128}, - {Sign::POS, -142, 0x960ac9fa'7ff37629'7910cec1'dd92dc10_u128}, - {Sign::POS, -142, 0x98ed77a3'0a4c684a'0cb5866b'baff34cb_u128}, - {Sign::POS, -142, 0x9bd02562'aa3936d0'9d5c02c8'0c702d11_u128}, - {Sign::POS, -142, 0x9eb2d339'5fbb5318'dddad053'6b56e775_u128}, - {Sign::POS, -142, 0xa1958127'2ad42e7e'a3a9505d'7f71247a_u128}, - {Sign::POS, -142, 0xa4782f2c'0b853a5d'e6dfbd5d'210830d7_u128}, - {Sign::POS, -142, 0xa75add48'01cfe812'c2372f44'7bdcfa45_u128}, - {Sign::POS, -142, 0xaa3d8b7b'0db5a8f9'73099fd5'32c14b05_u128}, - {Sign::POS, -142, 0xad2039c5'2f37ee6e'5951eef4'83de2c37_u128}, - {Sign::POS, -142, 0xb002e826'665829cd'f7abe6ff'6da76f1e_u128}, - {Sign::POS, -142, 0xb2e5969e'b317cc74'f354411e'd47c5d7b_u128}, - {Sign::POS, -142, 0xb5c8452e'157847c0'1428a99b'a8f5911f_u128}, - {Sign::POS, -142, 0xb8aaf3d4'8d7b0d0c'44a7c433'0edff2c8_u128}, - {Sign::POS, -142, 0xbb8da292'1b218db6'91f1306a'84e4e07b_u128}, - {Sign::POS, -142, 0xbe705166'be6d3b1c'2bc58de4'0cdf7b6a_u128}, - {Sign::POS, -142, 0xc1530052'775f869a'648680b2'54df1d99_u128}, - {Sign::POS, -142, 0xc435af55'45f9e18e'b136b5ac'e0d6f74d_u128}, - {Sign::POS, -142, 0xc7185e6f'2a3dbd56'a979e6c4'34fad480_u128}, - {Sign::POS, -142, 0xc9fb0da0'242c8b50'0794df56'00c90a5a_u128}, - {Sign::POS, -142, 0xccddbce8'33c7bcd8'a86d8081'4ac18cf1_u128}, - {Sign::POS, -142, 0xcfc06c47'5910c34e'8b8ac57a'9cca2d56_u128}, - {Sign::POS, -142, 0xd2a31bbd'9409100f'd314c7e0'3140001f_u128}, - {Sign::POS, -142, 0xd585cb4a'e4b2147a'c3d4c40e'20b5ec89_u128}, - {Sign::POS, -142, 0xd8687aef'4b0d41ed'c5351d72'9060644e_u128}, - {Sign::POS, -142, 0xdb4b2aaa'c71c09c7'614162e1'e12e445d_u128}, - {Sign::POS, -142, 0xde2dda7d'58dfdd66'44a652ea'df8ede85_u128}, - {Sign::POS, -142, 0xe1108a67'005a2e29'3eb1e02a'f3e52c3c_u128}, - {Sign::POS, -142, 0xe3f33a67'bd8c6d6f'415335a2'53a82aa2_u128}, - {Sign::POS, -142, 0xe6d5ea7f'90780c97'611abb08'33305fe1_u128}, - }, - // -log2(r) for the fourth step, generated by SageMath with: - // - // for i in range(-65, 65): - // r = 2^-28 * round( 2^28 / (1 + i*2^(-28)) ); - // s, m, e = RealField(128)(r).log2().sign_mantissa_exponent(); - // print("{Sign::NEG," if (s == 1) else "{Sign::POS,", e, ", - // format_hex(m), "},"); - /* .step_4 = */ - { - {Sign::NEG, -149, 0xbb8ce299'0b5d0b90'ef1bffe5'65ce0a46_u128}, - {Sign::NEG, -149, 0xb8aa39b8'07a576e4'bea32445'60ca3d99_u128}, - {Sign::NEG, -149, 0xb5c790d6'd5c354df'8b91f71c'eefa31a2_u128}, - {Sign::NEG, -149, 0xb2e4e7f5'75b6a57b'9096e3d6'84001c0e_u128}, - {Sign::NEG, -149, 0xb0023f13'e77f68b3'086054c7'94367f36_u128}, - {Sign::NEG, -149, 0xad1f9632'2b1d9e80'2d9cb330'94afe4de_u128}, - {Sign::NEG, -149, 0xaa3ced50'409146dd'3afa673c'fb3698f3_u128}, - {Sign::NEG, -149, 0xa75a446e'27da61c4'6b27d803'3e4c6450_u128}, - {Sign::NEG, -149, 0xa4779b8b'e0f8ef2f'f8d36b84'd52a477b_u128}, - {Sign::NEG, -149, 0xa194f2a9'6becef1a'1eab86ae'37c03565_u128}, - {Sign::NEG, -149, 0x9eb249c6'c8b6617d'175e8d56'deb4ce2c_u128}, - {Sign::NEG, -149, 0x9bcfa0e3'f7554653'1d9ae241'436519da_u128}, - {Sign::NEG, -149, 0x98ecf800'f7c99d96'6c0ee71a'dfe44325_u128}, - {Sign::NEG, -149, 0x960a4f1d'ca136741'3d68fc7c'2efb522f_u128}, - {Sign::NEG, -149, 0x9327a63a'6e32a34d'cc5781e8'ac28e749_u128}, - {Sign::NEG, -149, 0x9044fd56'e42751b6'5388d5ce'd3a0f5af_u128}, - {Sign::NEG, -149, 0x8d625473'2bf17275'0dab5588'224c7e4a_u128}, - {Sign::NEG, -149, 0x8a7fab8f'45910584'356d5d59'15c94a70_u128}, - {Sign::NEG, -149, 0x879d02ab'31060ade'057d4871'2c69a6a7_u128}, - {Sign::NEG, -149, 0x84ba59c6'ee50827c'b88970ea'e5341d60_u128}, - {Sign::NEG, -149, 0x81d7b0e2'7d706c5a'89402fcb'bfe331bb_u128}, - {Sign::NEG, -150, 0xfdea0ffb'bccb90e3'649fba08'79ca348b_u128}, - {Sign::NEG, -150, 0xf824be32'22612d78'dccd9edf'bab6f777_u128}, - {Sign::NEG, -150, 0xf25f6c68'2ba1ae69'f066b9aa'4636478e_u128}, - {Sign::NEG, -150, 0xec9a1a9d'd88d13ab'14c7b3cb'21578781_u128}, - {Sign::NEG, -150, 0xe6d4c8d3'29235d30'bf4d347b'528f56e1_u128}, - {Sign::NEG, -150, 0xe10f7708'1d648aef'6553e0c9'e1b70799_u128}, - {Sign::NEG, -150, 0xdb4a253c'b5509cdb'7c385b9b'd80c1375_u128}, - {Sign::NEG, -150, 0xd584d370'f0e792e9'795745ac'402f919d_u128}, - {Sign::NEG, -150, 0xcfbf81a4'd0296d0d'd20d3d8c'2625ac1b_u128}, - {Sign::NEG, -150, 0xc9fa2fd8'53162b3c'fbb6dfa2'97551554_u128}, - {Sign::NEG, -150, 0xc434de0b'79adcd6b'6bb0c62c'a2867d91_u128}, - {Sign::NEG, -150, 0xbe6f8c3e'43f0538d'9757893d'57e40877_u128}, - {Sign::NEG, -150, 0xb8aa3a70'b1ddbd97'f407bebd'c8f8c28e_u128}, - {Sign::NEG, -150, 0xb2e4e8a2'c3760b7e'f71dfa6d'08b016be_u128}, - {Sign::NEG, -150, 0xad1f96d4'78b93d37'15f6cde0'2b5543ce_u128}, - {Sign::NEG, -150, 0xa75a4505'd1a752b4'c5eec882'4692d1e9_u128}, - {Sign::NEG, -150, 0xa194f336'ce404bec'7c627794'7172081a_u128}, - {Sign::NEG, -150, 0x9bcfa167'6e8428d2'aeae662d'c45a61ce_u128}, - {Sign::NEG, -150, 0x960a4f97'b272e95b'd22f1d3b'59110455_u128}, - {Sign::NEG, -150, 0x9044fdc7'9a0c8d7c'5c412380'4ab83462_u128}, - {Sign::NEG, -150, 0x8a7fabf7'25511528'c240fd95'b5cecb89_u128}, - {Sign::NEG, -150, 0x84ba5a26'54408055'798b2dea'b82fadc4_u128}, - {Sign::NEG, -151, 0xfdea10aa'4db59ded'eef86988'e2227ddb_u128}, - {Sign::NEG, -151, 0xf25f6d07'3a400203'62e1207c'0209b090_u128}, - {Sign::NEG, -151, 0xe6d4c963'6e202cd4'39897891'13ec7bee_u128}, - {Sign::NEG, -151, 0xdb4a25be'e9561e49'5daa6556'5e562909_u128}, - {Sign::NEG, -151, 0xcfbf8219'abe1d64b'b9fcd606'2a84acbd_u128}, - {Sign::NEG, -151, 0xc434de73'b5c354c4'3939b586'c46792b3_u128}, - {Sign::NEG, -151, 0xb8aa3acd'06fa999b'c619ea6a'7a9ee85e_u128}, - {Sign::NEG, -151, 0xad1f9725'9f87a4bb'4b5656ef'9e7a27fd_u128}, - {Sign::NEG, -151, 0xa194f37d'7f6a760b'b3a7d900'83f7239c_u128}, - {Sign::NEG, -151, 0x960a4fd4'a6a30d75'e9c74a33'81c0f016_u128}, - {Sign::NEG, -151, 0x8a7fac2b'15316ae2'd86d7fca'f12ed012_u128}, - {Sign::NEG, -152, 0xfdea1101'962b1c76'd4a6956a'5c863e0f_u128}, - {Sign::NEG, -152, 0xe6d4c9ab'909eeed1'1462ef19'2f547877_u128}, - {Sign::NEG, -152, 0xcfbf8254'19be4ca6'45819d2f'1d72eb8b_u128}, - {Sign::NEG, -152, 0xb8aa3afb'318935c8'3d742790'eedbe719_u128}, - {Sign::NEG, -152, 0xa194f3a0'd7ffaa08'd1ac0d7b'70d74492_u128}, - {Sign::NEG, -152, 0x8a7fac45'0d21a939'd79ac583'75f83d0c_u128}, - {Sign::NEG, -153, 0xe6d4c9cf'a1de665a'49637b2b'ac367e87_u128}, - {Sign::NEG, -153, 0xb8aa3b12'46d08f69'1cc4b5ee'dcc78b35_u128}, - {Sign::NEG, -153, 0x8a7fac52'0919cd43'd43bf48a'42745836_u128}, - {Sign::NEG, -154, 0xb8aa3b1d'd1743f1c'3557bdcf'592619eb_u128}, - {Sign::NEG, -155, 0xb8aa3b23'96c617ae'6bdc2e83'd3ebb0c4_u128}, - {Sign::POS, 0, 0_u128}, - {Sign::POS, -155, 0xb8aa3b2f'2169ca44'2d5b4005'0e44e8ab_u128}, - {Sign::POS, -154, 0xb8aa3b34'e6bba447'b8560371'b8f04afe_u128}, - {Sign::POS, -153, 0x8a7fac6c'010a1f14'c79a43cc'c70459cc_u128}, - {Sign::POS, -153, 0xb8aa3b40'715f59c0'22c25632'f519f77f_u128}, - {Sign::POS, -153, 0xe6d4ca17'c45d8282'42c10a31'4e35fb9e_u128}, - {Sign::POS, -152, 0x8a7fac78'fd024cdb'be5a212e'd7b949e4_u128}, - {Sign::POS, -152, 0xa194f3e7'892a4fde'12dcf94e'f5c5b918_u128}, - {Sign::POS, -152, 0xb8aa3b57'86a6ca76'49781013'e57110ce_u128}, - {Sign::POS, -152, 0xcfbf82c8'f577bcd2'8cba70c0'85c12cb3_u128}, - {Sign::POS, -152, 0xe6d4ca3b'd59d2721'07332f3f'b09328b8_u128}, - {Sign::POS, -152, 0xfdea11b0'2717098f'e3716824'3a9d8b14_u128}, - {Sign::POS, -151, 0x8a7fac92'f4f2b226'a6022054'79b93722_u128}, - {Sign::POS, -151, 0x960a504e'8f041bc3'b5bd7358'52c0d583_u128}, - {Sign::POS, -151, 0xa194f40a'e1bfc1b6'36324863'0b0d812d_u128}, - {Sign::POS, -151, 0xad1f97c7'ed25a415'3ca83f0e'02b823c0_u128}, - {Sign::POS, -151, 0xb8aa3b85'b135c2f7'de66fb46'974bc4fd_u128}, - {Sign::POS, -151, 0xc434df44'2df01e75'30b6254e'23c69fc2_u128}, - {Sign::POS, -151, 0xcfbf8303'6354b6a4'48dd69ba'009b370c_u128}, - {Sign::POS, -151, 0xdb4a26c3'51638b9c'3c247973'83b16af5_u128}, - {Sign::POS, -151, 0xe6d4ca83'f81c9d74'1fd309b8'00678db7_u128}, - {Sign::POS, -151, 0xf25f6e45'577fec43'0930d418'c79378a3_u128}, - {Sign::POS, -151, 0xfdea1207'6f8d7820'0d85967b'2783a12c_u128}, - {Sign::POS, -150, 0x84ba5ae5'2022a091'210c898c'360016ed_u128}, - {Sign::POS, -150, 0x8a7facc6'e4d3a3b0'5e19883e'ef2605ab_u128}, - {Sign::POS, -150, 0x9044fea9'05d9c579'488dacc6'629300ae_u128}, - {Sign::POS, -150, 0x960a508b'833505f7'6b0cdebd'3264e3e3_u128}, - {Sign::POS, -150, 0x9bcfa26e'5ce56536'503b07e7'ff788dc2_u128}, - {Sign::POS, -150, 0xa194f451'92eae341'82bc1435'696a69d1_u128}, - {Sign::POS, -150, 0xa75a4635'25458024'8d33f1be'0e96fb1f_u128}, - {Sign::POS, -150, 0xad1f9819'13f53bea'fa4690c4'8c1b66c9_u128}, - {Sign::POS, -150, 0xb2e4e9fd'5efa16a0'5497e3b5'7dd5fe75_u128}, - {Sign::POS, -150, 0xb8aa3be2'06541050'26cbdf27'7e66cad5_u128}, - {Sign::POS, -150, 0xbe6f8dc7'0a032905'fb8679db'27301625_u128}, - {Sign::POS, -150, 0xc434dfac'6a0760cd'5d6bacbb'1056f6aa_u128}, - {Sign::POS, -150, 0xc9fa3192'2660b7b1'd71f72db'd0c3d936_u128}, - {Sign::POS, -150, 0xcfbf8378'3f0f2dbe'f345c97b'fe230ba2_u128}, - {Sign::POS, -150, 0xd584d55e'b412c300'3c82b004'2ce54751_u128}, - {Sign::POS, -150, 0xdb4a2745'856b7781'3d7a2806'f0403bae_u128}, - {Sign::POS, -150, 0xe10f792c'b3194b4d'80d03540'da2f18ae_u128}, - {Sign::POS, -150, 0xe6d4cb14'3d1c3e70'9128dd98'7b73194f_u128}, - {Sign::POS, -150, 0xec9a1cfc'237450f5'f928291e'63940e14_u128}, - {Sign::POS, -150, 0xf25f6ee4'662182e9'4372220d'20e0e78a_u128}, - {Sign::POS, -150, 0xf824c0cd'0523d455'faaad4c9'407040c7_u128}, - {Sign::POS, -150, 0xfdea12b6'007b4547'a9764fe1'4e20e9e4_u128}, - {Sign::POS, -149, 0x81d7b24f'ac13eae4'ed3c5206'ea4d3942_u128}, - {Sign::POS, -149, 0x84ba5b44'8614c2f4'0c2af218'aea6da27_u128}, - {Sign::POS, -149, 0x879d0439'8e402ad6'f6d912ac'383aaeba_u128}, - {Sign::POS, -149, 0x8a7fad2e'c4962293'7298bf5c'ca8b3d95_u128}, - {Sign::POS, -149, 0x8d625624'2916aa2f'44bc04da'a8808214_u128}, - {Sign::POS, -149, 0x9044ff19'bbc1c1b0'3294f0eb'14683198_u128}, - {Sign::POS, -149, 0x9327a80f'7c97691c'01759268'4ff600c3_u128}, - {Sign::POS, -149, 0x960a5105'6b97a078'76aff941'9c43e8b9_u128}, - {Sign::POS, -149, 0x98ecf9fb'88c267cb'5796367b'39d26c63_u128}, - {Sign::POS, -149, 0x9bcfa2f1'd417bf1a'697a5c2e'6888ddaa_u128}, - {Sign::POS, -149, 0x9eb24be8'4d97a66b'71ae7d89'67b5a2b7_u128}, - {Sign::POS, -149, 0xa194f4de'f5421dc4'3584aecf'760e7b39_u128}, - {Sign::POS, -149, 0xa4779dd5'cb17252a'7a4f0558'd1b0c59e_u128}, - {Sign::POS, -149, 0xa75a46cc'cf16bca4'055f9792'b821c455_u128}, - {Sign::POS, -149, 0xaa3cefc4'0140e436'9c087cff'664ee311_u128}, - {Sign::POS, -149, 0xad1f98bb'61959be8'039bce36'188dfc04_u128}, - {Sign::POS, -149, 0xb00241b2'f014e3be'016ba4e3'0a9d9d21_u128}, - {Sign::POS, -149, 0xb2e4eaaa'acbebbbe'5aca1bc7'77a54d5e_u128}, - {Sign::POS, -149, 0xb5c793a2'979323ee'd5094eb9'9a35d1f0_u128}, - {Sign::POS, -149, 0xb8aa3c9a'b0921c55'357b5aa4'ac49738d_u128}, - }}; - -// > P = fpminimax(log2(1 + x)/x, 3, [|128...|], [-0x1.0002143p-29 , 0x1p-29]); -// > P; -// > dirtyinfnorm(log2(1 + x)/x - P, [-0x1.0002143p-29 , 0x1p-29]); -// 0x1.27ad5...p-121 -constexpr Float128 BIG_COEFFS[4]{ - {Sign::NEG, -129, 0xb8aa3b29'5c2b21e3'3eccf694'0d66bbcc_u128}, - {Sign::POS, -129, 0xf6384ee1'd01febc9'ee39a6d6'49394bb1_u128}, - {Sign::NEG, -128, 0xb8aa3b29'5c17f0bb'be87fed0'67ea2ad5_u128}, - {Sign::POS, -127, 0xb8aa3b29'5c17f0bb'be87fed0'691d3e3f_u128}, -}; - -// Reuse the output of the fast pass range reduction. -// -2^-8 <= m_x < 2^-7 -double log2_accurate(int e_x, int index, double m_x) { - - Float128 sum(static_cast<float>(e_x)); - sum = fputil::quick_add(sum, LOG2_TABLE.step_1[index]); - - Float128 v_f128 = log_range_reduction(m_x, LOG2_TABLE, sum); - - // Polynomial approximation - Float128 p = fputil::quick_mul(v_f128, BIG_COEFFS[0]); - p = fputil::quick_mul(v_f128, fputil::quick_add(p, BIG_COEFFS[1])); - p = fputil::quick_mul(v_f128, fputil::quick_add(p, BIG_COEFFS[2])); - p = fputil::quick_mul(v_f128, fputil::quick_add(p, BIG_COEFFS[3])); - - Float128 r = fputil::quick_add(sum, p); - - return static_cast<double>(r); -} -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS - -} // namespace - -LLVM_LIBC_FUNCTION(double, log2, (double x)) { - using namespace common_constants_internal; - using FPBits_t = typename fputil::FPBits<double>; - - FPBits_t xbits(x); - uint64_t x_u = xbits.uintval(); - - int x_e = -FPBits_t::EXP_BIAS; - - if (LIBC_UNLIKELY(xbits == FPBits_t::one())) { - // log2(1.0) = +0.0 - return 0.0; - } - - if (LIBC_UNLIKELY(xbits.uintval() < FPBits_t::min_normal().uintval() || - xbits.uintval() > FPBits_t::max_normal().uintval())) { - if (x == 0.0) { - // return -Inf and raise FE_DIVBYZERO. - fputil::set_errno_if_required(ERANGE); - fputil::raise_except_if_required(FE_DIVBYZERO); - return FPBits_t::inf(Sign::NEG).get_val(); - } - if (xbits.is_neg() && !xbits.is_nan()) { - fputil::set_errno_if_required(EDOM); - fputil::raise_except_if_required(FE_INVALID); - return FPBits_t::quiet_nan().get_val(); - } - if (xbits.is_inf_or_nan()) { - return x; - } - // Normalize denormal inputs. - xbits = FPBits_t(x * 0x1.0p52); - x_e -= 52; - x_u = xbits.uintval(); - } - - // log2(x) = log2(2^x_e * x_m) - // = x_e + log2(x_m) - // Range reduction for log2(x_m): - // For each x_m, we would like to find r such that: - // -2^-8 <= r * x_m - 1 < 2^-7 - int shifted = static_cast<int>(x_u >> 45); - int index = shifted & 0x7F; - double r = RD[index]; - - // Add unbiased exponent. Add an extra 1 if the 8 leading fractional bits are - // all 1's. - x_e += static_cast<int>((x_u + (1ULL << 45)) >> 52); - double e_x = static_cast<double>(x_e); - - // Set m = 1.mantissa. - uint64_t x_m = (x_u & 0x000F'FFFF'FFFF'FFFFULL) | 0x3FF0'0000'0000'0000ULL; - double m = FPBits_t(x_m).get_val(); - - double u, u_sq; - fputil::DoubleDouble r1; - - // Perform exact range reduction -#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE - u = fputil::multiply_add(r, m, -1.0); // exact -#else - uint64_t c_m = x_m & 0x3FFF'E000'0000'0000ULL; - double c = FPBits_t(c_m).get_val(); - u = fputil::multiply_add(r, m - c, CD[index]); // exact -#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE - - // Exact sum: - // r1.hi + r1.lo = e_x * log(2)_hi - log(r)_hi + u - r1 = fputil::exact_add(LOG_R1[index].hi, u); - - // Error of u_sq = ulp(u^2); - u_sq = u * u; - // Degree-7 minimax polynomial - double p0 = fputil::multiply_add(u, LOG_COEFFS[1], LOG_COEFFS[0]); - double p1 = fputil::multiply_add(u, LOG_COEFFS[3], LOG_COEFFS[2]); - double p2 = fputil::multiply_add(u, LOG_COEFFS[5], LOG_COEFFS[4]); - double p = fputil::polyeval(u_sq, LOG_R1[index].lo, p0, p1, p2); - - r1.lo += p; - - // Quick double-double multiplication: - // r2.hi + r2.lo ~ r1 * log2(e), - // with error bounded by: - // 4*ulp( ulp(r2.hi) ) - fputil::DoubleDouble r2 = fputil::quick_mult(r1, LOG2_E); - fputil::DoubleDouble r3 = fputil::exact_add(e_x, r2.hi); - r3.lo += r2.lo; - - // Overall, if we choose sufficiently large constant C, the total error is - // bounded by (C * ulp(u^2)). - -#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - return r3.hi + r3.lo; -#else - // Total error is bounded by ~ C * ulp(u^2). - double err = u_sq * P_ERR; - // Lower bound from the result - double left = r3.hi + (r3.lo - err); - // Upper bound from the result - double right = r3.hi + (r3.lo + err); - - // Ziv's test if fast pass is accurate enough. - if (left == right) - return left; - - return log2_accurate(x_e, index, u); -#endif // LIBC_MATH_HAS_SKIP_ACCURATE_PASS -} +LLVM_LIBC_FUNCTION(double, log2, (double x)) { return math::log2(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/logbf.cpp b/libc/src/math/generic/logbf.cpp index 0dc0251..e319736 100644 --- a/libc/src/math/generic/logbf.cpp +++ b/libc/src/math/generic/logbf.cpp @@ -7,12 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/math/logbf.h" -#include "src/__support/FPUtil/ManipulationFunctions.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" +#include "src/__support/math/logbf.h" namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(float, logbf, (float x)) { return fputil::logb(x); } +LLVM_LIBC_FUNCTION(float, logbf, (float x)) { return math::logbf(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/logbf128.cpp b/libc/src/math/generic/logbf128.cpp index af83487..e70a04c 100644 --- a/libc/src/math/generic/logbf128.cpp +++ b/libc/src/math/generic/logbf128.cpp @@ -7,12 +7,12 @@ //===----------------------------------------------------------------------===// #include "src/math/logbf128.h" -#include "src/__support/FPUtil/ManipulationFunctions.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" +#include "src/__support/math/logbf128.h" namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(float128, logbf128, (float128 x)) { return fputil::logb(x); } +LLVM_LIBC_FUNCTION(float128, logbf128, (float128 x)) { + return math::logbf128(x); +} } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/logbf16.cpp b/libc/src/math/generic/logbf16.cpp index 6e286a2..bf4bf258 100644 --- a/libc/src/math/generic/logbf16.cpp +++ b/libc/src/math/generic/logbf16.cpp @@ -7,12 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/math/logbf16.h" -#include "src/__support/FPUtil/ManipulationFunctions.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" +#include "src/__support/math/logbf16.h" namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(float16, logbf16, (float16 x)) { return fputil::logb(x); } +LLVM_LIBC_FUNCTION(float16, logbf16, (float16 x)) { return math::logbf16(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/logf.cpp b/libc/src/math/generic/logf.cpp index 4d2947d..863a9378 100644 --- a/libc/src/math/generic/logf.cpp +++ b/libc/src/math/generic/logf.cpp @@ -7,16 +7,7 @@ //===----------------------------------------------------------------------===// #include "src/math/logf.h" -#include "src/__support/FPUtil/FEnvImpl.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/PolyEval.h" -#include "src/__support/FPUtil/except_value_utils.h" -#include "src/__support/FPUtil/multiply_add.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" -#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY -#include "src/__support/macros/properties/cpu_features.h" -#include "src/__support/math/common_constants.h" // Lookup table for (1/f) and log(f) +#include "src/__support/math/logf.h" // Lookup table for (1/f) and log(f) // This is an algorithm for log(x) in single precision which is correctly // rounded for all rounding modes, based on the implementation of log(x) from @@ -52,133 +43,6 @@ namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(float, logf, (float x)) { - using namespace common_constants_internal; - constexpr double LOG_2 = 0x1.62e42fefa39efp-1; - using FPBits = typename fputil::FPBits<float>; - - FPBits xbits(x); - uint32_t x_u = xbits.uintval(); - - int m = -FPBits::EXP_BIAS; - - using fputil::round_result_slightly_down; - using fputil::round_result_slightly_up; - - // Small inputs - if (x_u < 0x4c5d65a5U) { -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - // Hard-to-round cases. - switch (x_u) { - case 0x3f7f4d6fU: // x = 0x1.fe9adep-1f - return round_result_slightly_up(-0x1.659ec8p-9f); - case 0x41178febU: // x = 0x1.2f1fd6p+3f - return round_result_slightly_up(0x1.1fcbcep+1f); -#ifdef LIBC_TARGET_CPU_HAS_FMA - case 0x3f800000U: // x = 1.0f - return 0.0f; -#else - case 0x1e88452dU: // x = 0x1.108a5ap-66f - return round_result_slightly_up(-0x1.6d7b18p+5f); -#endif // LIBC_TARGET_CPU_HAS_FMA - } -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - // Subnormal inputs. - if (LIBC_UNLIKELY(x_u < FPBits::min_normal().uintval())) { - if (x == 0.0f) { - // Return -inf and raise FE_DIVBYZERO - fputil::set_errno_if_required(ERANGE); - fputil::raise_except_if_required(FE_DIVBYZERO); - return FPBits::inf(Sign::NEG).get_val(); - } - // Normalize denormal inputs. - xbits = FPBits(xbits.get_val() * 0x1.0p23f); - m -= 23; - x_u = xbits.uintval(); - } - } else { -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - // Hard-to-round cases. - switch (x_u) { - case 0x4c5d65a5U: // x = 0x1.bacb4ap+25f - return round_result_slightly_down(0x1.1e0696p+4f); - case 0x65d890d3U: // x = 0x1.b121a6p+76f - return round_result_slightly_down(0x1.a9a3f2p+5f); - case 0x6f31a8ecU: // x = 0x1.6351d8p+95f - return round_result_slightly_down(0x1.08b512p+6f); - case 0x7a17f30aU: // x = 0x1.2fe614p+117f - return round_result_slightly_up(0x1.451436p+6f); -#ifndef LIBC_TARGET_CPU_HAS_FMA_DOUBLE - case 0x500ffb03U: // x = 0x1.1ff606p+33f - return round_result_slightly_up(0x1.6fdd34p+4f); - case 0x5cd69e88U: // x = 0x1.ad3d1p+58f - return round_result_slightly_up(0x1.45c146p+5f); - case 0x5ee8984eU: // x = 0x1.d1309cp+62f; - return round_result_slightly_up(0x1.5c9442p+5f); -#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE - } -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - // Exceptional inputs. - if (LIBC_UNLIKELY(x_u > FPBits::max_normal().uintval())) { - if (x_u == 0x8000'0000U) { - // Return -inf and raise FE_DIVBYZERO - fputil::set_errno_if_required(ERANGE); - fputil::raise_except_if_required(FE_DIVBYZERO); - return FPBits::inf(Sign::NEG).get_val(); - } - if (xbits.is_neg() && !xbits.is_nan()) { - // Return NaN and raise FE_INVALID - fputil::set_errno_if_required(EDOM); - fputil::raise_except_if_required(FE_INVALID); - return FPBits::quiet_nan().get_val(); - } - // x is +inf or nan - if (xbits.is_signaling_nan()) { - fputil::raise_except_if_required(FE_INVALID); - return FPBits::quiet_nan().get_val(); - } - - return x; - } - } - -#ifndef LIBC_TARGET_CPU_HAS_FMA - // Returning the correct +0 when x = 1.0 for non-FMA targets with FE_DOWNWARD - // rounding mode. - if (LIBC_UNLIKELY((x_u & 0x007f'ffffU) == 0)) - return static_cast<float>( - static_cast<double>(m + xbits.get_biased_exponent()) * LOG_2); -#endif // LIBC_TARGET_CPU_HAS_FMA - - uint32_t mant = xbits.get_mantissa(); - // Extract 7 leading fractional bits of the mantissa - int index = mant >> 16; - // Add unbiased exponent. Add an extra 1 if the 7 leading fractional bits are - // all 1's. - m += static_cast<int>((x_u + (1 << 16)) >> 23); - - // Set bits to 1.m - xbits.set_biased_exponent(0x7F); - - float u = xbits.get_val(); - double v; -#ifdef LIBC_TARGET_CPU_HAS_FMA_FLOAT - v = static_cast<double>(fputil::multiply_add(u, R[index], -1.0f)); // Exact. -#else - v = fputil::multiply_add(static_cast<double>(u), RD[index], -1.0); // Exact -#endif // LIBC_TARGET_CPU_HAS_FMA_FLOAT - - // Degree-5 polynomial approximation of log generated by Sollya with: - // > P = fpminimax(log(1 + x)/x, 4, [|1, D...|], [-2^-8, 2^-7]); - constexpr double COEFFS[4] = {-0x1.000000000fe63p-1, 0x1.555556e963c16p-2, - -0x1.000028dedf986p-2, 0x1.966681bfda7f7p-3}; - double v2 = v * v; // Exact - double p2 = fputil::multiply_add(v, COEFFS[3], COEFFS[2]); - double p1 = fputil::multiply_add(v, COEFFS[1], COEFFS[0]); - double p0 = LOG_R[index] + v; - double r = fputil::multiply_add(static_cast<double>(m), LOG_2, - fputil::polyeval(v2, p0, p1, p2)); - return static_cast<float>(r); -} +LLVM_LIBC_FUNCTION(float, logf, (float x)) { return math::logf(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/logf16.cpp b/libc/src/math/generic/logf16.cpp index 22e0dc8..7149081 100644 --- a/libc/src/math/generic/logf16.cpp +++ b/libc/src/math/generic/logf16.cpp @@ -7,156 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/math/logf16.h" -#include "hdr/errno_macros.h" -#include "hdr/fenv_macros.h" -#include "src/__support/FPUtil/FEnvImpl.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/PolyEval.h" -#include "src/__support/FPUtil/cast.h" -#include "src/__support/FPUtil/except_value_utils.h" -#include "src/__support/FPUtil/multiply_add.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" -#include "src/__support/macros/optimization.h" -#include "src/__support/macros/properties/cpu_features.h" -#include "src/__support/math/expxf16_utils.h" +#include "src/__support/math/logf16.h" namespace LIBC_NAMESPACE_DECL { -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS -#ifdef LIBC_TARGET_CPU_HAS_FMA_FLOAT -static constexpr size_t N_LOGF16_EXCEPTS = 5; -#else -static constexpr size_t N_LOGF16_EXCEPTS = 11; -#endif - -static constexpr fputil::ExceptValues<float16, N_LOGF16_EXCEPTS> - LOGF16_EXCEPTS = {{ -// (input, RZ output, RU offset, RD offset, RN offset) -#ifndef LIBC_TARGET_CPU_HAS_FMA_FLOAT - // x = 0x1.61cp-13, logf16(x) = -0x1.16p+3 (RZ) - {0x0987U, 0xc858U, 0U, 1U, 0U}, - // x = 0x1.f2p-12, logf16(x) = -0x1.e98p+2 (RZ) - {0x0fc8U, 0xc7a6U, 0U, 1U, 1U}, -#endif - // x = 0x1.4d4p-9, logf16(x) = -0x1.7e4p+2 (RZ) - {0x1935U, 0xc5f9U, 0U, 1U, 0U}, - // x = 0x1.5ep-8, logf16(x) = -0x1.4ecp+2 (RZ) - {0x1d78U, 0xc53bU, 0U, 1U, 0U}, -#ifndef LIBC_TARGET_CPU_HAS_FMA_FLOAT - // x = 0x1.fdp-1, logf16(x) = -0x1.81p-8 (RZ) - {0x3bf4U, 0x9e04U, 0U, 1U, 1U}, - // x = 0x1.fep-1, logf16(x) = -0x1.008p-8 (RZ) - {0x3bf8U, 0x9c02U, 0U, 1U, 0U}, -#endif - // x = 0x1.ffp-1, logf16(x) = -0x1.004p-9 (RZ) - {0x3bfcU, 0x9801U, 0U, 1U, 0U}, - // x = 0x1.ff8p-1, logf16(x) = -0x1p-10 (RZ) - {0x3bfeU, 0x9400U, 0U, 1U, 1U}, -#ifdef LIBC_TARGET_CPU_HAS_FMA_FLOAT - // x = 0x1.4c4p+1, logf16(x) = 0x1.e84p-1 (RZ) - {0x4131U, 0x3ba1U, 1U, 0U, 1U}, -#else - // x = 0x1.75p+2, logf16(x) = 0x1.c34p+0 (RZ) - {0x45d4U, 0x3f0dU, 1U, 0U, 0U}, - // x = 0x1.75p+2, logf16(x) = 0x1.c34p+0 (RZ) - {0x45d4U, 0x3f0dU, 1U, 0U, 0U}, - // x = 0x1.d5p+9, logf16(x) = 0x1.b5cp+2 (RZ) - {0x6354U, 0x46d7U, 1U, 0U, 1U}, -#endif - }}; -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - -LLVM_LIBC_FUNCTION(float16, logf16, (float16 x)) { - using namespace math::expxf16_internal; - using FPBits = fputil::FPBits<float16>; - FPBits x_bits(x); - - uint16_t x_u = x_bits.uintval(); - - // If x <= 0, or x is 1, or x is +inf, or x is NaN. - if (LIBC_UNLIKELY(x_u == 0U || x_u == 0x3c00U || x_u >= 0x7c00U)) { - // log(NaN) = NaN - if (x_bits.is_nan()) { - if (x_bits.is_signaling_nan()) { - fputil::raise_except_if_required(FE_INVALID); - return FPBits::quiet_nan().get_val(); - } - - return x; - } - - // log(+/-0) = −inf - if ((x_u & 0x7fffU) == 0U) { - fputil::raise_except_if_required(FE_DIVBYZERO); - return FPBits::inf(Sign::NEG).get_val(); - } - - if (x_u == 0x3c00U) - return FPBits::zero().get_val(); - - // When x < 0. - if (x_u > 0x8000U) { - fputil::set_errno_if_required(EDOM); - fputil::raise_except_if_required(FE_INVALID); - return FPBits::quiet_nan().get_val(); - } - - // log(+inf) = +inf - return FPBits::inf().get_val(); - } - -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - if (auto r = LOGF16_EXCEPTS.lookup(x_u); LIBC_UNLIKELY(r.has_value())) - return r.value(); -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - - // To compute log(x), we perform the following range reduction: - // x = 2^m * 1.mant, - // log(x) = m * log(2) + log(1.mant). - // To compute log(1.mant), let f be the highest 6 bits including the hidden - // bit, and d be the difference (1.mant - f), i.e., the remaining 5 bits of - // the mantissa, then: - // log(1.mant) = log(f) + log(1.mant / f) - // = log(f) + log(1 + d/f) - // since d/f is sufficiently small. - // We store log(f) and 1/f in the lookup tables LOGF_F and ONE_OVER_F_F - // respectively. - - int m = -FPBits::EXP_BIAS; - - // When x is subnormal, normalize it. - if ((x_u & FPBits::EXP_MASK) == 0U) { - // Can't pass an integer to fputil::cast directly. - constexpr float NORMALIZE_EXP = 1U << FPBits::FRACTION_LEN; - x_bits = FPBits(x_bits.get_val() * fputil::cast<float16>(NORMALIZE_EXP)); - x_u = x_bits.uintval(); - m -= FPBits::FRACTION_LEN; - } - - uint16_t mant = x_bits.get_mantissa(); - // Leading 10 - 5 = 5 bits of the mantissa. - int f = mant >> 5; - // Unbiased exponent. - m += x_u >> FPBits::FRACTION_LEN; - - // Set bits to 1.mant instead of 2^m * 1.mant. - x_bits.set_biased_exponent(FPBits::EXP_BIAS); - float mant_f = x_bits.get_val(); - // v = 1.mant * 1/f - 1 = d/f - float v = fputil::multiply_add(mant_f, ONE_OVER_F_F[f], -1.0f); - - // Degree-3 minimax polynomial generated by Sollya with the following - // commands: - // > display = hexadecimal; - // > P = fpminimax(log(1 + x)/x, 2, [|SG...|], [-2^-5, 2^-5]); - // > x * P; - float log1p_d_over_f = - v * fputil::polyeval(v, 0x1p+0f, -0x1.001804p-1f, 0x1.557ef6p-2f); - // log(1.mant) = log(f) + log(1 + d/f) - float log_1_mant = LOGF_F[f] + log1p_d_over_f; - return fputil::cast<float16>( - fputil::multiply_add(static_cast<float>(m), LOGF_2, log_1_mant)); -} +LLVM_LIBC_FUNCTION(float16, logf16, (float16 x)) { return math::logf16(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/sinf.cpp b/libc/src/math/generic/sinf.cpp index c362628..648d57b 100644 --- a/libc/src/math/generic/sinf.cpp +++ b/libc/src/math/generic/sinf.cpp @@ -7,176 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/math/sinf.h" -#include "src/__support/FPUtil/BasicOperations.h" -#include "src/__support/FPUtil/FEnvImpl.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/PolyEval.h" -#include "src/__support/FPUtil/multiply_add.h" -#include "src/__support/FPUtil/rounding_mode.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" -#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY -#include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA - -#if defined(LIBC_MATH_HAS_SKIP_ACCURATE_PASS) && \ - defined(LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT) && \ - defined(LIBC_TARGET_CPU_HAS_FMA_FLOAT) - -#include "src/__support/math/sincosf_float_eval.h" +#include "src/__support/math/sinf.h" namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(float, sinf, (float x)) { - return math::sincosf_float_eval::sincosf_eval</*IS_SIN*/ true>(x); -} - -} // namespace LIBC_NAMESPACE_DECL - -#else // !LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT - -#include "src/__support/math/sincosf_utils.h" - -#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE -#include "src/__support/math/range_reduction_fma.h" -#else // !LIBC_TARGET_CPU_HAS_FMA_DOUBLE -#include "src/__support/math/range_reduction.h" -#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE - -namespace LIBC_NAMESPACE_DECL { - -LLVM_LIBC_FUNCTION(float, sinf, (float x)) { - using FPBits = typename fputil::FPBits<float>; - FPBits xbits(x); - - uint32_t x_u = xbits.uintval(); - uint32_t x_abs = x_u & 0x7fff'ffffU; - double xd = static_cast<double>(x); - - // Range reduction: - // For |x| > pi/32, we perform range reduction as follows: - // Find k and y such that: - // x = (k + y) * pi/32 - // k is an integer - // |y| < 0.5 - // For small range (|x| < 2^45 when FMA instructions are available, 2^22 - // otherwise), this is done by performing: - // k = round(x * 32/pi) - // y = x * 32/pi - k - // For large range, we will omit all the higher parts of 32/pi such that the - // least significant bits of their full products with x are larger than 63, - // since sin((k + y + 64*i) * pi/32) = sin(x + i * 2pi) = sin(x). - // - // When FMA instructions are not available, we store the digits of 32/pi in - // chunks of 28-bit precision. This will make sure that the products: - // x * THIRTYTWO_OVER_PI_28[i] are all exact. - // When FMA instructions are available, we simply store the digits of 32/pi in - // chunks of doubles (53-bit of precision). - // So when multiplying by the largest values of single precision, the - // resulting output should be correct up to 2^(-208 + 128) ~ 2^-80. By the - // worst-case analysis of range reduction, |y| >= 2^-38, so this should give - // us more than 40 bits of accuracy. For the worst-case estimation of range - // reduction, see for instances: - // Elementary Functions by J-M. Muller, Chapter 11, - // Handbook of Floating-Point Arithmetic by J-M. Muller et. al., - // Chapter 10.2. - // - // Once k and y are computed, we then deduce the answer by the sine of sum - // formula: - // sin(x) = sin((k + y)*pi/32) - // = sin(y*pi/32) * cos(k*pi/32) + cos(y*pi/32) * sin(k*pi/32) - // The values of sin(k*pi/32) and cos(k*pi/32) for k = 0..31 are precomputed - // and stored using a vector of 32 doubles. Sin(y*pi/32) and cos(y*pi/32) are - // computed using degree-7 and degree-6 minimax polynomials generated by - // Sollya respectively. - - // |x| <= pi/16 - if (LIBC_UNLIKELY(x_abs <= 0x3e49'0fdbU)) { - - // |x| < 0x1.d12ed2p-12f - if (LIBC_UNLIKELY(x_abs < 0x39e8'9769U)) { - if (LIBC_UNLIKELY(x_abs == 0U)) { - // For signed zeros. - return x; - } - // When |x| < 2^-12, the relative error of the approximation sin(x) ~ x - // is: - // |sin(x) - x| / |sin(x)| < |x^3| / (6|x|) - // = x^2 / 6 - // < 2^-25 - // < epsilon(1)/2. - // So the correctly rounded values of sin(x) are: - // = x - sign(x)*eps(x) if rounding mode = FE_TOWARDZERO, - // or (rounding mode = FE_UPWARD and x is - // negative), - // = x otherwise. - // To simplify the rounding decision and make it more efficient, we use - // fma(x, -2^-25, x) instead. - // An exhaustive test shows that this formula work correctly for all - // rounding modes up to |x| < 0x1.c555dep-11f. - // Note: to use the formula x - 2^-25*x to decide the correct rounding, we - // do need fma(x, -2^-25, x) to prevent underflow caused by -2^-25*x when - // |x| < 2^-125. For targets without FMA instructions, we simply use - // double for intermediate results as it is more efficient than using an - // emulated version of FMA. -#if defined(LIBC_TARGET_CPU_HAS_FMA_FLOAT) - return fputil::multiply_add(x, -0x1.0p-25f, x); -#else - return static_cast<float>(fputil::multiply_add(xd, -0x1.0p-25, xd)); -#endif // LIBC_TARGET_CPU_HAS_FMA_FLOAT - } - - // |x| < pi/16. - double xsq = xd * xd; - - // Degree-9 polynomial approximation: - // sin(x) ~ x + a_3 x^3 + a_5 x^5 + a_7 x^7 + a_9 x^9 - // = x (1 + a_3 x^2 + ... + a_9 x^8) - // = x * P(x^2) - // generated by Sollya with the following commands: - // > display = hexadecimal; - // > Q = fpminimax(sin(x)/x, [|0, 2, 4, 6, 8|], [|1, D...|], [0, pi/16]); - double result = - fputil::polyeval(xsq, 1.0, -0x1.55555555554c6p-3, 0x1.1111111085e65p-7, - -0x1.a019f70fb4d4fp-13, 0x1.718d179815e74p-19); - return static_cast<float>(xd * result); - } - -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - if (LIBC_UNLIKELY(x_abs == 0x4619'9998U)) { // x = 0x1.33333p13 - float r = -0x1.63f4bap-2f; - int rounding = fputil::quick_get_round(); - if ((rounding == FE_DOWNWARD && xbits.is_pos()) || - (rounding == FE_UPWARD && xbits.is_neg())) - r = -0x1.63f4bcp-2f; - return xbits.is_neg() ? -r : r; - } -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - - if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) { - if (xbits.is_signaling_nan()) { - fputil::raise_except_if_required(FE_INVALID); - return FPBits::quiet_nan().get_val(); - } - - if (x_abs == 0x7f80'0000U) { - fputil::set_errno_if_required(EDOM); - fputil::raise_except_if_required(FE_INVALID); - } - return x + FPBits::quiet_nan().get_val(); - } - - // Combine the results with the sine of sum formula: - // sin(x) = sin((k + y)*pi/32) - // = sin(y*pi/32) * cos(k*pi/32) + cos(y*pi/32) * sin(k*pi/32) - // = sin_y * cos_k + (1 + cosm1_y) * sin_k - // = sin_y * cos_k + (cosm1_y * sin_k + sin_k) - double sin_k, cos_k, sin_y, cosm1_y; - - sincosf_eval(xd, x_abs, sin_k, cos_k, sin_y, cosm1_y); - - return static_cast<float>(fputil::multiply_add( - sin_y, cos_k, fputil::multiply_add(cosm1_y, sin_k, sin_k))); -} +LLVM_LIBC_FUNCTION(float, sinf, (float x)) { return math::sinf(x); } } // namespace LIBC_NAMESPACE_DECL -#endif // LIBC_MATH_HAS_INTERMEDIATE_COMP_IN_FLOAT diff --git a/libc/src/math/generic/sinf16.cpp b/libc/src/math/generic/sinf16.cpp index 2b57920..6118970 100644 --- a/libc/src/math/generic/sinf16.cpp +++ b/libc/src/math/generic/sinf16.cpp @@ -7,110 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/math/sinf16.h" -#include "hdr/errno_macros.h" -#include "hdr/fenv_macros.h" -#include "src/__support/FPUtil/FEnvImpl.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/cast.h" -#include "src/__support/FPUtil/except_value_utils.h" -#include "src/__support/FPUtil/multiply_add.h" -#include "src/__support/macros/optimization.h" -#include "src/__support/math/sincosf16_utils.h" +#include "src/__support/math/sinf16.h" namespace LIBC_NAMESPACE_DECL { -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS -constexpr size_t N_EXCEPTS = 4; - -constexpr fputil::ExceptValues<float16, N_EXCEPTS> SINF16_EXCEPTS{{ - // (input, RZ output, RU offset, RD offset, RN offset) - {0x2b45, 0x2b43, 1, 0, 1}, - {0x585c, 0x3ba3, 1, 0, 1}, - {0x5cb0, 0xbbff, 0, 1, 0}, - {0x51f5, 0xb80f, 0, 1, 0}, -}}; -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - -LLVM_LIBC_FUNCTION(float16, sinf16, (float16 x)) { - using namespace sincosf16_internal; - using FPBits = fputil::FPBits<float16>; - FPBits xbits(x); - - uint16_t x_u = xbits.uintval(); - uint16_t x_abs = x_u & 0x7fff; - float xf = x; - - // Range reduction: - // For |x| > pi/32, we perform range reduction as follows: - // Find k and y such that: - // x = (k + y) * pi/32 - // k is an integer, |y| < 0.5 - // - // This is done by performing: - // k = round(x * 32/pi) - // y = x * 32/pi - k - // - // Once k and y are computed, we then deduce the answer by the sine of sum - // formula: - // sin(x) = sin((k + y) * pi/32) - // = sin(k * pi/32) * cos(y * pi/32) + - // sin(y * pi/32) * cos(k * pi/32) - -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - // Handle exceptional values - bool x_sign = x_u >> 15; - - if (auto r = SINF16_EXCEPTS.lookup_odd(x_abs, x_sign); - LIBC_UNLIKELY(r.has_value())) - return r.value(); -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - - int rounding = fputil::quick_get_round(); - - // Exhaustive tests show that for |x| <= 0x1.f4p-11, 1ULP rounding errors - // occur. To fix this, the following apply: - if (LIBC_UNLIKELY(x_abs <= 0x13d0)) { - // sin(+/-0) = +/-0 - if (LIBC_UNLIKELY(x_abs == 0U)) - return x; - - // When x > 0, and rounding upward, sin(x) == x. - // When x < 0, and rounding downward, sin(x) == x. - if ((rounding == FE_UPWARD && xbits.is_pos()) || - (rounding == FE_DOWNWARD && xbits.is_neg())) - return x; - - // When x < 0, and rounding upward, sin(x) == (x - 1ULP) - if (rounding == FE_UPWARD && xbits.is_neg()) { - x_u--; - return FPBits(x_u).get_val(); - } - } - - if (xbits.is_inf_or_nan()) { - if (xbits.is_signaling_nan()) { - fputil::raise_except_if_required(FE_INVALID); - return FPBits::quiet_nan().get_val(); - } - - if (xbits.is_inf()) { - fputil::set_errno_if_required(EDOM); - fputil::raise_except_if_required(FE_INVALID); - } - - return x + FPBits::quiet_nan().get_val(); - } - - float sin_k, cos_k, sin_y, cosm1_y; - sincosf16_eval(xf, sin_k, cos_k, sin_y, cosm1_y); - - if (LIBC_UNLIKELY(sin_y == 0 && sin_k == 0)) - return FPBits::zero(xbits.sign()).get_val(); - - // Since, cosm1_y = cos_y - 1, therefore: - // sin(x) = cos_k * sin_y + sin_k + (cosm1_y * sin_k) - return fputil::cast<float16>(fputil::multiply_add( - sin_y, cos_k, fputil::multiply_add(cosm1_y, sin_k, sin_k))); -} +LLVM_LIBC_FUNCTION(float16, sinf16, (float16 x)) { return math::sinf16(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/sinhf.cpp b/libc/src/math/generic/sinhf.cpp index 5f2d0b5..a8f8c71 100644 --- a/libc/src/math/generic/sinhf.cpp +++ b/libc/src/math/generic/sinhf.cpp @@ -7,74 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/math/sinhf.h" -#include "src/__support/FPUtil/FEnvImpl.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/rounding_mode.h" -#include "src/__support/macros/config.h" -#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY -#include "src/__support/math/sinhfcoshf_utils.h" +#include "src/__support/math/sinhf.h" namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(float, sinhf, (float x)) { - using FPBits = typename fputil::FPBits<float>; - FPBits xbits(x); - uint32_t x_abs = xbits.abs().uintval(); - - // When |x| >= 90, or x is inf or nan - if (LIBC_UNLIKELY(x_abs >= 0x42b4'0000U || x_abs <= 0x3da0'0000U)) { - // |x| <= 0.078125 - if (x_abs <= 0x3da0'0000U) { -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - // |x| = 0.0005589424981735646724700927734375 - if (LIBC_UNLIKELY(x_abs == 0x3a12'85ffU)) { - if (fputil::fenv_is_round_to_nearest()) - return x; - } -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - - // |x| <= 2^-26 - if (LIBC_UNLIKELY(x_abs <= 0x3280'0000U)) { - return static_cast<float>( - LIBC_UNLIKELY(x_abs == 0) ? x : (x + 0.25 * x * x * x)); - } - - double xdbl = x; - double x2 = xdbl * xdbl; - // Sollya: fpminimax(sinh(x),[|3,5,7|],[|D...|],[-1/16-1/64;1/16+1/64],x); - // Sollya output: x * (0x1p0 + x^0x1p1 * (0x1.5555555556583p-3 + x^0x1p1 - // * (0x1.111110d239f1fp-7 - // + x^0x1p1 * 0x1.a02b5a284013cp-13))) - // Therefore, output of Sollya = x * pe; - double pe = fputil::polyeval(x2, 0.0, 0x1.5555555556583p-3, - 0x1.111110d239f1fp-7, 0x1.a02b5a284013cp-13); - return static_cast<float>(fputil::multiply_add(xdbl, pe, xdbl)); - } - - if (xbits.is_nan()) - return x + 1.0f; // sNaN to qNaN + signal - - if (xbits.is_inf()) - return x; - - int rounding = fputil::quick_get_round(); - if (xbits.is_neg()) { - if (LIBC_UNLIKELY(rounding == FE_UPWARD || rounding == FE_TOWARDZERO)) - return -FPBits::max_normal().get_val(); - } else { - if (LIBC_UNLIKELY(rounding == FE_DOWNWARD || rounding == FE_TOWARDZERO)) - return FPBits::max_normal().get_val(); - } - - fputil::set_errno_if_required(ERANGE); - fputil::raise_except_if_required(FE_OVERFLOW); - - return x + FPBits::inf(xbits.sign()).get_val(); - } - - // sinh(x) = (e^x - e^(-x)) / 2. - return static_cast<float>( - math::sinhfcoshf_internal::exp_pm_eval</*is_sinh*/ true>(x)); -} +LLVM_LIBC_FUNCTION(float, sinhf, (float x)) { return math::sinhf(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/sinhf16.cpp b/libc/src/math/generic/sinhf16.cpp index f6b5c9b..1dd1501 100644 --- a/libc/src/math/generic/sinhf16.cpp +++ b/libc/src/math/generic/sinhf16.cpp @@ -7,147 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/math/sinhf16.h" -#include "hdr/errno_macros.h" -#include "hdr/fenv_macros.h" -#include "src/__support/FPUtil/FEnvImpl.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/except_value_utils.h" -#include "src/__support/FPUtil/rounding_mode.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" -#include "src/__support/macros/optimization.h" -#include "src/__support/math/expxf16_utils.h" +#include "src/__support/math/sinhf16.h" namespace LIBC_NAMESPACE_DECL { -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS -static constexpr fputil::ExceptValues<float16, 17> SINHF16_EXCEPTS_POS = {{ - // x = 0x1.714p-5, sinhf16(x) = 0x1.714p-5 (RZ) - {0x29c5U, 0x29c5U, 1U, 0U, 1U}, - // x = 0x1.25p-4, sinhf16(x) = 0x1.25p-4 (RZ) - {0x2c94U, 0x2c94U, 1U, 0U, 1U}, - // x = 0x1.f5p-4, sinhf16(x) = 0x1.f64p-4 (RZ) - {0x2fd4U, 0x2fd9U, 1U, 0U, 0U}, - // x = 0x1.b1cp-3, sinhf16(x) = 0x1.b4cp-3 (RZ) - {0x32c7U, 0x32d3U, 1U, 0U, 1U}, - // x = 0x1.6e8p-2, sinhf16(x) = 0x1.764p-2 (RZ) - {0x35baU, 0x35d9U, 1U, 0U, 1U}, - // x = 0x1.6b4p-1, sinhf16(x) = 0x1.8a4p-1 (RZ) - {0x39adU, 0x3a29U, 1U, 0U, 1U}, - // x = 0x1.a58p-1, sinhf16(x) = 0x1.d68p-1 (RZ) - {0x3a96U, 0x3b5aU, 1U, 0U, 1U}, - // x = 0x1.574p+0, sinhf16(x) = 0x1.c78p+0 (RZ) - {0x3d5dU, 0x3f1eU, 1U, 0U, 1U}, - // x = 0x1.648p+1, sinhf16(x) = 0x1.024p+3 (RZ) - {0x4192U, 0x4809U, 1U, 0U, 0U}, - // x = 0x1.cdcp+1, sinhf16(x) = 0x1.26cp+4 (RZ) - {0x4337U, 0x4c9bU, 1U, 0U, 0U}, - // x = 0x1.d0cp+1, sinhf16(x) = 0x1.2d8p+4 (RZ) - {0x4343U, 0x4cb6U, 1U, 0U, 1U}, - // x = 0x1.018p+2, sinhf16(x) = 0x1.bfp+4 (RZ) - {0x4406U, 0x4efcU, 1U, 0U, 0U}, - // x = 0x1.2fcp+2, sinhf16(x) = 0x1.cc4p+5 (RZ) - {0x44bfU, 0x5331U, 1U, 0U, 1U}, - // x = 0x1.4ecp+2, sinhf16(x) = 0x1.75cp+6 (RZ) - {0x453bU, 0x55d7U, 1U, 0U, 0U}, - // x = 0x1.8a4p+2, sinhf16(x) = 0x1.d94p+7 (RZ) - {0x4629U, 0x5b65U, 1U, 0U, 1U}, - // x = 0x1.5fp+3, sinhf16(x) = 0x1.c54p+14 (RZ) - {0x497cU, 0x7715U, 1U, 0U, 1U}, - // x = 0x1.3c8p+1, sinhf16(x) = 0x1.78ap+2 (RZ) - {0x40f2U, 0x45e2U, 1U, 0U, 1U}, -}}; - -static constexpr fputil::ExceptValues<float16, 13> SINHF16_EXCEPTS_NEG = {{ - // x = -0x1.714p-5, sinhf16(x) = -0x1.714p-5 (RZ) - {0xa9c5U, 0xa9c5U, 0U, 1U, 1U}, - // x = -0x1.25p-4, sinhf16(x) = -0x1.25p-4 (RZ) - {0xac94U, 0xac94U, 0U, 1U, 1U}, - // x = -0x1.f5p-4, sinhf16(x) = -0x1.f64p-4 (RZ) - {0xafd4U, 0xafd9U, 0U, 1U, 0U}, - // x = -0x1.6e8p-2, sinhf16(x) = -0x1.764p-2 (RZ) - {0xb5baU, 0xb5d9U, 0U, 1U, 1U}, - // x = -0x1.a58p-1, sinhf16(x) = -0x1.d68p-1 (RZ) - {0xba96U, 0xbb5aU, 0U, 1U, 1U}, - // x = -0x1.cdcp+1, sinhf16(x) = -0x1.26cp+4 (RZ) - {0xc337U, 0xcc9bU, 0U, 1U, 0U}, - // x = -0x1.d0cp+1, sinhf16(x) = -0x1.2d8p+4 (RZ) - {0xc343U, 0xccb6U, 0U, 1U, 1U}, - // x = -0x1.018p+2, sinhf16(x) = -0x1.bfp+4 (RZ) - {0xc406U, 0xcefcU, 0U, 1U, 0U}, - // x = -0x1.2fcp+2, sinhf16(x) = -0x1.cc4p+5 (RZ) - {0xc4bfU, 0xd331U, 0U, 1U, 1U}, - // x = -0x1.4ecp+2, sinhf16(x) = -0x1.75cp+6 (RZ) - {0xc53bU, 0xd5d7U, 0U, 1U, 0U}, - // x = -0x1.8a4p+2, sinhf16(x) = -0x1.d94p+7 (RZ) - {0xc629U, 0xdb65U, 0U, 1U, 1U}, - // x = -0x1.5fp+3, sinhf16(x) = -0x1.c54p+14 (RZ) - {0xc97cU, 0xf715U, 0U, 1U, 1U}, - // x = -0x1.3c8p+1, sinhf16(x) = -0x1.78ap+2 (RZ) - {0xc0f2U, 0xc5e2U, 0U, 1U, 1U}, -}}; -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - -LLVM_LIBC_FUNCTION(float16, sinhf16, (float16 x)) { - using namespace math::expxf16_internal; - using FPBits = fputil::FPBits<float16>; - FPBits x_bits(x); - - uint16_t x_u = x_bits.uintval(); - uint16_t x_abs = x_u & 0x7fffU; - - // When |x| = 0, or -2^(-14) <= x <= -2^(-9), or |x| >= asinh(2^16), or x is - // NaN. - if (LIBC_UNLIKELY(x_abs == 0U || (x_u >= 0x8400U && x_u <= 0xa400U) || - x_abs >= 0x49e5U)) { - // sinh(NaN) = NaN - if (x_bits.is_nan()) { - if (x_bits.is_signaling_nan()) { - fputil::raise_except_if_required(FE_INVALID); - return FPBits::quiet_nan().get_val(); - } - - return x; - } - - // sinh(+/-0) = sinh(+/-0) - if (x_abs == 0U) - return FPBits::zero(x_bits.sign()).get_val(); - - // When |x| >= asinh(2^16). - if (x_abs >= 0x49e5U) { - // sinh(+/-inf) = +/-inf - if (x_bits.is_inf()) - return FPBits::inf(x_bits.sign()).get_val(); - - int rounding_mode = fputil::quick_get_round(); - if (rounding_mode == FE_TONEAREST || - (x_bits.is_pos() && rounding_mode == FE_UPWARD) || - (x_bits.is_neg() && rounding_mode == FE_DOWNWARD)) { - fputil::set_errno_if_required(ERANGE); - fputil::raise_except_if_required(FE_OVERFLOW | FE_INEXACT); - return FPBits::inf(x_bits.sign()).get_val(); - } - return FPBits::max_normal(x_bits.sign()).get_val(); - } - - // When -2^(-14) <= x <= -2^(-9). - if (fputil::fenv_is_round_down()) - return FPBits(static_cast<uint16_t>(x_u + 1)).get_val(); - return FPBits(static_cast<uint16_t>(x_u)).get_val(); - } - -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - if (x_bits.is_pos()) { - if (auto r = SINHF16_EXCEPTS_POS.lookup(x_u); LIBC_UNLIKELY(r.has_value())) - return r.value(); - } else { - if (auto r = SINHF16_EXCEPTS_NEG.lookup(x_u); LIBC_UNLIKELY(r.has_value())) - return r.value(); - } -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - - return eval_sinh_or_cosh</*IsSinh=*/true>(x); -} +LLVM_LIBC_FUNCTION(float16, sinhf16, (float16 x)) { return math::sinhf16(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/sinpif.cpp b/libc/src/math/generic/sinpif.cpp index f3383f1..67e44a7 100644 --- a/libc/src/math/generic/sinpif.cpp +++ b/libc/src/math/generic/sinpif.cpp @@ -7,111 +7,9 @@ //===----------------------------------------------------------------------===// #include "src/math/sinpif.h" -#include "src/__support/FPUtil/FEnvImpl.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/PolyEval.h" -#include "src/__support/FPUtil/multiply_add.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" -#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY -#include "src/__support/math/sincosf_utils.h" +#include "src/__support/math/sinpif.h" namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(float, sinpif, (float x)) { - using FPBits = typename fputil::FPBits<float>; - FPBits xbits(x); - - uint32_t x_u = xbits.uintval(); - uint32_t x_abs = x_u & 0x7fff'ffffU; - double xd = static_cast<double>(x); - - // Range reduction: - // For |x| > 1/32, we perform range reduction as follows: - // Find k and y such that: - // x = (k + y) * 1/32 - // k is an integer - // |y| < 0.5 - // - // This is done by performing: - // k = round(x * 32) - // y = x * 32 - k - // - // Once k and y are computed, we then deduce the answer by the sine of sum - // formula: - // sin(x * pi) = sin((k + y)*pi/32) - // = sin(y*pi/32) * cos(k*pi/32) + cos(y*pi/32) * sin(k*pi/32) - // The values of sin(k*pi/32) and cos(k*pi/32) for k = 0..31 are precomputed - // and stored using a vector of 32 doubles. Sin(y*pi/32) and cos(y*pi/32) are - // computed using degree-7 and degree-6 minimax polynomials generated by - // Sollya respectively. - - // |x| <= 1/16 - if (LIBC_UNLIKELY(x_abs <= 0x3d80'0000U)) { - - if (LIBC_UNLIKELY(x_abs < 0x33CD'01D7U)) { - if (LIBC_UNLIKELY(x_abs == 0U)) { - // For signed zeros. - return x; - } - - // For very small values we can approximate sinpi(x) with x * pi - // An exhaustive test shows that this is accurate for |x| < 9.546391 × - // 10-8 - double xdpi = xd * 0x1.921fb54442d18p1; - return static_cast<float>(xdpi); - } - - // |x| < 1/16. - double xsq = xd * xd; - - // Degree-9 polynomial approximation: - // sinpi(x) ~ x + a_3 x^3 + a_5 x^5 + a_7 x^7 + a_9 x^9 - // = x (1 + a_3 x^2 + ... + a_9 x^8) - // = x * P(x^2) - // generated by Sollya with the following commands: - // > display = hexadecimal; - // > Q = fpminimax(sin(pi * x)/x, [|0, 2, 4, 6, 8|], [|D...|], [0, 1/16]); - double result = fputil::polyeval( - xsq, 0x1.921fb54442d18p1, -0x1.4abbce625bbf2p2, 0x1.466bc675e116ap1, - -0x1.32d2c0b62d41cp-1, 0x1.501ec4497cb7dp-4); - return static_cast<float>(xd * result); - } - - // Numbers greater or equal to 2^23 are always integers or NaN - if (LIBC_UNLIKELY(x_abs >= 0x4B00'0000)) { - - // check for NaN values - if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) { - if (xbits.is_signaling_nan()) { - fputil::raise_except_if_required(FE_INVALID); - return FPBits::quiet_nan().get_val(); - } - - if (x_abs == 0x7f80'0000U) { - fputil::set_errno_if_required(EDOM); - fputil::raise_except_if_required(FE_INVALID); - } - - return x + FPBits::quiet_nan().get_val(); - } - - return FPBits::zero(xbits.sign()).get_val(); - } - - // Combine the results with the sine of sum formula: - // sin(x * pi) = sin((k + y)*pi/32) - // = sin(y*pi/32) * cos(k*pi/32) + cos(y*pi/32) * sin(k*pi/32) - // = sin_y * cos_k + (1 + cosm1_y) * sin_k - // = sin_y * cos_k + (cosm1_y * sin_k + sin_k) - double sin_k, cos_k, sin_y, cosm1_y; - sincospif_eval(xd, sin_k, cos_k, sin_y, cosm1_y); - - if (LIBC_UNLIKELY(sin_y == 0 && sin_k == 0)) - return FPBits::zero(xbits.sign()).get_val(); - - return static_cast<float>(fputil::multiply_add( - sin_y, cos_k, fputil::multiply_add(cosm1_y, sin_k, sin_k))); -} - +LLVM_LIBC_FUNCTION(float, sinpif, (float x)) { return math::sinpif(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/sqrt.cpp b/libc/src/math/generic/sqrt.cpp index 791975e..05717d1 100644 --- a/libc/src/math/generic/sqrt.cpp +++ b/libc/src/math/generic/sqrt.cpp @@ -7,12 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/math/sqrt.h" -#include "src/__support/FPUtil/sqrt.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" +#include "src/__support/math/sqrt.h" namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(double, sqrt, (double x)) { return fputil::sqrt<double>(x); } +LLVM_LIBC_FUNCTION(double, sqrt, (double x)) { return math::sqrt(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/sqrtf16.cpp b/libc/src/math/generic/sqrtf16.cpp index 0aa4a20..d175f69f 100644 --- a/libc/src/math/generic/sqrtf16.cpp +++ b/libc/src/math/generic/sqrtf16.cpp @@ -7,14 +7,9 @@ //===----------------------------------------------------------------------===// #include "src/math/sqrtf16.h" -#include "src/__support/FPUtil/sqrt.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" +#include "src/__support/math/sqrtf16.h" namespace LIBC_NAMESPACE_DECL { -LLVM_LIBC_FUNCTION(float16, sqrtf16, (float16 x)) { - return fputil::sqrt<float16>(x); -} - +LLVM_LIBC_FUNCTION(float16, sqrtf16, (float16 x)) { return math::sqrtf16(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/tan.cpp b/libc/src/math/generic/tan.cpp index 7ea40c9..2e9f809 100644 --- a/libc/src/math/generic/tan.cpp +++ b/libc/src/math/generic/tan.cpp @@ -7,290 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/math/tan.h" -#include "hdr/errno_macros.h" -#include "src/__support/FPUtil/FEnvImpl.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/PolyEval.h" -#include "src/__support/FPUtil/double_double.h" -#include "src/__support/FPUtil/dyadic_float.h" -#include "src/__support/FPUtil/except_value_utils.h" -#include "src/__support/FPUtil/multiply_add.h" -#include "src/__support/FPUtil/rounding_mode.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" -#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY -#include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA -#include "src/__support/math/range_reduction_double_common.h" - -#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE -#include "src/__support/math/range_reduction_double_fma.h" -#else -#include "src/__support/math/range_reduction_double_nofma.h" -#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE +#include "src/__support/math/tan.h" namespace LIBC_NAMESPACE_DECL { -using DoubleDouble = fputil::DoubleDouble; -using Float128 = typename fputil::DyadicFloat<128>; - -namespace { - -LIBC_INLINE double tan_eval(const DoubleDouble &u, DoubleDouble &result) { - // Evaluate tan(y) = tan(x - k * (pi/128)) - // We use the degree-9 Taylor approximation: - // tan(y) ~ P(y) = y + y^3/3 + 2*y^5/15 + 17*y^7/315 + 62*y^9/2835 - // Then the error is bounded by: - // |tan(y) - P(y)| < 2^-6 * |y|^11 < 2^-6 * 2^-66 = 2^-72. - // For y ~ u_hi + u_lo, fully expanding the polynomial and drop any terms - // < ulp(u_hi^3) gives us: - // P(y) = y + y^3/3 + 2*y^5/15 + 17*y^7/315 + 62*y^9/2835 = ... - // ~ u_hi + u_hi^3 * (1/3 + u_hi^2 * (2/15 + u_hi^2 * (17/315 + - // + u_hi^2 * 62/2835))) + - // + u_lo (1 + u_hi^2 * (1 + u_hi^2 * 2/3)) - double u_hi_sq = u.hi * u.hi; // Error < ulp(u_hi^2) < 2^(-6 - 52) = 2^-58. - // p1 ~ 17/315 + u_hi^2 62 / 2835. - double p1 = - fputil::multiply_add(u_hi_sq, 0x1.664f4882c10fap-6, 0x1.ba1ba1ba1ba1cp-5); - // p2 ~ 1/3 + u_hi^2 2 / 15. - double p2 = - fputil::multiply_add(u_hi_sq, 0x1.1111111111111p-3, 0x1.5555555555555p-2); - // q1 ~ 1 + u_hi^2 * 2/3. - double q1 = fputil::multiply_add(u_hi_sq, 0x1.5555555555555p-1, 1.0); - double u_hi_3 = u_hi_sq * u.hi; - double u_hi_4 = u_hi_sq * u_hi_sq; - // p3 ~ 1/3 + u_hi^2 * (2/15 + u_hi^2 * (17/315 + u_hi^2 * 62/2835)) - double p3 = fputil::multiply_add(u_hi_4, p1, p2); - // q2 ~ 1 + u_hi^2 * (1 + u_hi^2 * 2/3) - double q2 = fputil::multiply_add(u_hi_sq, q1, 1.0); - double tan_lo = fputil::multiply_add(u_hi_3, p3, u.lo * q2); - // Overall, |tan(y) - (u_hi + tan_lo)| < ulp(u_hi^3) <= 2^-71. - // And the relative errors is: - // |(tan(y) - (u_hi + tan_lo)) / tan(y) | <= 2*ulp(u_hi^2) < 2^-64 - result = fputil::exact_add(u.hi, tan_lo); - return fputil::multiply_add(fputil::FPBits<double>(u_hi_3).abs().get_val(), - 0x1.0p-51, 0x1.0p-102); -} - -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS -// Accurate evaluation of tan for small u. -[[maybe_unused]] Float128 tan_eval(const Float128 &u) { - Float128 u_sq = fputil::quick_mul(u, u); - - // tan(x) ~ x + x^3/3 + x^5 * 2/15 + x^7 * 17/315 + x^9 * 62/2835 + - // + x^11 * 1382/155925 + x^13 * 21844/6081075 + - // + x^15 * 929569/638512875 + x^17 * 6404582/10854718875 - // Relative errors < 2^-127 for |u| < pi/256. - constexpr Float128 TAN_COEFFS[] = { - {Sign::POS, -127, 0x80000000'00000000'00000000'00000000_u128}, // 1 - {Sign::POS, -129, 0xaaaaaaaa'aaaaaaaa'aaaaaaaa'aaaaaaab_u128}, // 1 - {Sign::POS, -130, 0x88888888'88888888'88888888'88888889_u128}, // 2/15 - {Sign::POS, -132, 0xdd0dd0dd'0dd0dd0d'd0dd0dd0'dd0dd0dd_u128}, // 17/315 - {Sign::POS, -133, 0xb327a441'6087cf99'6b5dd24e'ec0b327a_u128}, // 62/2835 - {Sign::POS, -134, - 0x91371aaf'3611e47a'da8e1cba'7d900eca_u128}, // 1382/155925 - {Sign::POS, -136, - 0xeb69e870'abeefdaf'e606d2e4'd1e65fbc_u128}, // 21844/6081075 - {Sign::POS, -137, - 0xbed1b229'5baf15b5'0ec9af45'a2619971_u128}, // 929569/638512875 - {Sign::POS, -138, - 0x9aac1240'1b3a2291'1b2ac7e3'e4627d0a_u128}, // 6404582/10854718875 - }; - - return fputil::quick_mul( - u, fputil::polyeval(u_sq, TAN_COEFFS[0], TAN_COEFFS[1], TAN_COEFFS[2], - TAN_COEFFS[3], TAN_COEFFS[4], TAN_COEFFS[5], - TAN_COEFFS[6], TAN_COEFFS[7], TAN_COEFFS[8])); -} - -// Calculation a / b = a * (1/b) for Float128. -// Using the initial approximation of q ~ (1/b), then apply 2 Newton-Raphson -// iterations, before multiplying by a. -[[maybe_unused]] Float128 newton_raphson_div(const Float128 &a, Float128 b, - double q) { - Float128 q0(q); - constexpr Float128 TWO(2.0); - b.sign = (b.sign == Sign::POS) ? Sign::NEG : Sign::POS; - Float128 q1 = - fputil::quick_mul(q0, fputil::quick_add(TWO, fputil::quick_mul(b, q0))); - Float128 q2 = - fputil::quick_mul(q1, fputil::quick_add(TWO, fputil::quick_mul(b, q1))); - return fputil::quick_mul(a, q2); -} -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - -} // anonymous namespace - -LLVM_LIBC_FUNCTION(double, tan, (double x)) { - using namespace math::range_reduction_double_internal; - using FPBits = typename fputil::FPBits<double>; - FPBits xbits(x); - - uint16_t x_e = xbits.get_biased_exponent(); - - DoubleDouble y; - unsigned k; - LargeRangeReduction range_reduction_large{}; - - // |x| < 2^16 - if (LIBC_LIKELY(x_e < FPBits::EXP_BIAS + FAST_PASS_EXPONENT)) { - // |x| < 2^-7 - if (LIBC_UNLIKELY(x_e < FPBits::EXP_BIAS - 7)) { - // |x| < 2^-27, |tan(x) - x| < ulp(x)/2. - if (LIBC_UNLIKELY(x_e < FPBits::EXP_BIAS - 27)) { - // Signed zeros. - if (LIBC_UNLIKELY(x == 0.0)) - return x + x; // Make sure it works with FTZ/DAZ. - -#ifdef LIBC_TARGET_CPU_HAS_FMA_DOUBLE - return fputil::multiply_add(x, 0x1.0p-54, x); -#else - if (LIBC_UNLIKELY(x_e < 4)) { - int rounding_mode = fputil::quick_get_round(); - if ((xbits.sign() == Sign::POS && rounding_mode == FE_UPWARD) || - (xbits.sign() == Sign::NEG && rounding_mode == FE_DOWNWARD)) - return FPBits(xbits.uintval() + 1).get_val(); - } - return fputil::multiply_add(x, 0x1.0p-54, x); -#endif // LIBC_TARGET_CPU_HAS_FMA_DOUBLE - } - // No range reduction needed. - k = 0; - y.lo = 0.0; - y.hi = x; - } else { - // Small range reduction. - k = range_reduction_small(x, y); - } - } else { - // Inf or NaN - if (LIBC_UNLIKELY(x_e > 2 * FPBits::EXP_BIAS)) { - if (xbits.is_signaling_nan()) { - fputil::raise_except_if_required(FE_INVALID); - return FPBits::quiet_nan().get_val(); - } - // tan(+-Inf) = NaN - if (xbits.get_mantissa() == 0) { - fputil::set_errno_if_required(EDOM); - fputil::raise_except_if_required(FE_INVALID); - } - return x + FPBits::quiet_nan().get_val(); - } - - // Large range reduction. - k = range_reduction_large.fast(x, y); - } - - DoubleDouble tan_y; - [[maybe_unused]] double err = tan_eval(y, tan_y); - - // Look up sin(k * pi/128) and cos(k * pi/128) -#ifdef LIBC_MATH_HAS_SMALL_TABLES - // Memory saving versions. Use 65-entry table: - auto get_idx_dd = [](unsigned kk) -> DoubleDouble { - unsigned idx = (kk & 64) ? 64 - (kk & 63) : (kk & 63); - DoubleDouble ans = SIN_K_PI_OVER_128[idx]; - if (kk & 128) { - ans.hi = -ans.hi; - ans.lo = -ans.lo; - } - return ans; - }; - DoubleDouble msin_k = get_idx_dd(k + 128); - DoubleDouble cos_k = get_idx_dd(k + 64); -#else - // Fast look up version, but needs 256-entry table. - // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). - DoubleDouble msin_k = SIN_K_PI_OVER_128[(k + 128) & 255]; - DoubleDouble cos_k = SIN_K_PI_OVER_128[(k + 64) & 255]; -#endif // LIBC_MATH_HAS_SMALL_TABLES - - // After range reduction, k = round(x * 128 / pi) and y = x - k * (pi / 128). - // So k is an integer and -pi / 256 <= y <= pi / 256. - // Then tan(x) = sin(x) / cos(x) - // = sin((k * pi/128 + y) / cos((k * pi/128 + y) - // = (cos(y) * sin(k*pi/128) + sin(y) * cos(k*pi/128)) / - // / (cos(y) * cos(k*pi/128) - sin(y) * sin(k*pi/128)) - // = (sin(k*pi/128) + tan(y) * cos(k*pi/128)) / - // / (cos(k*pi/128) - tan(y) * sin(k*pi/128)) - DoubleDouble cos_k_tan_y = fputil::quick_mult(tan_y, cos_k); - DoubleDouble msin_k_tan_y = fputil::quick_mult(tan_y, msin_k); - - // num_dd = sin(k*pi/128) + tan(y) * cos(k*pi/128) - DoubleDouble num_dd = fputil::exact_add<false>(cos_k_tan_y.hi, -msin_k.hi); - // den_dd = cos(k*pi/128) - tan(y) * sin(k*pi/128) - DoubleDouble den_dd = fputil::exact_add<false>(msin_k_tan_y.hi, cos_k.hi); - num_dd.lo += cos_k_tan_y.lo - msin_k.lo; - den_dd.lo += msin_k_tan_y.lo + cos_k.lo; - -#ifdef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - double tan_x = (num_dd.hi + num_dd.lo) / (den_dd.hi + den_dd.lo); - return tan_x; -#else - // Accurate test and pass for correctly rounded implementation. - - // Accurate double-double division - DoubleDouble tan_x = fputil::div(num_dd, den_dd); - - // Simple error bound: |1 / den_dd| < 2^(1 + floor(-log2(den_dd)))). - uint64_t den_inv = (static_cast<uint64_t>(FPBits::EXP_BIAS + 1) - << (FPBits::FRACTION_LEN + 1)) - - (FPBits(den_dd.hi).uintval() & FPBits::EXP_MASK); - - // For tan_x = (num_dd + err) / (den_dd + err), the error is bounded by: - // | tan_x - num_dd / den_dd | <= err * ( 1 + | tan_x * den_dd | ). - double tan_err = - err * fputil::multiply_add(FPBits(den_inv).get_val(), - FPBits(tan_x.hi).abs().get_val(), 1.0); - - double err_higher = tan_x.lo + tan_err; - double err_lower = tan_x.lo - tan_err; - - double tan_upper = tan_x.hi + err_higher; - double tan_lower = tan_x.hi + err_lower; - - // Ziv's rounding test. - if (LIBC_LIKELY(tan_upper == tan_lower)) - return tan_upper; - - Float128 u_f128; - if (LIBC_LIKELY(x_e < FPBits::EXP_BIAS + FAST_PASS_EXPONENT)) - u_f128 = range_reduction_small_f128(x); - else - u_f128 = range_reduction_large.accurate(); - - Float128 tan_u = tan_eval(u_f128); - - auto get_sin_k = [](unsigned kk) -> Float128 { - unsigned idx = (kk & 64) ? 64 - (kk & 63) : (kk & 63); - Float128 ans = SIN_K_PI_OVER_128_F128[idx]; - if (kk & 128) - ans.sign = Sign::NEG; - return ans; - }; - - // cos(k * pi/128) = sin(k * pi/128 + pi/2) = sin((k + 64) * pi/128). - Float128 sin_k_f128 = get_sin_k(k); - Float128 cos_k_f128 = get_sin_k(k + 64); - Float128 msin_k_f128 = get_sin_k(k + 128); - - // num_f128 = sin(k*pi/128) + tan(y) * cos(k*pi/128) - Float128 num_f128 = - fputil::quick_add(sin_k_f128, fputil::quick_mul(cos_k_f128, tan_u)); - // den_f128 = cos(k*pi/128) - tan(y) * sin(k*pi/128) - Float128 den_f128 = - fputil::quick_add(cos_k_f128, fputil::quick_mul(msin_k_f128, tan_u)); - - // tan(x) = (sin(k*pi/128) + tan(y) * cos(k*pi/128)) / - // / (cos(k*pi/128) - tan(y) * sin(k*pi/128)) - // TODO: The initial seed 1.0/den_dd.hi for Newton-Raphson reciprocal can be - // reused from DoubleDouble fputil::div in the fast pass. - Float128 result = newton_raphson_div(num_f128, den_f128, 1.0 / den_dd.hi); - - // TODO: Add assertion if Ziv's accuracy tests fail in debug mode. - // https://github.com/llvm/llvm-project/issues/96452. - return static_cast<double>(result); - -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS -} +LLVM_LIBC_FUNCTION(double, tan, (double x)) { return math::tan(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/math/generic/tanf.cpp b/libc/src/math/generic/tanf.cpp index a8c557b..aee5a6c 100644 --- a/libc/src/math/generic/tanf.cpp +++ b/libc/src/math/generic/tanf.cpp @@ -7,146 +7,10 @@ //===----------------------------------------------------------------------===// #include "src/math/tanf.h" -#include "src/__support/FPUtil/FEnvImpl.h" -#include "src/__support/FPUtil/FPBits.h" -#include "src/__support/FPUtil/PolyEval.h" -#include "src/__support/FPUtil/except_value_utils.h" -#include "src/__support/FPUtil/multiply_add.h" -#include "src/__support/FPUtil/nearest_integer.h" -#include "src/__support/common.h" -#include "src/__support/macros/config.h" -#include "src/__support/macros/optimization.h" // LIBC_UNLIKELY -#include "src/__support/macros/properties/cpu_features.h" // LIBC_TARGET_CPU_HAS_FMA -#include "src/__support/math/sincosf_utils.h" +#include "src/__support/math/tanf.h" namespace LIBC_NAMESPACE_DECL { -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS -// Exceptional cases for tanf. -constexpr size_t N_EXCEPTS = 6; - -constexpr fputil::ExceptValues<float, N_EXCEPTS> TANF_EXCEPTS{{ - // (inputs, RZ output, RU offset, RD offset, RN offset) - // x = 0x1.ada6aap27, tan(x) = 0x1.e80304p-3 (RZ) - {0x4d56d355, 0x3e740182, 1, 0, 0}, - // x = 0x1.862064p33, tan(x) = -0x1.8dee56p-3 (RZ) - {0x50431032, 0xbe46f72b, 0, 1, 1}, - // x = 0x1.af61dap48, tan(x) = 0x1.60d1c6p-2 (RZ) - {0x57d7b0ed, 0x3eb068e3, 1, 0, 1}, - // x = 0x1.0088bcp52, tan(x) = 0x1.ca1edp0 (RZ) - {0x5980445e, 0x3fe50f68, 1, 0, 0}, - // x = 0x1.f90dfcp72, tan(x) = 0x1.597f9cp-1 (RZ) - {0x63fc86fe, 0x3f2cbfce, 1, 0, 0}, - // x = 0x1.a6ce12p86, tan(x) = -0x1.c5612ep-1 (RZ) - {0x6ad36709, 0xbf62b097, 0, 1, 0}, -}}; -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - -LLVM_LIBC_FUNCTION(float, tanf, (float x)) { - using FPBits = typename fputil::FPBits<float>; - FPBits xbits(x); - uint32_t x_abs = xbits.uintval() & 0x7fff'ffffU; - - // |x| < pi/32 - if (LIBC_UNLIKELY(x_abs <= 0x3dc9'0fdbU)) { - double xd = static_cast<double>(x); - - // |x| < 0x1.0p-12f - if (LIBC_UNLIKELY(x_abs < 0x3980'0000U)) { - if (LIBC_UNLIKELY(x_abs == 0U)) { - // For signed zeros. - return x; - } - // When |x| < 2^-12, the relative error of the approximation tan(x) ~ x - // is: - // |tan(x) - x| / |tan(x)| < |x^3| / (3|x|) - // = x^2 / 3 - // < 2^-25 - // < epsilon(1)/2. - // So the correctly rounded values of tan(x) are: - // = x + sign(x)*eps(x) if rounding mode = FE_UPWARD and x is positive, - // or (rounding mode = FE_DOWNWARD and x is - // negative), - // = x otherwise. - // To simplify the rounding decision and make it more efficient, we use - // fma(x, 2^-25, x) instead. - // Note: to use the formula x + 2^-25*x to decide the correct rounding, we - // do need fma(x, 2^-25, x) to prevent underflow caused by 2^-25*x when - // |x| < 2^-125. For targets without FMA instructions, we simply use - // double for intermediate results as it is more efficient than using an - // emulated version of FMA. -#if defined(LIBC_TARGET_CPU_HAS_FMA_FLOAT) - return fputil::multiply_add(x, 0x1.0p-25f, x); -#else - return static_cast<float>(fputil::multiply_add(xd, 0x1.0p-25, xd)); -#endif // LIBC_TARGET_CPU_HAS_FMA_FLOAT - } - - // |x| < pi/32 - double xsq = xd * xd; - - // Degree-9 minimax odd polynomial of tan(x) generated by Sollya with: - // > P = fpminimax(tan(x)/x, [|0, 2, 4, 6, 8|], [|1, D...|], [0, pi/32]); - double result = - fputil::polyeval(xsq, 1.0, 0x1.555555553d022p-2, 0x1.111111ce442c1p-3, - 0x1.ba180a6bbdecdp-5, 0x1.69c0a88a0b71fp-6); - return static_cast<float>(xd * result); - } - -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - bool x_sign = xbits.uintval() >> 31; - // Check for exceptional values - if (LIBC_UNLIKELY(x_abs == 0x3f8a1f62U)) { - // |x| = 0x1.143ec4p0 - float sign = x_sign ? -1.0f : 1.0f; - - // volatile is used to prevent compiler (gcc) from optimizing the - // computation, making the results incorrect in different rounding modes. - volatile float tmp = 0x1.ddf9f4p0f; - tmp = fputil::multiply_add(sign, tmp, sign * 0x1.1p-24f); - - return tmp; - } -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - - // |x| > 0x1.ada6a8p+27f - if (LIBC_UNLIKELY(x_abs > 0x4d56'd354U)) { - // Inf or NaN - if (LIBC_UNLIKELY(x_abs >= 0x7f80'0000U)) { - if (xbits.is_signaling_nan()) { - fputil::raise_except_if_required(FE_INVALID); - return FPBits::quiet_nan().get_val(); - } - - if (x_abs == 0x7f80'0000U) { - fputil::set_errno_if_required(EDOM); - fputil::raise_except_if_required(FE_INVALID); - } - return x + FPBits::quiet_nan().get_val(); - } -#ifndef LIBC_MATH_HAS_SKIP_ACCURATE_PASS - // Other large exceptional values - if (auto r = TANF_EXCEPTS.lookup_odd(x_abs, x_sign); - LIBC_UNLIKELY(r.has_value())) - return r.value(); -#endif // !LIBC_MATH_HAS_SKIP_ACCURATE_PASS - } - - // For |x| >= pi/32, we use the definition of tan(x) function: - // tan(x) = sin(x) / cos(x) - // The we follow the same computations of sin(x) and cos(x) as sinf, cosf, - // and sincosf. - - double xd = static_cast<double>(x); - double sin_k, cos_k, sin_y, cosm1_y; - - sincosf_eval(xd, x_abs, sin_k, cos_k, sin_y, cosm1_y); - // tan(x) = sin(x) / cos(x) - // = (sin_y * cos_k + cos_y * sin_k) / (cos_y * cos_k - sin_y * sin_k) - using fputil::multiply_add; - return static_cast<float>( - multiply_add(sin_y, cos_k, multiply_add(cosm1_y, sin_k, sin_k)) / - multiply_add(sin_y, -sin_k, multiply_add(cosm1_y, cos_k, cos_k))); -} +LLVM_LIBC_FUNCTION(float, tanf, (float x)) { return math::tanf(x); } } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/pthread/pthread_getattr_np.h b/libc/src/pthread/pthread_getattr_np.h new file mode 100644 index 0000000..7dada95 --- /dev/null +++ b/libc/src/pthread/pthread_getattr_np.h @@ -0,0 +1,21 @@ +//===-- Implementation header for pthread_getattr_np function -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===---------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_PTHREAD_PTHREAD_GETATTR_NP_H +#define LLVM_LIBC_SRC_PTHREAD_PTHREAD_GETATTR_NP_H + +#include "src/__support/macros/config.h" +#include <pthread.h> + +namespace LIBC_NAMESPACE_DECL { + +int pthread_getattr_np(pthread_t, pthread_attr_t *); + +} // namespace LIBC_NAMESPACE_DECL + +#endif // LLVM_LIBC_SRC_PTHREAD_PTHREAD_GETATTR_NP_H diff --git a/libc/src/spawn/linux/posix_spawn.cpp b/libc/src/spawn/linux/posix_spawn.cpp index fe82ba2..f058158 100644 --- a/libc/src/spawn/linux/posix_spawn.cpp +++ b/libc/src/spawn/linux/posix_spawn.cpp @@ -44,7 +44,7 @@ cpp::optional<int> open(const char *path, int oflags, mode_t mode) { int fd = LIBC_NAMESPACE::syscall_impl<int>(SYS_openat, AT_FDCWD, path, oflags, mode); #endif - if (fd > 0) + if (fd >= 0) return fd; // The open function is called as part of the child process' preparatory // steps. If an open fails, the child process just exits. So, unlike diff --git a/libc/src/stdio/printf_core/CMakeLists.txt b/libc/src/stdio/printf_core/CMakeLists.txt index 624129b..ae93cc75 100644 --- a/libc/src/stdio/printf_core/CMakeLists.txt +++ b/libc/src/stdio/printf_core/CMakeLists.txt @@ -43,6 +43,22 @@ if(NOT TARGET ${target_error_mapper}) set(target_error_mapper libc.src.stdio.printf_core.generic.error_mapper) endif() +if(LIBC_CONF_PRINTF_DISABLE_WIDE) + set(wchar_deps "") + set(parser_wchar_deps "") +else() + set(wchar_deps + libc.hdr.types.wchar_t + libc.hdr.types.wint_t + libc.hdr.wchar_macros + libc.src.__support.wchar.wcrtomb + libc.src.__support.wchar.mbstate + ) + set(parser_wchar_deps + libc.hdr.types.wint_t + ) +endif() + add_header_library( printf_config HDRS @@ -76,6 +92,7 @@ add_header_library( libc.src.__support.CPP.string_view libc.src.__support.CPP.type_traits libc.src.__support.common + ${parser_wchar_deps} ) add_header_library( @@ -111,6 +128,7 @@ add_header_library( .printf_config .writer libc.include.inttypes + libc.hdr.limits_macros libc.src.__support.big_int libc.src.__support.common libc.src.__support.CPP.limits @@ -125,6 +143,7 @@ add_header_library( libc.src.__support.uint128 libc.src.__support.StringUtil.error_to_string libc.src.string.memory_utils.inline_memcpy + ${wchar_deps} ) add_header_library( diff --git a/libc/src/stdio/printf_core/char_converter.h b/libc/src/stdio/printf_core/char_converter.h index fd2eb25..e4792c3 100644 --- a/libc/src/stdio/printf_core/char_converter.h +++ b/libc/src/stdio/printf_core/char_converter.h @@ -1,4 +1,4 @@ -//===-- String Converter for printf -----------------------------*- C++ -*-===// +//===-- Character Converter for printf --------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -9,6 +9,15 @@ #ifndef LLVM_LIBC_SRC_STDIO_PRINTF_CORE_CHAR_CONVERTER_H #define LLVM_LIBC_SRC_STDIO_PRINTF_CORE_CHAR_CONVERTER_H +#ifndef LIBC_COPT_PRINTF_DISABLE_WIDE +#include "hdr/types/wchar_t.h" +#include "hdr/types/wint_t.h" +#include "hdr/wchar_macros.h" +#include "src/__support/wchar/mbstate.h" +#include "src/__support/wchar/wcrtomb.h" +#endif // LIBC_COPT_PRINTF_DISABLE_WIDE + +#include "hdr/limits_macros.h" #include "src/__support/macros/config.h" #include "src/stdio/printf_core/converter_utils.h" #include "src/stdio/printf_core/core_structs.h" @@ -20,12 +29,41 @@ namespace printf_core { template <WriteMode write_mode> LIBC_INLINE int convert_char(Writer<write_mode> *writer, const FormatSection &to_conv) { - char c = static_cast<char>(to_conv.conv_val_raw); - constexpr int STRING_LEN = 1; + char buffer[MB_LEN_MAX]; + size_t write_size = 0; + + if (to_conv.length_modifier == LengthModifier::l) { +#ifndef LIBC_COPT_PRINTF_DISABLE_WIDE + wint_t wi = static_cast<wint_t>(to_conv.conv_val_raw); + + if (wi == WEOF) { + return ILLEGAL_WIDE_CHAR; + } + + internal::mbstate mbstate; + wchar_t wc = static_cast<wchar_t>(wi); + auto ret = internal::wcrtomb(buffer, wc, &mbstate); + + if (!ret.has_value()) { + return MB_CONVERSION_ERROR; + } + + write_size = ret.value(); +#else + // If wide characters are disabled, treat the 'l' modifier as a no-op. + buffer[0] = static_cast<char>(to_conv.conv_val_raw); + write_size = 1; + +#endif // LIBC_COPT_PRINTF_DISABLE_WIDE + } else { + buffer[0] = static_cast<char>(to_conv.conv_val_raw); + write_size = 1; + } - size_t padding_spaces = - to_conv.min_width > STRING_LEN ? to_conv.min_width - STRING_LEN : 0; + size_t padding_spaces = to_conv.min_width > static_cast<int>(write_size) + ? to_conv.min_width - static_cast<int>(write_size) + : 0; // If the padding is on the left side, write the spaces first. if (padding_spaces > 0 && @@ -33,7 +71,7 @@ LIBC_INLINE int convert_char(Writer<write_mode> *writer, RET_IF_RESULT_NEGATIVE(writer->write(' ', padding_spaces)); } - RET_IF_RESULT_NEGATIVE(writer->write(c)); + RET_IF_RESULT_NEGATIVE(writer->write({buffer, write_size})); // If the padding is on the right side, write the spaces last. if (padding_spaces > 0 && diff --git a/libc/src/stdio/printf_core/core_structs.h b/libc/src/stdio/printf_core/core_structs.h index 0d41f22..d93fa96 100644 --- a/libc/src/stdio/printf_core/core_structs.h +++ b/libc/src/stdio/printf_core/core_structs.h @@ -142,6 +142,8 @@ constexpr int INT_CONVERSION_ERROR = -1004; constexpr int FIXED_POINT_CONVERSION_ERROR = -1005; constexpr int ALLOCATION_ERROR = -1006; constexpr int OVERFLOW_ERROR = -1007; +constexpr int ILLEGAL_WIDE_CHAR = -1008; +constexpr int MB_CONVERSION_ERROR = -1009; } // namespace printf_core } // namespace LIBC_NAMESPACE_DECL diff --git a/libc/src/stdio/printf_core/linux/error_mapper.h b/libc/src/stdio/printf_core/linux/error_mapper.h index 3c2fe66..3449f12 100644 --- a/libc/src/stdio/printf_core/linux/error_mapper.h +++ b/libc/src/stdio/printf_core/linux/error_mapper.h @@ -40,6 +40,9 @@ LIBC_INLINE static int internal_error_to_errno(int internal_error) { return ENOMEM; case OVERFLOW_ERROR: return EOVERFLOW; + case ILLEGAL_WIDE_CHAR: + case MB_CONVERSION_ERROR: + return EILSEQ; default: LIBC_ASSERT( false && diff --git a/libc/src/stdio/printf_core/parser.h b/libc/src/stdio/printf_core/parser.h index cef9b1a..a3b6299 100644 --- a/libc/src/stdio/printf_core/parser.h +++ b/libc/src/stdio/printf_core/parser.h @@ -27,6 +27,9 @@ #ifndef LIBC_COPT_PRINTF_DISABLE_STRERROR #include "src/__support/libc_errno.h" #endif // LIBC_COPT_PRINTF_DISABLE_STRERROR +#ifndef LIBC_COPT_PRINTF_DISABLE_WIDE +#include "hdr/types/wint_t.h" +#endif // LIBC_COPT_PRINTF_DISABLE_WIDE namespace LIBC_NAMESPACE_DECL { namespace printf_core { @@ -73,9 +76,9 @@ template <typename ArgProvider> class Parser { ArgProvider args_cur; #ifndef LIBC_COPT_PRINTF_DISABLE_INDEX_MODE - // args_start stores the start of the va_args, which is allows getting the - // value of arguments that have already been passed. args_index is tracked so - // that we know which argument args_cur is on. + // args_start stores the start of the va_args, which helps in getting the + // number of arguments that have already been passed. args_index is tracked + // so that we know which argument args_cur is on. ArgProvider args_start; size_t args_index = 1; @@ -173,7 +176,17 @@ public: section.has_conv = true; break; case ('c'): - WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, int, conv_index); + if (section.length_modifier == LengthModifier::l) { +#ifdef LIBC_COPT_PRINTF_DISABLE_WIDE + using WideCharArgType = int; +#else + using WideCharArgType = wint_t; +#endif // LIBC_COPT_PRINTF_DISABLE_WIDE + WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, WideCharArgType, + conv_index); + } else { + WRITE_ARG_VAL_SIMPLEST(section.conv_val_raw, int, conv_index); + } break; case ('d'): case ('i'): @@ -574,7 +587,16 @@ private: conv_size = type_desc_from_type<void>(); break; case ('c'): - conv_size = type_desc_from_type<int>(); + if (lm == LengthModifier::l) { +#ifdef LIBC_COPT_PRINTF_DISABLE_WIDE + using WideCharArgType = int; +#else + using WideCharArgType = wint_t; +#endif // LIBC_COPT_PRINTF_DISABLE_WIDE + conv_size = type_desc_from_type<WideCharArgType>(); + } else { + conv_size = type_desc_from_type<int>(); + } break; case ('d'): case ('i'): diff --git a/libc/src/string/memory_utils/inline_memcpy.h b/libc/src/string/memory_utils/inline_memcpy.h index 13975e6..931d282 100644 --- a/libc/src/string/memory_utils/inline_memcpy.h +++ b/libc/src/string/memory_utils/inline_memcpy.h @@ -31,7 +31,7 @@ #elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) #include "src/string/memory_utils/riscv/inline_memcpy.h" #define LIBC_SRC_STRING_MEMORY_UTILS_MEMCPY inline_memcpy_riscv -#elif defined(LIBC_TARGET_ARCH_IS_GPU) +#elif defined(LIBC_TARGET_ARCH_IS_GPU) || defined(LIBC_TARGET_ARCH_IS_WASM) #include "src/string/memory_utils/generic/builtin.h" #define LIBC_SRC_STRING_MEMORY_UTILS_MEMCPY inline_memcpy_builtin #else diff --git a/libc/src/string/memory_utils/inline_memmove.h b/libc/src/string/memory_utils/inline_memmove.h index 71a28c32..3162766 100644 --- a/libc/src/string/memory_utils/inline_memmove.h +++ b/libc/src/string/memory_utils/inline_memmove.h @@ -29,7 +29,7 @@ #define LIBC_SRC_STRING_MEMORY_UTILS_MEMMOVE_SMALL_SIZE \ inline_memmove_no_small_size #define LIBC_SRC_STRING_MEMORY_UTILS_MEMMOVE_FOLLOW_UP inline_memmove_riscv -#elif defined(LIBC_TARGET_ARCH_IS_GPU) +#elif defined(LIBC_TARGET_ARCH_IS_GPU) || defined(LIBC_TARGET_ARCH_IS_WASM) #include "src/string/memory_utils/generic/builtin.h" #define LIBC_SRC_STRING_MEMORY_UTILS_MEMMOVE_SMALL_SIZE \ inline_memmove_no_small_size diff --git a/libc/src/string/memory_utils/inline_memset.h b/libc/src/string/memory_utils/inline_memset.h index e41bdb6..da85f09 100644 --- a/libc/src/string/memory_utils/inline_memset.h +++ b/libc/src/string/memory_utils/inline_memset.h @@ -27,7 +27,7 @@ #elif defined(LIBC_TARGET_ARCH_IS_ANY_RISCV) #include "src/string/memory_utils/riscv/inline_memset.h" #define LIBC_SRC_STRING_MEMORY_UTILS_MEMSET inline_memset_riscv -#elif defined(LIBC_TARGET_ARCH_IS_GPU) +#elif defined(LIBC_TARGET_ARCH_IS_GPU) || defined(LIBC_TARGET_ARCH_IS_WASM) #include "src/string/memory_utils/generic/builtin.h" #define LIBC_SRC_STRING_MEMORY_UTILS_MEMSET inline_memset_builtin #else |
