[libc-commits] [libc] [llvm] [libc] Refactor `BigInt` (PR #86137)
Nick Desaulniers via libc-commits
libc-commits at lists.llvm.org
Wed Mar 27 09:02:57 PDT 2024
================
@@ -449,38 +553,63 @@ struct BigInt {
*this = result;
}
- // TODO: Make division work correctly for signed integers.
-
- // div takes another BigInt of the same size and divides this by it. The value
- // of this will be set to the quotient, and the return value is the remainder.
- LIBC_INLINE constexpr cpp::optional<BigInt> div(const BigInt &other) {
- BigInt remainder(0);
- if (*this < other) {
- remainder = *this;
- *this = BigInt(0);
- return remainder;
- }
- if (other == 1) {
- return remainder;
- }
- if (other == 0) {
- return cpp::nullopt;
- }
-
- BigInt quotient(0);
- BigInt subtractor = other;
- int cur_bit = static_cast<int>(subtractor.clz() - this->clz());
- subtractor.shift_left(cur_bit);
-
- for (; cur_bit >= 0 && *this > 0; --cur_bit, subtractor.shift_right(1)) {
- if (*this >= subtractor) {
- this->sub(subtractor);
- quotient = quotient | (BigInt(1) << cur_bit);
+ // Performs inplace signed / unsigned division. Returns remainder if not
+ // dividing by zero.
+ // For signed numbers it behaves like C++ signed integer division.
+ // That is by truncating the fractionnal part
+ // https://stackoverflow.com/a/3602857
+ LIBC_INLINE constexpr cpp::optional<BigInt> div(const BigInt ÷r) {
+ auto ÷nd = *this;
+ if constexpr (SIGNED) {
+ // Signed Multiword Division
+ // 1. Negate the dividend it it is negative, and similarly for the
+ // divisor.
+ // 2. Convert the divident and divisor to unsigned representation.
+ // 3. Use unsigned multiword division algorithm.
+ // 4. Convert the quotient and remainder to signed representation.
+ // 5. Negate the quotient if the dividend and divisor had opposite signs.
+ // 6. Negate the remainder if the dividend was negative.
+ const bool dividend_is_neg = dividend.is_neg();
+ const bool divider_is_neg = divider.is_neg();
+ unsigned_type udividend(dividend);
+ unsigned_type udivider(divider);
+ if (dividend_is_neg)
+ udividend.negate();
+ if (divider_is_neg)
+ udivider.negate();
+ auto maybe_remainder = udividend.div(udivider);
+ if (!maybe_remainder)
+ return cpp::nullopt;
+ unsigned_type remainder = *maybe_remainder;
+ if (dividend_is_neg != divider_is_neg)
+ udividend.negate(); // this is the quotient
+ dividend = signed_type(udividend);
+ if (dividend_is_neg)
+ remainder.negate();
+ return signed_type(remainder);
+ } else {
----------------
nickdesaulniers wrote:
If the then clause returns unconditionally, then there's no need for the `else`. You can save one level of indentation here.
https://github.com/llvm/llvm-project/pull/86137
More information about the libc-commits
mailing list