• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- Floating point divsion and remainder operations ---------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_DIVISIONANDREMAINDEROPERATIONS_H
10 #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_DIVISIONANDREMAINDEROPERATIONS_H
11 
12 #include "FPBits.h"
13 #include "ManipulationFunctions.h"
14 #include "NormalFloat.h"
15 
16 #include "src/__support/CPP/type_traits.h"
17 #include "src/__support/common.h"
18 
19 namespace LIBC_NAMESPACE {
20 namespace fputil {
21 
22 static constexpr int QUOTIENT_LSB_BITS = 3;
23 
24 // The implementation is a bit-by-bit algorithm which uses integer division
25 // to evaluate the quotient and remainder.
26 template <typename T, cpp::enable_if_t<cpp::is_floating_point_v<T>, int> = 0>
remquo(T x,T y,int & q)27 LIBC_INLINE T remquo(T x, T y, int &q) {
28   FPBits<T> xbits(x), ybits(y);
29   if (xbits.is_nan())
30     return x;
31   if (ybits.is_nan())
32     return y;
33   if (xbits.is_inf() || ybits.is_zero())
34     return FPBits<T>::quiet_nan().get_val();
35 
36   if (xbits.is_zero()) {
37     q = 0;
38     return LIBC_NAMESPACE::fputil::copysign(T(0.0), x);
39   }
40 
41   if (ybits.is_inf()) {
42     q = 0;
43     return x;
44   }
45 
46   const Sign result_sign =
47       (xbits.sign() == ybits.sign() ? Sign::POS : Sign::NEG);
48 
49   // Once we know the sign of the result, we can just operate on the absolute
50   // values. The correct sign can be applied to the result after the result
51   // is evaluated.
52   xbits.set_sign(Sign::POS);
53   ybits.set_sign(Sign::POS);
54 
55   NormalFloat<T> normalx(xbits), normaly(ybits);
56   int exp = normalx.exponent - normaly.exponent;
57   typename NormalFloat<T>::StorageType mx = normalx.mantissa,
58                                        my = normaly.mantissa;
59 
60   q = 0;
61   while (exp >= 0) {
62     unsigned shift_count = 0;
63     typename NormalFloat<T>::StorageType n = mx;
64     for (shift_count = 0; n < my; n <<= 1, ++shift_count)
65       ;
66 
67     if (static_cast<int>(shift_count) > exp)
68       break;
69 
70     exp -= shift_count;
71     if (0 <= exp && exp < QUOTIENT_LSB_BITS)
72       q |= (1 << exp);
73 
74     mx = n - my;
75     if (mx == 0) {
76       q = result_sign.is_neg() ? -q : q;
77       return LIBC_NAMESPACE::fputil::copysign(T(0.0), x);
78     }
79   }
80 
81   NormalFloat<T> remainder(Sign::POS, exp + normaly.exponent, mx);
82 
83   // Since NormalFloat to native type conversion is a truncation operation
84   // currently, the remainder value in the native type is correct as is.
85   // However, if NormalFloat to native type conversion is updated in future,
86   // then the conversion to native remainder value should be updated
87   // appropriately and some directed tests added.
88   T native_remainder(remainder);
89   T absy = ybits.get_val();
90   int cmp = remainder.mul2(1).cmp(normaly);
91   if (cmp > 0) {
92     q = q + 1;
93     if (x >= T(0.0))
94       native_remainder = native_remainder - absy;
95     else
96       native_remainder = absy - native_remainder;
97   } else if (cmp == 0) {
98     if (q & 1) {
99       q += 1;
100       if (x >= T(0.0))
101         native_remainder = -native_remainder;
102     } else {
103       if (x < T(0.0))
104         native_remainder = -native_remainder;
105     }
106   } else {
107     if (x < T(0.0))
108       native_remainder = -native_remainder;
109   }
110 
111   q = result_sign.is_neg() ? -q : q;
112   if (native_remainder == T(0.0))
113     return LIBC_NAMESPACE::fputil::copysign(T(0.0), x);
114   return native_remainder;
115 }
116 
117 } // namespace fputil
118 } // namespace LIBC_NAMESPACE
119 
120 #endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_DIVISIONANDREMAINDEROPERATIONS_H
121