diff --git a/builtin/bigint_js.mbt b/builtin/bigint_js.mbt index eab03328a..ec83d740d 100644 --- a/builtin/bigint_js.mbt +++ b/builtin/bigint_js.mbt @@ -212,3 +212,15 @@ extern "js" fn js_shl(self : BigInt, other : Int) -> BigInt = ///| extern "js" fn js_shr(self : BigInt, other : Int) -> BigInt = #|(x, y) => x >> BigInt(y) + +///| +pub extern "js" fn land(self : BigInt, other : BigInt) -> BigInt = + #|(x, y) => x & y + +///| +pub extern "js" fn lor(self : BigInt, other : BigInt) -> BigInt = + #|(x, y) => x | y + +///| +pub extern "js" fn lxor(self : BigInt, other : BigInt) -> BigInt = + #|(x, y) => x ^ y diff --git a/builtin/bigint_nonjs.mbt b/builtin/bigint_nonjs.mbt index 690fe3857..eff519e78 100644 --- a/builtin/bigint_nonjs.mbt +++ b/builtin/bigint_nonjs.mbt @@ -925,3 +925,264 @@ pub fn BigInt::to_octets(self : BigInt, length? : Int) -> Bytes { } result } + +///| +pub fn land(self : BigInt, other : BigInt) -> BigInt { + let max_length = if self.limbs.length() < other.limbs.length() { + other.limbs.length() + 1 + } else { + self.limbs.length() + 1 + } + // Extend the limbs to store the sign bits + let x_limbs = FixedArray::make(max_length, 0U)..unsafe_blit( + 0, + self.limbs, + 0, + self.limbs.length(), + ) + let y_limbs = FixedArray::make(max_length, 0U)..unsafe_blit( + 0, + other.limbs, + 0, + other.limbs.length(), + ) + + // Calculate the complement code per 2 + if self.sign == Negative { + for i = 0; i < x_limbs.length(); i = i + 1 { + x_limbs[i] = x_limbs[i] ^ 0xFFFFFFFFU + } + for i = 0; i < x_limbs.length(); i = i + 1 { + x_limbs[i] += 1 + if x_limbs[i] != 0x0U { + break + } + } + } + if other.sign == Negative { + for i = 0; i < y_limbs.length(); i = i + 1 { + y_limbs[i] = y_limbs[i] ^ 0xFFFFFFFFU + } + for i = 0; i < y_limbs.length(); i = i + 1 { + y_limbs[i] += 1 + if y_limbs[i] != 0x0U { + break + } + } + } + + // Bit Ops + for i = 0; i < x_limbs.length(); i = i + 1 { + x_limbs[i] = x_limbs[i] & y_limbs[i] + } + + // Check wether the result is either positive or negative + let new_sign = if x_limbs[x_limbs.length() - 1] == 0xFFFFFFFFU { + Negative + } else { + Positive + } + + // Restore as true code + if new_sign == Negative { + for i = 0; i < x_limbs.length(); i = i + 1 { + x_limbs[i] -= 1 + if x_limbs[i] != 0xFFFFFFFFU { + break + } + } + for i = 0; i < x_limbs.length(); i = i + 1 { + x_limbs[i] = x_limbs[i] ^ 0xFFFFFFFFU + } + } + + // return the result + { + limbs: FixedArray::make(max_length - 1, 0U)..unsafe_blit( + 0, + x_limbs, + 0, + max_length - 1, + ), + sign: new_sign, + len: if self.len > other.len { + self.len + } else { + other.len + }, + } +} + +///| +pub fn lor(self : BigInt, other : BigInt) -> BigInt { + let max_length = if self.limbs.length() < other.limbs.length() { + other.limbs.length() + 1 + } else { + self.limbs.length() + 1 + } + // Extend the limbs to store the sign bits + let x_limbs = FixedArray::make(max_length, 0U)..unsafe_blit( + 0, + self.limbs, + 0, + self.limbs.length(), + ) + let y_limbs = FixedArray::make(max_length, 0U)..unsafe_blit( + 0, + other.limbs, + 0, + other.limbs.length(), + ) + + // Calculate the complement code per 2 + if self.sign == Negative { + for i = 0; i < x_limbs.length(); i = i + 1 { + x_limbs[i] = x_limbs[i] ^ 0xFFFFFFFFU + } + for i = 0; i < x_limbs.length(); i = i + 1 { + x_limbs[i] += 1 + if x_limbs[i] != 0x0U { + break + } + } + } + if other.sign == Negative { + for i = 0; i < y_limbs.length(); i = i + 1 { + y_limbs[i] = y_limbs[i] ^ 0xFFFFFFFFU + } + for i = 0; i < y_limbs.length(); i = i + 1 { + y_limbs[i] += 1 + if y_limbs[i] != 0x0U { + break + } + } + } + + // Bit Ops + for i = 0; i < x_limbs.length(); i = i + 1 { + x_limbs[i] = x_limbs[i] | y_limbs[i] + } + + // Check wether the result is either positive or negative + let new_sign = if x_limbs[x_limbs.length() - 1] == 0xFFFFFFFFU { + Negative + } else { + Positive + } + + // Restore as true code + if new_sign == Negative { + for i = 0; i < x_limbs.length(); i = i + 1 { + x_limbs[i] -= 1 + if x_limbs[i] != 0xFFFFFFFFU { + break + } + } + for i = 0; i < x_limbs.length(); i = i + 1 { + x_limbs[i] = x_limbs[i] ^ 0xFFFFFFFFU + } + } + + // return the result + { + limbs: FixedArray::make(max_length - 1, 0U)..unsafe_blit( + 0, + x_limbs, + 0, + max_length - 1, + ), + sign: new_sign, + len: if self.len > other.len { + self.len + } else { + other.len + }, + } +} + +///| +pub fn lxor(self : BigInt, other : BigInt) -> BigInt { + let max_length = if self.limbs.length() < other.limbs.length() { + other.limbs.length() + 1 + } else { + self.limbs.length() + 1 + } + // Extend the limbs to store the sign bits + let x_limbs = FixedArray::make(max_length, 0U)..unsafe_blit( + 0, + self.limbs, + 0, + self.limbs.length(), + ) + let y_limbs = FixedArray::make(max_length, 0U)..unsafe_blit( + 0, + other.limbs, + 0, + other.limbs.length(), + ) + + // Calculate the complement code per 2 + if self.sign == Negative { + for i = 0; i < x_limbs.length(); i = i + 1 { + x_limbs[i] = x_limbs[i] ^ 0xFFFFFFFFU + } + for i = 0; i < x_limbs.length(); i = i + 1 { + x_limbs[i] += 1 + if x_limbs[i] != 0x0U { + break + } + } + } + if other.sign == Negative { + for i = 0; i < y_limbs.length(); i = i + 1 { + y_limbs[i] = y_limbs[i] ^ 0xFFFFFFFFU + } + for i = 0; i < y_limbs.length(); i = i + 1 { + y_limbs[i] += 1 + if y_limbs[i] != 0x0U { + break + } + } + } + + // Bit Ops + for i = 0; i < x_limbs.length(); i = i + 1 { + x_limbs[i] = x_limbs[i] ^ y_limbs[i] + } + + // Check wether the result is either positive or negative + let new_sign = if x_limbs[x_limbs.length() - 1] == 0xFFFFFFFFU { + Negative + } else { + Positive + } + + // Restore as true code + if new_sign == Negative { + for i = 0; i < x_limbs.length(); i = i + 1 { + x_limbs[i] -= 1 + if x_limbs[i] != 0xFFFFFFFFU { + break + } + } + for i = 0; i < x_limbs.length(); i = i + 1 { + x_limbs[i] = x_limbs[i] ^ 0xFFFFFFFFU + } + } + + // return the result + { + limbs: FixedArray::make(max_length - 1, 0U)..unsafe_blit( + 0, + x_limbs, + 0, + max_length - 1, + ), + sign: new_sign, + len: if self.len > other.len { + self.len + } else { + other.len + }, + } +} diff --git a/builtin/bigint_test.mbt b/builtin/bigint_test.mbt index be4f06bd3..a7703f030 100644 --- a/builtin/bigint_test.mbt +++ b/builtin/bigint_test.mbt @@ -557,3 +557,93 @@ test "to_hex" { content="-11e3444dc1f35f057ad2cbc2791737468140a426fac3cba7af8c92a8f34e", ) } + +test "land_1" { + let a = BigInt::from_string("-10") + let b = BigInt::from_string("11") + inspect!(a & b, content="2") +} + +test "land_2" { + let a = BigInt::from_string("-10") + let b = BigInt::from_hex("fffffffffffffff") // 15 'f' chars + inspect!(a & b, content="1152921504606846966") +} + +test "land_3" { + let a = BigInt::from_hex("ffffffffffffffff") // 16 'f' chars + let b = BigInt::from_string("-10") + inspect!(a & b, content="18446744073709551606") +} + +test "land_4" { + let a = BigInt::from_string("0") + let b = BigInt::from_string("-10") + inspect!(a & b, content="0") +} + +test "land_5" { + let a = BigInt::from_hex("ffffffffffffffff") + let b = BigInt::from_hex("ffffffffffffffff") + inspect!(a & b, content="18446744073709551615") +} + +test "lor_1" { + let a = BigInt::from_string("-10") + let b = BigInt::from_string("11") + inspect!(a | b, content="-1") +} + +test "lor_2" { + let a = BigInt::from_string("-10") + let b = BigInt::from_hex("fffffffffffffff") // 15 'f' chars + inspect!(a | b, content="-1") +} + +test "lor_3" { + let a = BigInt::from_hex("ffffffffffffffff") // 16 'f' chars + let b = BigInt::from_string("-10") + inspect!(a | b, content="-1") +} + +test "lor_4" { + let a = BigInt::from_string("0") + let b = BigInt::from_string("-10") + inspect!(a | b, content="-10") +} + +test "lor_5" { + let a = BigInt::from_hex("ffffffffffffffff") + let b = BigInt::from_string("0") + inspect!(a | b, content="18446744073709551615") +} + +test "lxor_1" { + let a = BigInt::from_string("-10") + let b = BigInt::from_string("11") + inspect!(a ^ b, content="-3") +} + +test "lxor_2" { + let a = BigInt::from_string("-10") + let b = BigInt::from_hex("fffffffffffffff") // 15 'f' chars + inspect!(a ^ b, content="-1152921504606846967") +} + +test "lxor_3" { + let a = BigInt::from_hex("ffffffffffffffff") // 16 'f' chars + let b = BigInt::from_string("-10") + inspect!(a ^ b, content="-18446744073709551607") +} + +test "lxor_4" { + let a = BigInt::from_string("0") + let b = BigInt::from_string("-10") + inspect!(a ^ b, content="-10") +} + +test "lxor_5" { + let a = BigInt::from_string("0") + let b = BigInt::from_hex("ffffffffffffffff") + inspect!(a ^ b, content="18446744073709551615") +} diff --git a/builtin/builtin.mbti b/builtin/builtin.mbti index bcf853375..bebef7700 100644 --- a/builtin/builtin.mbti +++ b/builtin/builtin.mbti @@ -155,7 +155,10 @@ impl BigInt { from_octets(Bytes, signum~ : Int = ..) -> Self from_string(String) -> Self is_zero(Self) -> Bool + land(Self, Self) -> Self + lor(Self, Self) -> Self lsl(Self, Int) -> Self //deprecated + lxor(Self, Self) -> Self op_add(Self, Self) -> Self op_div(Self, Self) -> Self op_equal(Self, Self) -> Bool