[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 &divider) {
+    auto &dividend = *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