From e6497eddf13f7a8b6bbf6970a1cdae59279fc579 Mon Sep 17 00:00:00 2001 From: mertcandav Date: Sat, 7 Sep 2024 20:42:14 +0300 Subject: [PATCH] std::math::big: add the DivMod method to Int --- std/math/big/bits.jule | 11 +++---- std/math/big/int.jule | 44 ++++++++++++++++------------ std/math/big/int_test.jule | 60 ++++++++++++++++++++++++++++++++++++++ std/math/big/nat.jule | 58 +++++++++++++++++++++++++++++------- 4 files changed, 139 insertions(+), 34 deletions(-) diff --git a/std/math/big/bits.jule b/std/math/big/bits.jule index d0d0845c7..baa5ad00a 100644 --- a/std/math/big/bits.jule +++ b/std/math/big/bits.jule @@ -88,7 +88,7 @@ fn subRes(mut &x: bits, y: bits) { carry = addRfast(x, y) |: mut xn := make(bits, len(y)) - _ = copy(xn, x) + copy(xn, x) x = xn twosComplement(x) carry = addFast(x, y) @@ -267,7 +267,7 @@ fn cloneBits(x: bits): bits { fn lsh(mut x: bits, y: int): bits { if y > 0 && len(x) > 0 { mut x2 := make(bits, len(x) + y) - _ = copy(x2[y:], x) + copy(x2[y:], x) ret x2 } ret x @@ -380,7 +380,7 @@ fn karatsubaLsh(mut x: bits, mut y: int): bits { ret x } mut x2 := make(bits, len(x) + y) - _ = copy(x2[y:], x) + copy(x2[y:], x) ret x2 } ret x @@ -530,17 +530,18 @@ fn recursiveDiv(mut &x: bits, mut &y: bits, mut &s: bits, mut &q: bits) { ret | 0: addOne(s) + x = nil ret } for cmp(q, x) == +1 { q = q[1:] } + subRes(x, q) + fit(x) if len(q) == len(y) { addOne(s) ret } - subRes(x, q) - fit(x) mut sq := q[:len(q)-len(y)+1] mut &last := unsafe { *(&sq[len(sq)-1]) } old := last diff --git a/std/math/big/int.jule b/std/math/big/int.jule index c0823fbe1..090d627c4 100644 --- a/std/math/big/int.jule +++ b/std/math/big/int.jule @@ -146,6 +146,17 @@ impl Int { self.minus = self.Len() > 0 && self.minus != y.minus } + // Sets self to quotient self/y, returns remainder self%y. + fn DivMod(mut self, y: Int): Int { + mut r := Int{ + minus: self.minus, + nat: self.nat.divMod(y.nat), + } + self.minus = self.minus != y.minus && self.Len() > 0 // 0 has no sign + handleRem(r, y) + ret r + } + // Divides two Int and returns result. fn Div(self, y: Int): Int { mut r := self @@ -156,11 +167,7 @@ impl Int { // Divides Int. fn DivAssign(mut self, y: Int) { self.nat /= y.nat - if self.Len() == 0 { - self.minus = false - } else { - self.minus = self.minus != y.minus - } + self.minus = self.minus != y.minus && self.Len() > 0 // 0 has no sign } // Modulo two Int and returns result. @@ -172,18 +179,8 @@ impl Int { // Modulo Int. fn ModAssign(mut self, y: Int) { - if self.minus == y.minus { - self.nat %= y.nat - self.minus = self.Len() > 0 && y.minus - ret - } self.nat %= y.nat - if self.Len() == 0 { - self.minus = false - ret - } - self.nat -= y.nat - self.minus = self.Len() > 0 && y.minus + handleRem(self, y) } // Bitwise left shift. @@ -222,7 +219,7 @@ impl Int { fn BitOrAssign(mut self, y: Int) { if self.Len() < y.Len() { mut xb := make(bits, y.Len()) - _ = copy(xb, self.nat.bits) + copy(xb, self.nat.bits) self.nat.bits = xb } if self.minus { @@ -252,7 +249,7 @@ impl Int { fn BitAndAssign(mut self, y: Int) { if self.Len() < y.Len() { mut xb := make(bits, y.Len()) - _ = copy(xb, self.nat.bits) + copy(xb, self.nat.bits) self.nat.bits = xb } if self.minus { @@ -292,7 +289,7 @@ impl Int { } if self.Len() < y.Len() { mut xb := make(bits, y.Len()) - _ = copy(xb, self.nat.bits) + copy(xb, self.nat.bits) self.nat.bits = xb } if self.minus { @@ -502,4 +499,13 @@ fn min(a: int, b: int): int { ret a } ret b +} + +// Handles remainder after x%y computation. +// Assumes r equals to remainder x%y. +fn handleRem(mut &r: Int, &y: Int) { + if r.minus != y.minus && r.nat.len() > 0 { + r.nat -= y.nat + } + r.minus = y.minus && r.Len() > 0 // 0 has no sign } \ No newline at end of file diff --git a/std/math/big/int_test.jule b/std/math/big/int_test.jule index 61b9cedfb..6c2e796e9 100644 --- a/std/math/big/int_test.jule +++ b/std/math/big/int_test.jule @@ -190,6 +190,66 @@ fn testIntMod(t: &T) { testCommonIntOp(t, "%", casesIntMod) } +#test +fn testIntDivMod_Div(t: &T) { + for _, c in casesIntDiv { + mut n1 := Int.Parse(c[0], 2) else { + t.Errorf("exception occurs: {}", error) + continue + } + n2 := Int.Parse(c[1], 2) else { + t.Errorf("exception occurs: {}", error) + continue + } + _ = n1.DivMod(n2) + cr := c[2] + if n1.Len() != len(cr)-1 || + n1.minus && c[2][0] != '-' || + !n1.minus && c[2][0] != '+' { + t.Errorf("{} / {} != {}", c[0], c[1], c[2]) + continue + } + for i, b in n1.nat.bits { + cb := cr[len(cr)-1-i] + if b == 0b1 && cb != '1' || + b == 0b0 && cb != '0' { + t.Errorf("{} / {} != {}", c[0], c[1], c[2]) + break + } + } + } +} + +#test +fn testIntDivMod_Mod(t: &T) { + for _, c in casesIntMod { + mut n1 := Int.Parse(c[0], 2) else { + t.Errorf("exception occurs: {}", error) + continue + } + n2 := Int.Parse(c[1], 2) else { + t.Errorf("exception occurs: {}", error) + continue + } + n1 = n1.DivMod(n2) + cr := c[2] + if n1.Len() != len(cr)-1 || + n1.minus && c[2][0] != '-' || + !n1.minus && c[2][0] != '+' { + t.Errorf("{} % {} != {}", c[0], c[1], c[2]) + continue + } + for i, b in n1.nat.bits { + cb := cr[len(cr)-1-i] + if b == 0b1 && cb != '1' || + b == 0b0 && cb != '0' { + t.Errorf("{} % {} != {}", c[0], c[1], c[2]) + break + } + } + } +} + #test fn testIntBitNot(t: &T) { for _, c in casesIntBitNot { diff --git a/std/math/big/nat.jule b/std/math/big/nat.jule index 96775da72..d80e817d7 100644 --- a/std/math/big/nat.jule +++ b/std/math/big/nat.jule @@ -189,6 +189,44 @@ impl nat { ret r } + // Sets self to quotient self/y, returns remainder self%y. + fn divMod(mut self, y: nat): nat { + if self.len() == 0 { + // Left operans is zero, remainder is always zero. + ret nat.zero() + } + match y.len() { + | 1: + // Right operand is 1, remainder is always zero. + ret nat.zero() + | 0: + panic("std::math::big: division by zero") + } + match self.cmp(y) { + | -1: + // Left operand is less than right operand. + // Quotient is always equals to zero, remainder equals to left operand. + mut rem := nat{self.bits} + self.bits = nil + ret rem + | 0: + // Left operand and right operand are equal. + // Quotient is always equals one, remainder zero. + self.bits = [1] + ret nat.zero() + } + mut xb := cloneBits(self.bits) + mut q := make(bits, len(xb)) + copy(q[len(q)-len(y.bits):], y.bits) + mut s := make(bits, len(xb)) + recursiveDiv(xb, y.bits, s, q) + self.bits = s + self.fit() + mut rem := nat{xb} + rem.fit() + ret rem + } + // Divides nat. fn DivAssign(mut self, y: nat) { if self.len() == 0 { @@ -197,26 +235,26 @@ impl nat { } match y.len() { | 1: - // Right operand is 1, quotient is always equals to left operand. + // Right operand is 1, remainder is always zero. ret | 0: panic("std::math::big: division by zero") } match self.cmp(y) { | -1: - // Left operand is less than right oprand. - // Quotient is always equals to zero. + // Left operand is less than right operand. + // Quotient is always equals to zero, remainder equals to left operand. self.bits = nil ret | 0: - // Left oprand and right operand are equal. - // Quotient is always zero. + // Left operand and right operand are equal. + // Quotient is always equals one, remainder zero. self.bits = [1] ret } mut xb := cloneBits(self.bits) mut q := make(bits, len(xb)) - _ = copy(q[len(q)-len(y.bits):], y.bits) + copy(q[len(q)-len(y.bits):], y.bits) mut s := make(bits, len(xb)) recursiveDiv(xb, y.bits, s, q) self.bits = s @@ -233,7 +271,7 @@ impl nat { // Modulo nat. fn ModAssign(mut self, y: nat) { if self.len() == 0 { - // Left operans is zero, remainder is always zero. + // Left operands is zero, remainder is always zero. ret } match { @@ -243,7 +281,7 @@ impl nat { ret | y.len() == 2 && y.bits[0] == 0b0: // Right operand is 2. - // If left opeand is even, remainder is always zero. + // If left operand is even, remainder is always zero. // If left operand is odd, remainder is always one. if self.even() { self.bits = nil @@ -260,14 +298,14 @@ impl nat { // Remainder always equals to left operand. ret | 0: - // Left oprand and right operand are equal. + // Left operand and right operand are equal. // Remainder is always zero. self.bits = nil ret } mut xb := cloneBits(self.bits) mut q := make(bits, len(xb)) - _ = copy(q[len(q)-len(y.bits):], y.bits) + copy(q[len(q)-len(y.bits):], y.bits) self.bits = recursiveMod(xb, y.bits, q) self.fit() }