//===-- Implementation of hypotf 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_FPUTIL_HYPOT_H #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_HYPOT_H #include "BasicOperations.h" #include "FEnvImpl.h" #include "FPBits.h" #include "rounding_mode.h" #include "src/__support/CPP/bit.h" #include "src/__support/CPP/type_traits.h" #include "src/__support/common.h" #include "src/__support/macros/config.h" #include "src/__support/uint128.h" namespace LIBC_NAMESPACE_DECL { namespace fputil { namespace internal { template <typename T> LIBC_INLINE T find_leading_one(T mant, int &shift_length) { … } } // namespace internal template <typename T> struct DoubleLength; template <> struct DoubleLength<uint16_t> { … }; template <> struct DoubleLength<uint32_t> { … }; template <> struct DoubleLength<uint64_t> { … }; // Correctly rounded IEEE 754 HYPOT(x, y) with round to nearest, ties to even. // // Algorithm: // - Let a = max(|x|, |y|), b = min(|x|, |y|), then we have that: // a <= sqrt(a^2 + b^2) <= min(a + b, a*sqrt(2)) // 1. So if b < eps(a)/2, then HYPOT(x, y) = a. // // - Moreover, the exponent part of HYPOT(x, y) is either the same or 1 more // than the exponent part of a. // // 2. For the remaining cases, we will use the digit-by-digit (shift-and-add) // algorithm to compute SQRT(Z): // // - For Y = y0.y1...yn... = SQRT(Z), // let Y(n) = y0.y1...yn be the first n fractional digits of Y. // // - The nth scaled residual R(n) is defined to be: // R(n) = 2^n * (Z - Y(n)^2) // // - Since Y(n) = Y(n - 1) + yn * 2^(-n), the scaled residual // satisfies the following recurrence formula: // R(n) = 2*R(n - 1) - yn*(2*Y(n - 1) + 2^(-n)), // with the initial conditions: // Y(0) = y0, and R(0) = Z - y0. // // - So the nth fractional digit of Y = SQRT(Z) can be decided by: // yn = 1 if 2*R(n - 1) >= 2*Y(n - 1) + 2^(-n), // 0 otherwise. // // 3. Precision analysis: // // - Notice that in the decision function: // 2*R(n - 1) >= 2*Y(n - 1) + 2^(-n), // the right hand side only uses up to the 2^(-n)-bit, and both sides are // non-negative, so R(n - 1) can be truncated at the 2^(-(n + 1))-bit, so // that 2*R(n - 1) is corrected up to the 2^(-n)-bit. // // - Thus, in order to round SQRT(a^2 + b^2) correctly up to n-fractional // bits, we need to perform the summation (a^2 + b^2) correctly up to (2n + // 2)-fractional bits, and the remaining bits are sticky bits (i.e. we only // care if they are 0 or > 0), and the comparisons, additions/subtractions // can be done in n-fractional bits precision. // // - For single precision (float), we can use uint64_t to store the sum a^2 + // b^2 exact up to (2n + 2)-fractional bits. // // - Then we can feed this sum into the digit-by-digit algorithm for SQRT(Z) // described above. // // // Special cases: // - HYPOT(x, y) is +Inf if x or y is +Inf or -Inf; else // - HYPOT(x, y) is NaN if x or y is NaN. // template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0> LIBC_INLINE T hypot(T x, T y) { … } } // namespace fputil } // namespace LIBC_NAMESPACE_DECL #endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_HYPOT_H