1c120edc7SMichael Jones //===-- Floating point divsion and remainder operations ---------*- C++ -*-===// 2c120edc7SMichael Jones // 3c120edc7SMichael Jones // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4c120edc7SMichael Jones // See https://llvm.org/LICENSE.txt for license information. 5c120edc7SMichael Jones // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6c120edc7SMichael Jones // 7c120edc7SMichael Jones //===----------------------------------------------------------------------===// 8c120edc7SMichael Jones 9270547f3SGuillaume Chatelet #ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_DIVISIONANDREMAINDEROPERATIONS_H 10270547f3SGuillaume Chatelet #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_DIVISIONANDREMAINDEROPERATIONS_H 11c120edc7SMichael Jones 12c120edc7SMichael Jones #include "FPBits.h" 13c120edc7SMichael Jones #include "ManipulationFunctions.h" 14c120edc7SMichael Jones #include "NormalFloat.h" 15c120edc7SMichael Jones 16f7226150SGuillaume Chatelet #include "src/__support/CPP/type_traits.h" 1759c809cdSSiva Chandra Reddy #include "src/__support/common.h" 18*5ff3ff33SPetr Hosek #include "src/__support/macros/config.h" 19c120edc7SMichael Jones 20*5ff3ff33SPetr Hosek namespace LIBC_NAMESPACE_DECL { 21c120edc7SMichael Jones namespace fputil { 22c120edc7SMichael Jones 231c92911eSMichael Jones static constexpr int QUOTIENT_LSB_BITS = 3; 24c120edc7SMichael Jones 25c120edc7SMichael Jones // The implementation is a bit-by-bit algorithm which uses integer division 26c120edc7SMichael Jones // to evaluate the quotient and remainder. 27f7226150SGuillaume Chatelet template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0> 2859c809cdSSiva Chandra Reddy LIBC_INLINE T remquo(T x, T y, int &q) { 29c120edc7SMichael Jones FPBits<T> xbits(x), ybits(y); 301c92911eSMichael Jones if (xbits.is_nan()) 31c120edc7SMichael Jones return x; 321c92911eSMichael Jones if (ybits.is_nan()) 33c120edc7SMichael Jones return y; 341c92911eSMichael Jones if (xbits.is_inf() || ybits.is_zero()) 35ace383dfSGuillaume Chatelet return FPBits<T>::quiet_nan().get_val(); 36c120edc7SMichael Jones 371c92911eSMichael Jones if (xbits.is_zero()) { 38c120edc7SMichael Jones q = 0; 39b6bc9d72SGuillaume Chatelet return LIBC_NAMESPACE::fputil::copysign(T(0.0), x); 40c120edc7SMichael Jones } 41c120edc7SMichael Jones 421c92911eSMichael Jones if (ybits.is_inf()) { 43c120edc7SMichael Jones q = 0; 44c120edc7SMichael Jones return x; 45c120edc7SMichael Jones } 46c120edc7SMichael Jones 4711ec512fSGuillaume Chatelet const Sign result_sign = 4811ec512fSGuillaume Chatelet (xbits.sign() == ybits.sign() ? Sign::POS : Sign::NEG); 49c120edc7SMichael Jones 50c120edc7SMichael Jones // Once we know the sign of the result, we can just operate on the absolute 51c120edc7SMichael Jones // values. The correct sign can be applied to the result after the result 52c120edc7SMichael Jones // is evaluated. 5311ec512fSGuillaume Chatelet xbits.set_sign(Sign::POS); 5411ec512fSGuillaume Chatelet ybits.set_sign(Sign::POS); 55c120edc7SMichael Jones 56c120edc7SMichael Jones NormalFloat<T> normalx(xbits), normaly(ybits); 57c120edc7SMichael Jones int exp = normalx.exponent - normaly.exponent; 583546f4daSGuillaume Chatelet typename NormalFloat<T>::StorageType mx = normalx.mantissa, 59c120edc7SMichael Jones my = normaly.mantissa; 60c120edc7SMichael Jones 61c120edc7SMichael Jones q = 0; 62c120edc7SMichael Jones while (exp >= 0) { 631c92911eSMichael Jones unsigned shift_count = 0; 643546f4daSGuillaume Chatelet typename NormalFloat<T>::StorageType n = mx; 651c92911eSMichael Jones for (shift_count = 0; n < my; n <<= 1, ++shift_count) 66c120edc7SMichael Jones ; 67c120edc7SMichael Jones 681c92911eSMichael Jones if (static_cast<int>(shift_count) > exp) 69c120edc7SMichael Jones break; 70c120edc7SMichael Jones 711c92911eSMichael Jones exp -= shift_count; 721c92911eSMichael Jones if (0 <= exp && exp < QUOTIENT_LSB_BITS) 73c120edc7SMichael Jones q |= (1 << exp); 74c120edc7SMichael Jones 75c120edc7SMichael Jones mx = n - my; 76c120edc7SMichael Jones if (mx == 0) { 7711ec512fSGuillaume Chatelet q = result_sign.is_neg() ? -q : q; 78b6bc9d72SGuillaume Chatelet return LIBC_NAMESPACE::fputil::copysign(T(0.0), x); 79c120edc7SMichael Jones } 80c120edc7SMichael Jones } 81c120edc7SMichael Jones 82508c4efeSGuillaume Chatelet NormalFloat<T> remainder(Sign::POS, exp + normaly.exponent, mx); 83c120edc7SMichael Jones 84c120edc7SMichael Jones // Since NormalFloat to native type conversion is a truncation operation 85c120edc7SMichael Jones // currently, the remainder value in the native type is correct as is. 86c120edc7SMichael Jones // However, if NormalFloat to native type conversion is updated in future, 87c120edc7SMichael Jones // then the conversion to native remainder value should be updated 88c120edc7SMichael Jones // appropriately and some directed tests added. 891c92911eSMichael Jones T native_remainder(remainder); 902856db0dSGuillaume Chatelet T absy = ybits.get_val(); 91c120edc7SMichael Jones int cmp = remainder.mul2(1).cmp(normaly); 92c120edc7SMichael Jones if (cmp > 0) { 93c120edc7SMichael Jones q = q + 1; 94c120edc7SMichael Jones if (x >= T(0.0)) 951c92911eSMichael Jones native_remainder = native_remainder - absy; 96c120edc7SMichael Jones else 971c92911eSMichael Jones native_remainder = absy - native_remainder; 98c120edc7SMichael Jones } else if (cmp == 0) { 99c120edc7SMichael Jones if (q & 1) { 100c120edc7SMichael Jones q += 1; 101c120edc7SMichael Jones if (x >= T(0.0)) 1021c92911eSMichael Jones native_remainder = -native_remainder; 103c120edc7SMichael Jones } else { 104c120edc7SMichael Jones if (x < T(0.0)) 1051c92911eSMichael Jones native_remainder = -native_remainder; 106c120edc7SMichael Jones } 107c120edc7SMichael Jones } else { 108c120edc7SMichael Jones if (x < T(0.0)) 1091c92911eSMichael Jones native_remainder = -native_remainder; 110c120edc7SMichael Jones } 111c120edc7SMichael Jones 11211ec512fSGuillaume Chatelet q = result_sign.is_neg() ? -q : q; 1131c92911eSMichael Jones if (native_remainder == T(0.0)) 114b6bc9d72SGuillaume Chatelet return LIBC_NAMESPACE::fputil::copysign(T(0.0), x); 1151c92911eSMichael Jones return native_remainder; 116c120edc7SMichael Jones } 117c120edc7SMichael Jones 118c120edc7SMichael Jones } // namespace fputil 119*5ff3ff33SPetr Hosek } // namespace LIBC_NAMESPACE_DECL 120c120edc7SMichael Jones 121270547f3SGuillaume Chatelet #endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_DIVISIONANDREMAINDEROPERATIONS_H 122