//===-- Floating point divsion and remainder operations ---------*- 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_UTILS_FPUTIL_DIVISION_AND_REMAINDER_OPERATIONS_H #define LLVM_LIBC_UTILS_FPUTIL_DIVISION_AND_REMAINDER_OPERATIONS_H #include "FPBits.h" #include "ManipulationFunctions.h" #include "NormalFloat.h" #include "utils/CPP/TypeTraits.h" namespace __llvm_libc { namespace fputil { static constexpr int quotientLSBBits = 3; // The implementation is a bit-by-bit algorithm which uses integer division // to evaluate the quotient and remainder. template ::Value, int> = 0> static inline T remquo(T x, T y, int &q) { FPBits xbits(x), ybits(y); if (xbits.isNaN()) return x; if (ybits.isNaN()) return y; if (xbits.isInf() || ybits.isZero()) return FPBits::buildNaN(1); if (xbits.isZero()) { q = 0; return __llvm_libc::fputil::copysign(T(0.0), x); } if (ybits.isInf()) { q = 0; return x; } bool resultSign = (xbits.sign == ybits.sign ? false : true); // Once we know the sign of the result, we can just operate on the absolute // values. The correct sign can be applied to the result after the result // is evaluated. xbits.sign = ybits.sign = 0; NormalFloat normalx(xbits), normaly(ybits); int exp = normalx.exponent - normaly.exponent; typename NormalFloat::UIntType mx = normalx.mantissa, my = normaly.mantissa; q = 0; while (exp >= 0) { unsigned shiftCount = 0; typename NormalFloat::UIntType n = mx; for (shiftCount = 0; n < my; n <<= 1, ++shiftCount) ; if (static_cast(shiftCount) > exp) break; exp -= shiftCount; if (0 <= exp && exp < quotientLSBBits) q |= (1 << exp); mx = n - my; if (mx == 0) { q = resultSign ? -q : q; return __llvm_libc::fputil::copysign(T(0.0), x); } } NormalFloat remainder(exp + normaly.exponent, mx, 0); // Since NormalFloat to native type conversion is a truncation operation // currently, the remainder value in the native type is correct as is. // However, if NormalFloat to native type conversion is updated in future, // then the conversion to native remainder value should be updated // appropriately and some directed tests added. T nativeRemainder(remainder); T absy = T(ybits); int cmp = remainder.mul2(1).cmp(normaly); if (cmp > 0) { q = q + 1; if (x >= T(0.0)) nativeRemainder = nativeRemainder - absy; else nativeRemainder = absy - nativeRemainder; } else if (cmp == 0) { if (q & 1) { q += 1; if (x >= T(0.0)) nativeRemainder = -nativeRemainder; } else { if (x < T(0.0)) nativeRemainder = -nativeRemainder; } } else { if (x < T(0.0)) nativeRemainder = -nativeRemainder; } q = resultSign ? -q : q; if (nativeRemainder == T(0.0)) return __llvm_libc::fputil::copysign(T(0.0), x); return nativeRemainder; } } // namespace fputil } // namespace __llvm_libc #endif // LLVM_LIBC_UTILS_FPUTIL_DIVISION_AND_REMAINDER_OPERATIONS_H