1 //===-- Floating point divsion and remainder operations ---------*- C++ -*-===//
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
7 //===----------------------------------------------------------------------===//
9 #ifndef LLVM_LIBC_SRC___SUPPORT_FPUTIL_DIVISIONANDREMAINDEROPERATIONS_H
10 #define LLVM_LIBC_SRC___SUPPORT_FPUTIL_DIVISIONANDREMAINDEROPERATIONS_H
13 #include "ManipulationFunctions.h"
14 #include "NormalFloat.h"
16 #include "src/__support/CPP/type_traits.h"
17 #include "src/__support/common.h"
18 #include "src/__support/macros/config.h"
20 namespace LIBC_NAMESPACE_DECL
{
23 static constexpr int QUOTIENT_LSB_BITS
= 3;
25 // The implementation is a bit-by-bit algorithm which uses integer division
26 // to evaluate the quotient and remainder.
27 template <typename T
, cpp::enable_if_t
<cpp::is_floating_point_v
<T
>, int> = 0>
28 LIBC_INLINE T
remquo(T x
, T y
, int &q
) {
29 FPBits
<T
> xbits(x
), ybits(y
);
34 if (xbits
.is_inf() || ybits
.is_zero())
35 return FPBits
<T
>::quiet_nan().get_val();
37 if (xbits
.is_zero()) {
39 return LIBC_NAMESPACE::fputil::copysign(T(0.0), x
);
47 const Sign result_sign
=
48 (xbits
.sign() == ybits
.sign() ? Sign::POS
: Sign::NEG
);
50 // Once we know the sign of the result, we can just operate on the absolute
51 // values. The correct sign can be applied to the result after the result
53 xbits
.set_sign(Sign::POS
);
54 ybits
.set_sign(Sign::POS
);
56 NormalFloat
<T
> normalx(xbits
), normaly(ybits
);
57 int exp
= normalx
.exponent
- normaly
.exponent
;
58 typename NormalFloat
<T
>::StorageType mx
= normalx
.mantissa
,
59 my
= normaly
.mantissa
;
63 unsigned shift_count
= 0;
64 typename NormalFloat
<T
>::StorageType n
= mx
;
65 for (shift_count
= 0; n
< my
; n
<<= 1, ++shift_count
)
68 if (static_cast<int>(shift_count
) > exp
)
72 if (0 <= exp
&& exp
< QUOTIENT_LSB_BITS
)
77 q
= result_sign
.is_neg() ? -q
: q
;
78 return LIBC_NAMESPACE::fputil::copysign(T(0.0), x
);
82 NormalFloat
<T
> remainder(Sign::POS
, exp
+ normaly
.exponent
, mx
);
84 // Since NormalFloat to native type conversion is a truncation operation
85 // currently, the remainder value in the native type is correct as is.
86 // However, if NormalFloat to native type conversion is updated in future,
87 // then the conversion to native remainder value should be updated
88 // appropriately and some directed tests added.
89 T
native_remainder(remainder
);
90 T absy
= ybits
.get_val();
91 int cmp
= remainder
.mul2(1).cmp(normaly
);
95 native_remainder
= native_remainder
- absy
;
97 native_remainder
= absy
- native_remainder
;
98 } else if (cmp
== 0) {
102 native_remainder
= -native_remainder
;
105 native_remainder
= -native_remainder
;
109 native_remainder
= -native_remainder
;
112 q
= result_sign
.is_neg() ? -q
: q
;
113 if (native_remainder
== T(0.0))
114 return LIBC_NAMESPACE::fputil::copysign(T(0.0), x
);
115 return native_remainder
;
118 } // namespace fputil
119 } // namespace LIBC_NAMESPACE_DECL
121 #endif // LLVM_LIBC_SRC___SUPPORT_FPUTIL_DIVISIONANDREMAINDEROPERATIONS_H