From f1060f8170ada9c2c28ab8dde7879af4b2325749 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?ZHU=20Yuhao=20=E6=9C=B1=E5=AE=87=E6=B5=A9?= Date: Wed, 26 Mar 2025 22:53:32 +0100 Subject: [PATCH 1/4] Re-write arith for bigint --- src/decimojo/bigint/arithmetics.mojo | 124 ++++++--------------------- 1 file changed, 28 insertions(+), 96 deletions(-) diff --git a/src/decimojo/bigint/arithmetics.mojo b/src/decimojo/bigint/arithmetics.mojo index 0d48987d..0b32896d 100644 --- a/src/decimojo/bigint/arithmetics.mojo +++ b/src/decimojo/bigint/arithmetics.mojo @@ -22,7 +22,7 @@ import time import testing from decimojo.bigint.bigint import BigInt -import decimojo.bigint.comparison +from decimojo.biguint.biguint import BigUInt from decimojo.rounding_mode import RoundingMode @@ -36,55 +36,20 @@ fn add(x1: BigInt, x2: BigInt) raises -> BigInt: Returns: The sum of the two BigInts. """ - # If one of the numbers is zero, return the other number if x1.is_zero(): return x2 if x2.is_zero(): return x1 - # If signs are different, we use `subtract` instead + # If signs are different, delegate to `subtract` if x1.sign != x2.sign: return subtract(x1, -x2) - # At this point, both numbers have the same sign - # The result will have the same sign as the operands - # The result will have at most one more word than the longer operand - var result = BigInt( - List[UInt32]( - capacity=max(x1.number_of_words(), x2.number_of_words()) + 1 - ), - sign=x1.sign, - ) - result.sign = x1.sign # Result has the same sign as the operands - - var carry: UInt32 = 0 - var ith: Int = 0 - var sum_of_words: UInt32 = 0 - - # Add corresponding words from both numbers - while ith < len(x1.magnitude.words) or ith < len(x2.magnitude.words): - sum_of_words = carry - - # Add x1's word if available - if ith < len(x1.magnitude.words): - sum_of_words += x1.magnitude.words[ith] - - # Add x2's word if available - if ith < len(x2.magnitude.words): - sum_of_words += x2.magnitude.words[ith] + # Same sign: add magnitudes and preserve the sign + var magnitude: BigUInt = x1.magnitude + x2.magnitude - # Compute new word and carry - carry = UInt32(sum_of_words // 1_000_000_000) - result.magnitude.words.append(UInt32(sum_of_words % 1_000_000_000)) - - ith += 1 - - # Handle final carry if it exists - if carry > 0: - result.magnitude.words.append(carry) - - return result^ + return BigInt(magnitude^, sign=x1.sign) fn subtract(x1: BigInt, x2: BigInt) raises -> BigInt: @@ -104,69 +69,29 @@ fn subtract(x1: BigInt, x2: BigInt) raises -> BigInt: if x1.is_zero(): return -x2 - # If signs are different, we use `add` instead + # If signs are different, delegate to `add` if x1.sign != x2.sign: - return add(x1, -x2) + return x1 + (-x2) - # At this point, both numbers have the same sign - # We need to determine which number has the larger absolute value - var comparison_result = decimojo.bigint.comparison.compare_absolute(x1, x2) + # Same sign, compare magnitudes to determine result sign and operation + var comparison_result = x1.magnitude.compare(x2.magnitude) if comparison_result == 0: - # |x1| = |x2| - return BigInt() # Return zero - - # The result will have no more words than the larger operand - var result = BigInt( - List[UInt32](capacity=max(x1.number_of_words(), x2.number_of_words())), - sign=False, - ) - var borrow: Int32 = 0 - var ith: Int = 0 - var difference: Int32 = 0 # Int32 is sufficient for the difference - - if comparison_result > 0: - # |x1| > |x2| - result.sign = x1.sign - while ith < len(x1.magnitude.words): - # Subtract the borrow - difference = Int32(x1.magnitude.words[ith]) - borrow - # Subtract smaller's word if available - if ith < len(x2.magnitude.words): - difference -= Int32(x2.magnitude.words[ith]) - # Handle borrowing if needed - if difference < Int32(0): - difference += Int32(1_000_000_000) - borrow = Int32(1) - else: - borrow = Int32(0) - result.magnitude.words.append(UInt32(difference)) - ith += 1 + return BigInt() # Equal magnitudes result in zero - else: - # |x1| < |x2| - # Same as above, but we swap x1 and x2 - result.sign = not x2.sign - while ith < len(x2.magnitude.words): - difference = Int32(x2.magnitude.words[ith]) - borrow - if ith < len(x1.magnitude.words): - difference -= Int32(x1.magnitude.words[ith]) - if difference < Int32(0): - difference += Int32(1_000_000_000) - borrow = Int32(1) - else: - borrow = Int32(0) - result.magnitude.words.append(UInt32(difference)) - ith += 1 + var magnitude: BigUInt + var sign: Bool + if comparison_result > 0: # |x1| > |x2| + # Subtract smaller from larger + magnitude = x1.magnitude - x2.magnitude + sign = x1.sign - # Remove trailing zeros - while ( - len(result.magnitude.words) > 1 - and result.magnitude.words[len(result.magnitude.words) - 1] == 0 - ): - result.magnitude.words.resize(len(result.magnitude.words) - 1) + else: # |x1| < |x2| + # Subtract larger from smaller and negate the result + magnitude = x2.magnitude - x1.magnitude + sign = not x1.sign - return result^ + return BigInt(magnitude^, sign=sign) fn negative(x: BigInt) -> BigInt: @@ -177,7 +102,14 @@ fn negative(x: BigInt) -> BigInt: Returns: A new BigInt containing the negative of x. + + Notes: + `BigInt` does allow signed zeros, so the negative of zero is zero. """ + # If x is zero, return zero + if x.is_zero(): + return BigInt() + var result = x result.sign = not result.sign return result^ From cc9db018a925799a04657109f2e31be141afb1b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?ZHU=20Yuhao=20=E6=9C=B1=E5=AE=87=E6=B5=A9?= Date: Wed, 26 Mar 2025 23:34:03 +0100 Subject: [PATCH 2/4] Update --- src/decimojo/bigint/arithmetics.mojo | 251 +------ tests/bigint/test_bigint_truncate_divide.mojo | 627 ++++++++++++++++++ 2 files changed, 639 insertions(+), 239 deletions(-) create mode 100644 tests/bigint/test_bigint_truncate_divide.mojo diff --git a/src/decimojo/bigint/arithmetics.mojo b/src/decimojo/bigint/arithmetics.mojo index 0b32896d..58eab0c5 100644 --- a/src/decimojo/bigint/arithmetics.mojo +++ b/src/decimojo/bigint/arithmetics.mojo @@ -217,7 +217,7 @@ fn floor_divide(x1: BigInt, x2: BigInt) raises -> BigInt: x2: The divisor. Returns: - The quotient of x1 // x2, rounded toward negative infinity. + The quotient of x1 / x2, rounded toward negative infinity. """ if x2.is_zero(): @@ -226,6 +226,10 @@ fn floor_divide(x1: BigInt, x2: BigInt) raises -> BigInt: if x1.is_zero(): return BigInt() + # For floor division, the sign rules are: + # (1) Same signs: result is positive, use `floor_divide` on magnitudes + # (1) Different signs: result is negative, use `ceil_divide` on magnitudes + if x1.sign == x2.sign: # Use floor (truncate) division between magnitudes return BigInt(x1.magnitude.floor_divide(x2.magnitude), sign=False) @@ -250,233 +254,14 @@ fn truncate_divide(x1: BigInt, x2: BigInt) raises -> BigInt: Raises: ValueError: If the divisor is zero. """ - # CASE: Division by zero if x2.is_zero(): raise Error("Error in `truncate_divide`: Division by zero") - # CASE: Dividend is zero if x1.is_zero(): return BigInt() # Return zero - # CASE: Division by one or negative one - if x2.is_one_or_minus_one(): - var result = x1 # Copy dividend - # If divisor is -1, negate the result - if x2.sign: - result.sign = not result.sign - return result - - # CASE: Single words division - if len(x1.magnitude.words) == 1 and len(x2.magnitude.words) == 1: - var result = BigInt( - UInt32(x1.magnitude.words[0] // x2.magnitude.words[0]), - sign=x1.sign != x2.sign, - ) - return result - - # CASE: Powers of 10 - if x2.magnitude.is_power_of_10(): - # Divisor is 10^n - # Remove the last words (10^9) and shift the rest - var result: BigInt - if x2.number_of_words() == 1: - result = x1 - else: - var word_shift = x2.number_of_words() - 1 - # If we need to drop more words than exists, result is zero - if word_shift >= len(x1.magnitude.words): - return BigInt() - # Create result with the remaining words - result = BigInt(List[UInt32](), sign=False) - for i in range(word_shift, len(x1.magnitude.words)): - result.magnitude.words.append(x1.magnitude.words[i]) - - # Get the last word of the divisor - var x2_word = x2.magnitude.words[len(x2.magnitude.words) - 1] - var carry = UInt32(0) - var power_of_carry = UInt32(1_000_000_000) // x2_word - for i in range(len(result.magnitude.words) - 1, -1, -1): - var quot = result.magnitude.words[i] // x2_word - var rem = result.magnitude.words[i] % x2_word - result.magnitude.words[i] = quot + carry * power_of_carry - carry = rem - - # Remove leading zeros - while ( - len(result.magnitude.words) > 1 - and result.magnitude.words[len(result.magnitude.words) - 1] == 0 - ): - result.magnitude.words.resize(len(result.magnitude.words) - 1) - - result.sign = x1.sign != x2.sign - return result - - # CASE: |dividend| < |divisor| - if x1.compare_absolute(x2) < 0: - return BigInt() # Return zero - - # CASE: |dividend| == |divisor| - if x1.compare_absolute(x2) == 0: - return BigInt(UInt32(1), sign=x1.sign != x2.sign) - - # CASE: division by a single-word number - if len(x2.magnitude.words) == 1: - var divisor_value = x2.magnitude.words[0] - var result = BigInt(List[UInt32](), sign=False) - var temp_remainder: UInt64 = 0 - - # Process from most significant word to least significant - for i in range(len(x1.magnitude.words) - 1, -1, -1): - # Combine remainder with current digit - var current = temp_remainder * 1_000_000_000 + UInt64( - x1.magnitude.words[i] - ) - - # Calculate quotient and new remainder - var quotient_digit = current // UInt64(divisor_value) - temp_remainder = current % UInt64(divisor_value) - - # Only add significant digits to the result - # This avoids leading zeros - if len(result.magnitude.words) > 0 or quotient_digit > 0: - result.magnitude.words.append(UInt32(quotient_digit)) - - # If no digits were added, result is zero - if len(result.magnitude.words) == 0: - result.magnitude.words.append(0) - - # To match the expected base-10^9 representation, - # we need to reverse the order of the words in the result - var reversed_result = BigInt( - List[UInt32](capacity=len(result.magnitude.words)), sign=False - ) - for i in range(len(result.magnitude.words) - 1, -1, -1): - reversed_result.magnitude.words.append(result.magnitude.words[i]) - - # Set the sign - reversed_result.sign = x1.sign != x2.sign - return reversed_result - - # CASE: multi-word divisors - # Initialize result and working copy of dividend - var result = BigInt( - List[UInt32](capacity=len(x1.magnitude.words)), sign=False - ) - var remainder = absolute(x1) - var normalized_divisor = absolute(x2) - - # Calculate the number of significant words in each operand - var n = len(remainder.magnitude.words) - while n > 0 and remainder.magnitude.words[n - 1] == 0: - n -= 1 - - var m = len(normalized_divisor.magnitude.words) - while m > 0 and normalized_divisor.magnitude.words[m - 1] == 0: - m -= 1 - - # If divisor has more significant digits than dividend, result is zero - if m > n: - return BigInt() - - # Shift divisor left to align with dividend - var d = n - m - - # Initialize result with zeros - for _ in range(d + 1): - result.magnitude.words.append(0) - - # Working variables for the division algorithm - var j = d - - # Main division loop - while j >= 0: - # Calculate quotient digit estimate - var dividend_part: UInt64 = 0 - - # Get the relevant part of the dividend for this step - if j + m < n: - dividend_part = UInt64(remainder.magnitude.words[j + m]) - if j + m - 1 < n: - dividend_part = dividend_part * 1_000_000_000 + UInt64( - remainder.magnitude.words[j + m - 1] - ) - elif j + m - 1 < n: - dividend_part = UInt64(remainder.magnitude.words[j + m - 1]) - - # Calculate quotient digit (cap at MAX_DIGIT) - var divisor_high = UInt64(normalized_divisor.magnitude.words[m - 1]) - if divisor_high == 0: - divisor_high = 1 # Avoid division by zero - var q = min(dividend_part // divisor_high, UInt64(999_999_999)) - - # Create trial product: q * divisor - var trial_product = normalized_divisor * BigInt(UInt32(q), sign=False) - - # Shift trial product left j positions - var shifted_product = BigInt(List[UInt32](), sign=False) - for _ in range(j): - shifted_product.magnitude.words.append(0) - for word in trial_product.magnitude.words: - shifted_product.magnitude.words.append(word[]) - - # Use binary search for quotient adjustment - if shifted_product.compare_absolute(remainder) > 0: - # Initial estimate was too high, use binary search to find correct q - var low: UInt64 = 0 - var high: UInt64 = q - 1 - - while low <= high: - var mid: UInt64 = (low + high) / 2 - - # Recalculate trial product with new q - trial_product = normalized_divisor * BigInt( - UInt32(mid), sign=False - ) - - # Recalculate shifted product - shifted_product = BigInt(List[UInt32](), sign=False) - for _ in range(j): - shifted_product.magnitude.words.append(0) - for word in trial_product.magnitude.words: - shifted_product.magnitude.words.append(word[]) - - if shifted_product.compare_absolute(remainder) <= 0: - # This quotient works, try a larger one - q = mid # Keep track of best quotient found so far - low = mid + 1 - else: - # Too large, try smaller - high = mid - 1 - - # Recalculate final product with best q found - trial_product = normalized_divisor * BigInt(UInt32(q), sign=False) - - # Recalculate final shifted product - shifted_product = BigInt(List[UInt32](), sign=False) - for _ in range(j): - shifted_product.magnitude.words.append(0) - for word in trial_product.magnitude.words: - shifted_product.magnitude.words.append(word[]) - - # Store quotient digit - result.magnitude.words[j] = UInt32(q) - - # Subtract shifted product from remainder - remainder = subtract(remainder, shifted_product) - - # Move to next position - j -= 1 - - # Remove leading zeros - while ( - len(result.magnitude.words) > 1 - and result.magnitude.words[len(result.magnitude.words) - 1] == 0 - ): - result.magnitude.words.resize(len(result.magnitude.words) - 1) - - # Set the sign - result.sign = x1.sign != x2.sign - return result + var magnitude = x1.magnitude.floor_divide(x2.magnitude) + return BigInt(magnitude^, sign=x1.sign != x2.sign) fn floor_modulo(x1: BigInt, x2: BigInt) raises -> BigInt: @@ -495,6 +280,9 @@ fn floor_modulo(x1: BigInt, x2: BigInt) raises -> BigInt: if x2.is_zero(): raise Error("Error in `floor_modulo`: Division by zero") + if x1.is_zero(): + return BigInt() # Return zero + if x1.sign == x2.sign: # Use floor (truncate) division between magnitudes return BigInt(x1.magnitude.floor_modulo(x2.magnitude), sign=x2.sign) @@ -519,26 +307,11 @@ fn truncate_modulo(x1: BigInt, x2: BigInt) raises -> BigInt: Raises: ValueError: If the divisor is zero. """ - # CASE: Division by zero if x2.is_zero(): raise Error("Error in `truncate_modulo`: Division by zero") - # CASE: Dividend is zero if x1.is_zero(): return BigInt() # Return zero - # CASE: Divisor is one or negative one - no remainder - if x2.is_one_or_minus_one(): - return BigInt() # Always divisible with no remainder - - # CASE: |dividend| < |divisor| - the remainder is the dividend itself - if decimojo.bigint.comparison.compare_absolute(x1, x2) < 0: - return x1 - - # Calculate quotient with truncation - var quotient = truncate_divide(x1, x2) - - # Calculate remainder: dividend - (divisor * quotient) - var remainder = subtract(x1, multiply(x2, quotient)) - - return remainder + var magnitude = x1.magnitude.floor_modulo(x2.magnitude) + return BigInt(magnitude^, sign=x1.sign) diff --git a/tests/bigint/test_bigint_truncate_divide.mojo b/tests/bigint/test_bigint_truncate_divide.mojo new file mode 100644 index 00000000..7a05b9fb --- /dev/null +++ b/tests/bigint/test_bigint_truncate_divide.mojo @@ -0,0 +1,627 @@ +""" +Comprehensive tests for the truncate_divide operation of the BigInt type. +BigInt is a signed integer type, so these tests focus on division with both positive and negative numbers. + +Note: Python's division is floor division (rounds toward negative infinity), +while truncate division rounds toward zero. This means for negative numbers, +the results will differ between floor and truncate division. +""" + +import testing +from decimojo.bigint.bigint import BigInt +import decimojo.bigint.arithmetics +from python import Python + + +fn test_basic_truncate_division_positive() raises: + """Test basic truncate division cases with positive numbers.""" + print("Testing basic truncate division with positive numbers...") + + # For positive numbers, truncate division behaves the same as floor division + + # Test case 1: Simple division with no remainder + var a1 = BigInt("10") + var b1 = BigInt("2") + var result1 = decimojo.bigint.arithmetics.truncate_divide(a1, b1) + testing.assert_equal( + String(result1), "5", "10 / 2 should equal 5, got " + String(result1) + ) + + # Test case 2: Division with remainder (truncate toward zero) + var a2 = BigInt("10") + var b2 = BigInt("3") + var result2 = decimojo.bigint.arithmetics.truncate_divide(a2, b2) + testing.assert_equal( + String(result2), "3", "10 / 3 should equal 3, got " + String(result2) + ) + + # Test case 3: Division results in zero (smaller / larger) + var a3 = BigInt("3") + var b3 = BigInt("10") + var result3 = decimojo.bigint.arithmetics.truncate_divide(a3, b3) + testing.assert_equal( + String(result3), "0", "3 / 10 should equal 0, got " + String(result3) + ) + + # Test case 4: Division by 1 + var a4 = BigInt("42") + var b4 = BigInt("1") + var result4 = decimojo.bigint.arithmetics.truncate_divide(a4, b4) + testing.assert_equal( + String(result4), "42", "42 / 1 should equal 42, got " + String(result4) + ) + + # Test case 5: Large number division + var a5 = BigInt("1000000000000") + var b5 = BigInt("1000000") + var result5 = decimojo.bigint.arithmetics.truncate_divide(a5, b5) + testing.assert_equal( + String(result5), + "1000000", + "1000000000000 / 1000000 should equal 1000000, got " + String(result5), + ) + + print("✓ Basic truncate division with positive numbers tests passed!") + + +fn test_basic_truncate_division_negative() raises: + """Test basic truncate division cases with negative numbers.""" + print("Testing basic truncate division with negative numbers...") + + # This is where truncate division differs from floor division + + # Test case 1: Negative dividend, positive divisor + var a1 = BigInt("-10") + var b1 = BigInt("2") + var result1 = decimojo.bigint.arithmetics.truncate_divide(a1, b1) + testing.assert_equal( + String(result1), "-5", "-10 / 2 should equal -5, got " + String(result1) + ) + + # Test case 2: Negative dividend, negative divisor + var a2 = BigInt("-10") + var b2 = BigInt("-2") + var result2 = decimojo.bigint.arithmetics.truncate_divide(a2, b2) + testing.assert_equal( + String(result2), "5", "-10 / -2 should equal 5, got " + String(result2) + ) + + # Test case 3: Positive dividend, negative divisor + var a3 = BigInt("10") + var b3 = BigInt("-2") + var result3 = decimojo.bigint.arithmetics.truncate_divide(a3, b3) + testing.assert_equal( + String(result3), "-5", "10 / -2 should equal -5, got " + String(result3) + ) + + # Test case 4: Negative dividend with remainder (truncate division case) + var a4 = BigInt("-7") + var b4 = BigInt("3") + var result4 = decimojo.bigint.arithmetics.truncate_divide(a4, b4) + + # In truncate division, -7/3 = -2.333... -> -2 (truncate toward zero) + # In floor division, -7//3 = -3 (round toward negative infinity) + testing.assert_equal( + String(result4), "-2", "-7 / 3 should equal -2, got " + String(result4) + ) + + # Test case 5: Key test for truncate division (negative numbers) + var a5 = BigInt("-5") + var b5 = BigInt("2") + var result5 = decimojo.bigint.arithmetics.truncate_divide(a5, b5) + + # In truncate division, -5/2 = -2.5 -> -2 + # In floor division, -5//2 = -3 + testing.assert_equal( + String(result5), "-2", "-5 / 2 should equal -2, got " + String(result5) + ) + + print("✓ Basic truncate division with negative numbers tests passed!") + + +fn test_mixed_sign_truncate_division() raises: + """Test truncate division cases with mixed signs.""" + print("Testing truncate division with mixed signs...") + + # Test case 1: Negative / positive with exact division + var a1 = BigInt("-6") + var b1 = BigInt("3") + var result1 = decimojo.bigint.arithmetics.truncate_divide(a1, b1) + testing.assert_equal( + String(result1), "-2", "-6 / 3 should equal -2, got " + String(result1) + ) + + # Test case 2: Negative / negative with exact division + var a2 = BigInt("-6") + var b2 = BigInt("-3") + var result2 = decimojo.bigint.arithmetics.truncate_divide(a2, b2) + testing.assert_equal( + String(result2), "2", "-6 / -3 should equal 2, got " + String(result2) + ) + + # Test case 3: Positive / negative with exact division + var a3 = BigInt("6") + var b3 = BigInt("-3") + var result3 = decimojo.bigint.arithmetics.truncate_divide(a3, b3) + testing.assert_equal( + String(result3), "-2", "6 / -3 should equal -2, got " + String(result3) + ) + + # Test case 4: Negative / positive with remainder (critical truncate division case) + var a4 = BigInt("-7") + var b4 = BigInt("4") + var result4 = decimojo.bigint.arithmetics.truncate_divide(a4, b4) + + # In truncate division, -7/4 = -1.75 -> -1 + # In floor division, -7//4 = -2 + testing.assert_equal( + String(result4), "-1", "-7 / 4 should equal -1, got " + String(result4) + ) + + # Test case 5: Positive / negative with remainder (critical truncate division case) + var a5 = BigInt("7") + var b5 = BigInt("-4") + var result5 = decimojo.bigint.arithmetics.truncate_divide(a5, b5) + + # In truncate division, 7/-4 = -1.75 -> -1 + # In floor division, 7//-4 = -2 + testing.assert_equal( + String(result5), "-1", "7 / -4 should equal -1, got " + String(result5) + ) + + print("✓ Truncate division with mixed signs tests passed!") + + +fn test_zero_handling() raises: + """Test truncate division cases involving zero.""" + print("Testing zero handling in truncate division...") + + # Test case 1: Zero dividend, positive divisor + var a1 = BigInt("0") + var b1 = BigInt("5") + var result1 = decimojo.bigint.arithmetics.truncate_divide(a1, b1) + testing.assert_equal( + String(result1), "0", "0 / 5 should equal 0, got " + String(result1) + ) + + # Test case 2: Zero dividend, negative divisor + var a2 = BigInt("0") + var b2 = BigInt("-5") + var result2 = decimojo.bigint.arithmetics.truncate_divide(a2, b2) + testing.assert_equal( + String(result2), "0", "0 / -5 should equal 0, got " + String(result2) + ) + + # Test case 3: Division by zero should raise an error + var a3 = BigInt("10") + var b3 = BigInt("0") + var exception_caught = False + try: + var _result3 = decimojo.bigint.arithmetics.truncate_divide(a3, b3) + except: + exception_caught = True + testing.assert_true( + exception_caught, "Division by zero should raise an error" + ) + + # Test case 4: Negative number division by zero should raise an error + var a4 = BigInt("-10") + var b4 = BigInt("0") + exception_caught = False + try: + var _result4 = decimojo.bigint.arithmetics.truncate_divide(a4, b4) + except: + exception_caught = True + testing.assert_true( + exception_caught, "Division by zero should raise an error" + ) + + print("✓ Zero handling tests passed!") + + +fn test_large_number_division() raises: + """Test truncate division with very large numbers.""" + print("Testing truncate division with large numbers...") + + # Test case 1: Large positive number divided by small number + var a1 = BigInt("1" + "0" * 50) # 10^50 + var b1 = BigInt("7") + var result1 = decimojo.bigint.arithmetics.truncate_divide(a1, b1) + testing.assert_equal( + String(result1), + "14285714285714285714285714285714285714285714285714", + "10^50 / 7 gave incorrect result", + ) + print("passed: {} / {} = {}".format(a1, b1, result1)) + + # Test case 2: Large negative number divided by small number + var a2 = BigInt("-" + "1" + "0" * 50) # -10^50 + var b2 = BigInt("7") + var result2 = decimojo.bigint.arithmetics.truncate_divide(a2, b2) + testing.assert_equal( + String(result2), + "-14285714285714285714285714285714285714285714285714", + "-10^50 / 7 gave incorrect result", + ) + print("passed: {} / {} = {}".format(a2, b2, result2)) + + # Test case 3: Large positive number divided by small negative number + var a3 = BigInt("1" + "0" * 50) # 10^50 + var b3 = BigInt("-7") + var result3 = decimojo.bigint.arithmetics.truncate_divide(a3, b3) + testing.assert_equal( + String(result3), + "-14285714285714285714285714285714285714285714285714", + "10^50 / -7 gave incorrect result", + ) + print("passed: {} / {} = {}".format(a3, b3, result3)) + + # Test case 4: Large negative number divided by small negative number + var a4 = BigInt("-" + "1" + "0" * 50) # -10^50 + var b4 = BigInt("-7") + var result4 = decimojo.bigint.arithmetics.truncate_divide(a4, b4) + testing.assert_equal( + String(result4), + "14285714285714285714285714285714285714285714285714", + "-10^50 / -7 gave incorrect result", + ) + print("passed: {} / {} = {}".format(a4, b4, result4)) + + # Test case 5: Large number divided by large number (same sign) + var a5 = BigInt("9" * 30) # 30 nines + var b5 = BigInt("9" * 15) # 15 nines + var result5 = decimojo.bigint.arithmetics.truncate_divide(a5, b5) + testing.assert_equal( + String(result5), + "1000000000000001", + "large / large (same sign) gave incorrect result", + ) + print("passed: {} / {} = {}".format(a5, b5, result5)) + + # Test case 6: Large number divided by large number (opposite sign) + var a6 = BigInt("9" * 30) # 30 nines + var b6 = BigInt("-" + "9" * 15) # -15 nines + var result6 = decimojo.bigint.arithmetics.truncate_divide(a6, b6) + testing.assert_equal( + String(result6), + "-1000000000000001", + "large / large (opposite sign) gave incorrect result", + ) + print("passed: {} / {} = {}".format(a6, b6, result6)) + + print("✓ Large number division tests passed!") + + +fn test_truncate_modulo_identity() raises: + """Test mathematical properties of truncate division and modulo.""" + print("Testing mathematical identity: a = (a / b) * b + (a % b)...") + + # Test case 1: Positive dividend, positive divisor + var a1 = BigInt("17") + var b1 = BigInt("5") + var quotient1 = decimojo.bigint.arithmetics.truncate_divide(a1, b1) + var remainder1 = decimojo.bigint.arithmetics.truncate_modulo(a1, b1) + var reconstructed1 = quotient1 * b1 + remainder1 + + testing.assert_equal( + String(reconstructed1), + String(a1), + "(a / b) * b + (a % b) should equal a for positive numbers", + ) + testing.assert_equal(String(quotient1), "3", "17/5 should equal 3") + testing.assert_equal(String(remainder1), "2", "17%5 should equal 2") + + # Test case 2: Negative dividend, positive divisor + var a2 = BigInt("-17") + var b2 = BigInt("5") + var quotient2 = decimojo.bigint.arithmetics.truncate_divide(a2, b2) + var remainder2 = decimojo.bigint.arithmetics.truncate_modulo(a2, b2) + var reconstructed2 = quotient2 * b2 + remainder2 + + testing.assert_equal( + String(reconstructed2), + String(a2), + "(a / b) * b + (a % b) should equal a for negative dividend", + ) + testing.assert_equal(String(quotient2), "-3", "-17/5 should equal -3") + testing.assert_equal(String(remainder2), "-2", "-17%5 should equal -2") + + # Test case 3: Positive dividend, negative divisor + var a3 = BigInt("17") + var b3 = BigInt("-5") + var quotient3 = decimojo.bigint.arithmetics.truncate_divide(a3, b3) + var remainder3 = decimojo.bigint.arithmetics.truncate_modulo(a3, b3) + var reconstructed3 = quotient3 * b3 + remainder3 + + testing.assert_equal( + String(reconstructed3), + String(a3), + "(a / b) * b + (a % b) should equal a for negative divisor", + ) + testing.assert_equal(String(quotient3), "-3", "17/-5 should equal -3") + testing.assert_equal(String(remainder3), "2", "17%-5 should equal 2") + + # Test case 4: Negative dividend, negative divisor + var a4 = BigInt("-17") + var b4 = BigInt("-5") + var quotient4 = decimojo.bigint.arithmetics.truncate_divide(a4, b4) + var remainder4 = decimojo.bigint.arithmetics.truncate_modulo(a4, b4) + var reconstructed4 = quotient4 * b4 + remainder4 + + testing.assert_equal( + String(reconstructed4), + String(a4), + ( + "(a / b) * b + (a % b) should equal a for negative dividend and" + " divisor" + ), + ) + testing.assert_equal(String(quotient4), "3", "-17/-5 should equal 3") + testing.assert_equal(String(remainder4), "-2", "-17%-5 should equal -2") + + # Test case 5: With large numbers + var a5 = BigInt("12345678901234567890") + var b5 = BigInt("987654321") + var quotient5 = decimojo.bigint.arithmetics.truncate_divide(a5, b5) + var remainder5 = decimojo.bigint.arithmetics.truncate_modulo(a5, b5) + var reconstructed5 = quotient5 * b5 + remainder5 + + testing.assert_equal( + String(reconstructed5), + String(a5), + "(a / b) * b + (a % b) should equal a for large numbers", + ) + + print("✓ Mathematical identity tests passed!") + + +fn test_truncate_division_rounding() raises: + """Test that truncate division correctly rounds toward zero.""" + print("Testing truncate division rounding behavior...") + + # Test case 1: Positive / positive with remainder + var a1 = BigInt("7") + var b1 = BigInt("2") + var result1 = decimojo.bigint.arithmetics.truncate_divide(a1, b1) + testing.assert_equal( + String(result1), "3", "7 / 2 should equal 3, got " + String(result1) + ) + + # Test case 2: Negative / positive with remainder (key truncate division case) + var a2 = BigInt("-7") + var b2 = BigInt("2") + var result2 = decimojo.bigint.arithmetics.truncate_divide(a2, b2) + + # In truncate division, -7/2 = -3.5 -> -3 (truncate toward zero) + # In floor division, -7//2 = -4 (round toward negative infinity) + testing.assert_equal( + String(result2), "-3", "-7 / 2 should equal -3, got " + String(result2) + ) + + # Test case 3: Positive / negative with remainder (key truncate division case) + var a3 = BigInt("7") + var b3 = BigInt("-2") + var result3 = decimojo.bigint.arithmetics.truncate_divide(a3, b3) + + # In truncate division, 7/-2 = -3.5 -> -3 (truncate toward zero) + # In floor division, 7//-2 = -4 (round toward negative infinity) + testing.assert_equal( + String(result3), "-3", "7 / -2 should equal -3, got " + String(result3) + ) + + # Test case 4: Negative / negative with remainder + var a4 = BigInt("-7") + var b4 = BigInt("-2") + var result4 = decimojo.bigint.arithmetics.truncate_divide(a4, b4) + testing.assert_equal( + String(result4), "3", "-7 / -2 should equal 3, got " + String(result4) + ) + + # Test case 5: Different dividend/divisor patterns + var a5 = BigInt("1") + var b5 = BigInt("4") + var result5 = decimojo.bigint.arithmetics.truncate_divide(a5, b5) + testing.assert_equal( + String(result5), "0", "1 / 4 should equal 0, got " + String(result5) + ) + + # Test case 6: Negative small / positive large + var a6 = BigInt("-1") + var b6 = BigInt("4") + var result6 = decimojo.bigint.arithmetics.truncate_divide(a6, b6) + # In truncate division, -1/4 = -0.25 -> 0 (truncate toward zero) + # In floor division, -1//4 = -1 (round toward negative infinity) + testing.assert_equal( + String(result6), "0", "-1 / 4 should equal 0, got " + String(result6) + ) + + # Test case 7: Another truncate vs. floor example + var a7 = BigInt("-9") + var b7 = BigInt("5") + var result7 = decimojo.bigint.arithmetics.truncate_divide(a7, b7) + # In truncate division, -9/5 = -1.8 -> -1 + # In floor division, -9//5 = -2 + testing.assert_equal( + String(result7), "-1", "-9 / 5 should equal -1, got " + String(result7) + ) + + print("✓ Truncate division rounding tests passed!") + + +fn test_edge_cases() raises: + """Test edge cases for truncate division.""" + print("Testing edge cases for truncate division...") + + # Test case 1: Maximum divisor (just below dividend) + var a1 = BigInt("1000") + var b1 = BigInt("999") + var result1 = decimojo.bigint.arithmetics.truncate_divide(a1, b1) + testing.assert_equal(String(result1), "1", "1000 / 999 should equal 1") + + # Test case 2: Maximum negative divisor (just below dividend in magnitude) + var a2 = BigInt("1000") + var b2 = BigInt("-999") + var result2 = decimojo.bigint.arithmetics.truncate_divide(a2, b2) + testing.assert_equal(String(result2), "-1", "1000 / -999 should equal -1") + + # Test case 3: Consecutive numbers (positive) + var a3 = BigInt("101") + var b3 = BigInt("100") + var result3 = decimojo.bigint.arithmetics.truncate_divide(a3, b3) + testing.assert_equal(String(result3), "1", "101 / 100 should equal 1") + + # Test case 4: Consecutive numbers (negative) + var a4 = BigInt("-101") + var b4 = BigInt("100") + var result4 = decimojo.bigint.arithmetics.truncate_divide(a4, b4) + testing.assert_equal(String(result4), "-1", "-101 / 100 should equal -1") + + # Test case 5: Equal numbers (positive) + var a5 = BigInt("9" * 100) # 100 nines + var b5 = BigInt("9" * 100) # 100 nines + var result5 = decimojo.bigint.arithmetics.truncate_divide(a5, b5) + testing.assert_equal( + String(result5), + "1", + "Equal large positive numbers division should equal 1", + ) + + # Test case 6: Equal numbers (negative) + var a6 = BigInt("-" + "9" * 100) + var b6 = BigInt("-" + "9" * 100) + var result6 = decimojo.bigint.arithmetics.truncate_divide(a6, b6) + testing.assert_equal( + String(result6), + "1", + "Equal large negative numbers division should equal 1", + ) + + # Test case 7: Comparing truncate division with floor division + var a7 = BigInt("-23") + var b7 = BigInt("5") + var truncate_result = decimojo.bigint.arithmetics.truncate_divide(a7, b7) + + testing.assert_equal( + String(truncate_result), + "-4", + "Truncate division of -23 by 5 should equal -4", + ) + + # Test case 8: Powers of 10 division + var a8 = BigInt("1" + "0" * 20) # 10^20 + var b8 = BigInt("1" + "0" * 5) # 10^5 + var result8 = decimojo.bigint.arithmetics.truncate_divide(a8, b8) + testing.assert_equal( + String(result8), + "1" + "0" * 15, + "Powers of 10 truncate division gave incorrect result", + ) + + print("✓ Edge cases tests passed!") + + +fn test_python_comparison() raises: + """Compare BigInt truncate_divide results with Python's int division.""" + print("Testing truncate division against Python's int division...") + + var py = Python.import_module("builtins") + + # Test case 1: Simple positive division + var a1 = BigInt("42") + var b1 = BigInt("5") + var mojo_result = decimojo.bigint.arithmetics.truncate_divide(a1, b1) + var py_result = py.int(42) // py.int(5) + testing.assert_equal( + String(mojo_result), + String(py_result), + "Truncate division differs from Python for positive numbers", + ) + + # Test case 2: Negative dividend + var a2 = BigInt("-42") + var b2 = BigInt("5") + var mojo_result2 = decimojo.bigint.arithmetics.truncate_divide(a2, b2) + # Note: Python uses floor division, not truncate division + # For negative numbers, we need to calculate truncate division explicitly + + testing.assert_equal( + String(mojo_result2), "-8", "Truncate division should be -8 for -42/5" + ) + print("Note: Python's // does floor division (-9), while truncate gives -8") + + # Test case 3: Large numbers + var a3 = BigInt("9" * 20) + var b3 = BigInt("3") + var mojo_result3 = decimojo.bigint.arithmetics.truncate_divide(a3, b3) + var py_div3 = py.int("9" * 20) // py.int(3) + + testing.assert_equal( + String(mojo_result3), + String(py_div3), + "Truncate division differs from Python for large positive numbers", + ) + + print( + "✓ Python comparison tests passed with expected differences for" + " negative numbers!" + ) + + +fn run_test_with_error_handling( + test_fn: fn () raises -> None, test_name: String +) raises: + """Helper function to run a test function with error handling and reporting. + """ + try: + print("\n" + "=" * 50) + print("RUNNING: " + test_name) + print("=" * 50) + test_fn() + print("\n✓ " + test_name + " passed\n") + except e: + print("\n✗ " + test_name + " FAILED!") + print("Error message: " + String(e)) + raise e + + +fn main() raises: + print("=========================================") + print("Running BigInt Truncate Division Tests") + print("=========================================") + + print("Note: Truncate division rounds toward zero, while floor division") + print("rounds toward negative infinity.") + print("For positive numbers, both yield the same results.") + print("For negative numbers divided by positive numbers:") + print(" -7/3 = -2.33... → truncate: -2, floor: -3") + print("For positive numbers divided by negative numbers:") + print(" 7/-3 = -2.33... → truncate: -2, floor: -3") + print() + + run_test_with_error_handling( + test_basic_truncate_division_positive, + "Basic truncate division with positive numbers test", + ) + run_test_with_error_handling( + test_basic_truncate_division_negative, + "Basic truncate division with negative numbers test", + ) + run_test_with_error_handling( + test_mixed_sign_truncate_division, "Mixed sign truncate division test" + ) + run_test_with_error_handling(test_zero_handling, "Zero handling test") + run_test_with_error_handling( + test_large_number_division, "Large number division test" + ) + run_test_with_error_handling( + test_truncate_modulo_identity, "Mathematical identity test" + ) + run_test_with_error_handling( + test_truncate_division_rounding, "Division rounding behavior test" + ) + run_test_with_error_handling(test_edge_cases, "Edge cases test") + run_test_with_error_handling( + test_python_comparison, "Python comparison test" + ) + + print("All BigInt truncate division tests passed!") From 980d137c028cb703630096d1e896171c80876a8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?ZHU=20Yuhao=20=E6=9C=B1=E5=AE=87=E6=B5=A9?= Date: Wed, 26 Mar 2025 23:41:07 +0100 Subject: [PATCH 3/4] finish re-written --- src/decimojo/bigint/arithmetics.mojo | 68 +++------------------------- 1 file changed, 6 insertions(+), 62 deletions(-) diff --git a/src/decimojo/bigint/arithmetics.mojo b/src/decimojo/bigint/arithmetics.mojo index 58eab0c5..13bae1b9 100644 --- a/src/decimojo/bigint/arithmetics.mojo +++ b/src/decimojo/bigint/arithmetics.mojo @@ -142,69 +142,13 @@ fn multiply(x1: BigInt, x2: BigInt) raises -> BigInt: """ # CASE: One of the operands is zero if x1.is_zero() or x2.is_zero(): - return BigInt(UInt32(0), sign=x1.sign != x2.sign) - - # CASE: One of the operands is one or negative one - if x1.is_one_or_minus_one(): - var result = x2 - result.sign = x1.sign != x2.sign - return result^ - - if x2.is_one_or_minus_one(): - var result = x1 - result.sign = x1.sign != x2.sign - return result^ - - # The maximum number of words in the result is the sum of the words in the operands - var max_result_len = x1.number_of_words() + x2.number_of_words() - var result = BigInt(List[UInt32](capacity=max_result_len), sign=False) - result.sign = x1.sign != x2.sign - - # Initialize result words with zeros - for _ in range(max_result_len): - result.magnitude.words.append(0) - - # Perform the multiplication word by word (from least significant to most significant) - # x1 = x1[0] + x1[1] * 10^9 - # x2 = x2[0] + x2[1] * 10^9 - # x1 * x2 = x1[0] * x2[0] + (x1[0] * x2[1] + x1[1] * x2[0]) * 10^9 + x1[1] * x2[1] * 10^18 - var carry: UInt64 = 0 - for i in range(len(x1.magnitude.words)): - # Skip if the word is zero - if x1.magnitude.words[i] == 0: - continue - - carry = UInt64(0) - - for j in range(len(x2.magnitude.words)): - # Skip if the word is zero - if x2.magnitude.words[j] == 0: - continue - - # Calculate the product of the current words - # plus the carry from the previous multiplication - # plus the value already at this position in the result - var product = UInt64(x1.magnitude.words[i]) * UInt64( - x2.magnitude.words[j] - ) + carry + UInt64(result.magnitude.words[i + j]) - - # The lower 9 digits (base 10^9) go into the current word - # The upper digits become the carry for the next position - result.magnitude.words[i + j] = UInt32(product % 1_000_000_000) - carry = product // 1_000_000_000 - - # If there is a carry left, add it to the next position - if carry > 0: - result.magnitude.words[i + len(x2.magnitude.words)] += UInt32(carry) - - # Remove trailing zeros - while ( - len(result.magnitude.words) > 1 - and result.magnitude.words[len(result.magnitude.words) - 1] == 0 - ): - result.magnitude.words.resize(len(result.magnitude.words) - 1) + return BigInt() # Return zero regardless of sign - return result^ + # Multiply the magnitudes using BigUInt's multiplication + var result_magnitude = x1.magnitude * x2.magnitude + + # Create and return final result with correct sign + return BigInt(result_magnitude^, sign=x1.sign != x2.sign) fn floor_divide(x1: BigInt, x2: BigInt) raises -> BigInt: From 13196f656b799aaf8e011d70f7908f325feb8310 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?ZHU=20Yuhao=20=E6=9C=B1=E5=AE=87=E6=B5=A9?= Date: Wed, 26 Mar 2025 23:54:39 +0100 Subject: [PATCH 4/4] Finish --- src/decimojo/bigint/bigint.mojo | 67 ++++++++++++++++++++--------- src/decimojo/bigint/comparison.mojo | 6 +-- src/decimojo/biguint/biguint.mojo | 28 ++++++------ 3 files changed, 64 insertions(+), 37 deletions(-) diff --git a/src/decimojo/bigint/bigint.mojo b/src/decimojo/bigint/bigint.mojo index a4827380..b06b25e6 100644 --- a/src/decimojo/bigint/bigint.mojo +++ b/src/decimojo/bigint/bigint.mojo @@ -442,6 +442,14 @@ struct BigInt(Absable, IntableRaising, Writable): fn __mod__(self, other: Self) raises -> Self: return decimojo.bigint.arithmetics.floor_modulo(self, other) + @always_inline + fn __pow__(self, exponent: Self) raises -> Self: + return self.power(exponent) + + @always_inline + fn __pow__(self, exponent: Int) raises -> Self: + return self.power(exponent) + # ===------------------------------------------------------------------=== # # Basic binary augmented arithmetic assignments dunders # These methods are called to implement the binary augmented arithmetic @@ -508,20 +516,6 @@ struct BigInt(Absable, IntableRaising, Writable): # Mathematical methods that do not implement a trait (not a dunder) # ===------------------------------------------------------------------=== # - @always_inline - fn compare_absolute(self, other: Self) -> Int8: - """Compares the absolute values of two BigInts. - See `compare_absolute()` for more information. - """ - return decimojo.bigint.comparison.compare_absolute(self, other) - - @always_inline - fn compare(self, other: Self) -> Int8: - """Compares two BigInts. - See `compare()` for more information. - """ - return decimojo.bigint.comparison.compare(self, other) - @always_inline fn floor_divide(self, other: Self) raises -> Self: """Performs a floor division of two BigInts. @@ -550,6 +544,39 @@ struct BigInt(Absable, IntableRaising, Writable): """ return decimojo.bigint.arithmetics.truncate_modulo(self, other) + fn power(self, exponent: Int) raises -> Self: + """Raises the BigInt to the power of an integer exponent. + See `power()` for more information. + """ + var magnitude = self.magnitude.power(exponent) + var sign = False + if self.sign: + sign = exponent % 2 == 1 + return Self(magnitude^, sign) + + fn power(self, exponent: Self) raises -> Self: + """Raises the BigInt to the power of another BigInt. + See `power()` for more information. + """ + if exponent > Self(BigUInt(UInt32(0), UInt32(1)), sign=False): + raise Error("Error in `BigUInt.power()`: The exponent is too large") + var exponent_as_int = exponent.to_int() + return self.power(exponent_as_int) + + @always_inline + fn compare_magnitudes(self, other: Self) -> Int8: + """Compares the magnitudes of two BigInts. + See `compare_magnitudes()` for more information. + """ + return decimojo.bigint.comparison.compare_magnitudes(self, other) + + @always_inline + fn compare(self, other: Self) -> Int8: + """Compares two BigInts. + See `compare()` for more information. + """ + return decimojo.bigint.comparison.compare(self, other) + # ===------------------------------------------------------------------=== # # Other methods # ===------------------------------------------------------------------=== # @@ -578,18 +605,18 @@ struct BigInt(Absable, IntableRaising, Writable): # Internal methods # ===------------------------------------------------------------------=== # - fn internal_representation(value: BigInt): + fn internal_representation(self): """Prints the internal representation details of a BigInt.""" print("\nInternal Representation Details of BigInt") print("-----------------------------------------") - print("number: ", value) - print(" ", value.to_str_with_separators()) - print("negative: ", value.sign) - for i in range(len(value.magnitude.words)): + print("number: ", self) + print(" ", self.to_str_with_separators()) + print("negative: ", self.sign) + for i in range(len(self.magnitude.words)): print( "word", i, ": ", - String(value.magnitude.words[i]).rjust(width=9, fillchar="0"), + String(self.magnitude.words[i]).rjust(width=9, fillchar="0"), ) print("--------------------------------") diff --git a/src/decimojo/bigint/comparison.mojo b/src/decimojo/bigint/comparison.mojo index 54e0c7fc..7a554191 100644 --- a/src/decimojo/bigint/comparison.mojo +++ b/src/decimojo/bigint/comparison.mojo @@ -22,8 +22,8 @@ from decimojo.bigint.bigint import BigInt from decimojo.biguint.biguint import BigUInt -fn compare_absolute(x1: BigInt, x2: BigInt) -> Int8: - """Compares the absolute values of two numbers and returns the result. +fn compare_magnitudes(x1: BigInt, x2: BigInt) -> Int8: + """Compares the magnitudes of two numbers and returns the result. Args: x1: First number. @@ -59,7 +59,7 @@ fn compare(x1: BigInt, x2: BigInt) -> Int8: return -1 if x1.sign else 1 # Same signs: compare magnitudes - var magnitude_comparison = compare_absolute(x1, x2) + var magnitude_comparison = compare_magnitudes(x1, x2) # If both negative, reverse the comparison result return magnitude_comparison if not x1.sign else -magnitude_comparison diff --git a/src/decimojo/biguint/biguint.mojo b/src/decimojo/biguint/biguint.mojo index 505b7afe..e0b304da 100644 --- a/src/decimojo/biguint/biguint.mojo +++ b/src/decimojo/biguint/biguint.mojo @@ -675,13 +675,6 @@ struct BigUInt(Absable, IntableRaising, Writable): # Mathematical methods that do not implement a trait (not a dunder) # ===------------------------------------------------------------------=== # - @always_inline - fn compare(self, other: Self) -> Int8: - """Compares the magnitudes of two BigUInts. - See `compare()` for more information. - """ - return decimojo.biguint.comparison.compare(self, other) - @always_inline fn floor_divide(self, other: Self) raises -> Self: """Returns the result of floor dividing this number by `other`. @@ -762,11 +755,18 @@ struct BigUInt(Absable, IntableRaising, Writable): fn power(self, exponent: Self) raises -> Self: """Returns the result of raising this number to the power of `exponent`. """ - var exponent_as_int = exponent.to_int() - if exponent_as_int > 1_000_000_000: + if exponent > BigUInt(UInt32(0), UInt32(1)): raise Error("Error in `BigUInt.power()`: The exponent is too large") + var exponent_as_int = exponent.to_int() return self.power(exponent_as_int) + @always_inline + fn compare(self, other: Self) -> Int8: + """Compares the magnitudes of two BigUInts. + See `compare()` for more information. + """ + return decimojo.biguint.comparison.compare(self, other) + # ===------------------------------------------------------------------=== # # Other methods # ===------------------------------------------------------------------=== # @@ -811,18 +811,18 @@ struct BigUInt(Absable, IntableRaising, Writable): return True return False - fn internal_representation(value: BigUInt): + fn internal_representation(self): """Prints the internal representation details of a BigUInt.""" print("\nInternal Representation Details of BigUInt") print("-----------------------------------------") - print("number: ", value) - print(" ", value.to_str_with_separators()) - for i in range(len(value.words)): + print("number: ", self) + print(" ", self.to_str_with_separators()) + for i in range(len(self.words)): print( "word", i, ": ", - String(value.words[i]).rjust(width=9, fillchar="0"), + String(self.words[i]).rjust(width=9, fillchar="0"), ) print("--------------------------------")