Skip to content

Commit

Permalink
Add land/lor/lxor for BigInt. (#1336)
Browse files Browse the repository at this point in the history
* Add land/lor/lxor for BigInt.

* Call  method directly in test.

* Make land/lor/lxor consistent with JS.

* Update builtin/bigint_js.mbt

* Update builtin/bigint_nonjs.mbt

* Update builtin/bigint_nonjs.mbt

* Update builtin/bigint_nonjs.mbt

* Update builtin/bigint_test.mbt

---------

Co-authored-by: Hongbo Zhang <[email protected]>
Co-authored-by: Zihang Ye <[email protected]>
  • Loading branch information
3 people authored Dec 23, 2024
1 parent e106481 commit 78faf98
Show file tree
Hide file tree
Showing 4 changed files with 366 additions and 0 deletions.
12 changes: 12 additions & 0 deletions builtin/bigint_js.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -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
261 changes: 261 additions & 0 deletions builtin/bigint_nonjs.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -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
},
}
}
90 changes: 90 additions & 0 deletions builtin/bigint_test.mbt
Original file line number Diff line number Diff line change
Expand Up @@ -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")
}
3 changes: 3 additions & 0 deletions builtin/builtin.mbti
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 78faf98

Please sign in to comment.