Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# SCM syntax highlighting & preventing 3-way merges
pixi.lock merge=binary linguist-language=YAML linguist-generated=true
magic.lock merge=binary linguist-language=YAML linguist-generated=true
magic.lock merge=binary linguist-language=YAML linguist-generated=true

# Force LF (Unix-style) line endings
* text=auto eol=lf
4 changes: 2 additions & 2 deletions pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ readme = "README.md"
version = "0.5.0"

[dependencies]
max = ">25.4"
mojo = "*"

[tasks]
# format the code
Expand Down Expand Up @@ -41,4 +41,4 @@ buint_debug = "clear && pixi run package && cd benches/biguint && pixi run mojo
bdec_debug = "clear && pixi run package && cd benches/bigdecimal && pixi run mojo run -I ../ -D ASSERT=all bench.mojo && cd ../.. && pixi run clean"

# doc
doc = "clear && pixi run mojo doc -o docs/doc.json --diagnose-missing-doc-strings --validate-doc-strings src/decimojo"
doc = "clear && pixi run mojo doc -o docs/doc.json --diagnose-missing-doc-strings --validate-doc-strings src/decimojo"
157 changes: 116 additions & 41 deletions src/decimojo/bigint/arithmetics.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ Implements basic arithmetic functions for the BigInt type.

from decimojo.bigint.bigint import BigInt
from decimojo.biguint.biguint import BigUInt
from decimojo.errors import DeciMojoError
from decimojo.rounding_mode import RoundingMode


fn add(x1: BigInt, x2: BigInt) raises -> BigInt:
fn add(x1: BigInt, x2: BigInt) -> BigInt:
"""Returns the sum of two BigInts.

Args:
Expand Down Expand Up @@ -57,7 +58,7 @@ fn add(x1: BigInt, x2: BigInt) raises -> BigInt:
return BigInt(magnitude^, sign=x1.sign)


fn add_inplace(mut x1: BigInt, x2: BigInt) raises -> None:
fn add_inplace(mut x1: BigInt, x2: BigInt) -> None:
"""Increments a BigInt number by another BigInt number in place.

Args:
Expand All @@ -67,15 +68,17 @@ fn add_inplace(mut x1: BigInt, x2: BigInt) raises -> None:

# If signs are different, delegate to `subtract`
if x1.sign != x2.sign:
x1 = subtract(x1, -x2)
x1 = subtract(x1, negative(x2))
return

# Same sign: add magnitudes in place
else:
x1.magnitude += x2.magnitude
decimojo.biguint.arithmetics.add_inplace(x1.magnitude, x2.magnitude)

return

fn subtract(x1: BigInt, x2: BigInt) raises -> BigInt:

fn subtract(x1: BigInt, x2: BigInt) -> BigInt:
"""Returns the difference of two numbers.

Args:
Expand All @@ -102,7 +105,7 @@ fn subtract(x1: BigInt, x2: BigInt) raises -> BigInt:

# If signs are different, delegate to `add`
if x1.sign != x2.sign:
return x1 + (-x2)
return add(x1, negative(x2))

# Same sign, compare magnitudes to determine result sign and operation
var comparison_result = x1.magnitude.compare(x2.magnitude)
Expand All @@ -114,12 +117,18 @@ fn subtract(x1: BigInt, x2: BigInt) raises -> BigInt:
var sign: Bool
if comparison_result > 0: # |x1| > |x2|
# Subtract smaller from larger
magnitude = x1.magnitude - x2.magnitude
magnitude = x1.magnitude
decimojo.biguint.arithmetics.subtract_inplace_no_check(
magnitude, x2.magnitude
)
sign = x1.sign

else: # |x1| < |x2|
# Subtract larger from smaller and negate the result
magnitude = x2.magnitude - x1.magnitude
magnitude = x2.magnitude
decimojo.biguint.arithmetics.subtract_inplace_no_check(
magnitude, x1.magnitude
)
sign = not x1.sign

return BigInt(magnitude^, sign=sign)
Expand Down Expand Up @@ -165,7 +174,7 @@ fn absolute(x: BigInt) -> BigInt:
return x


fn multiply(x1: BigInt, x2: BigInt) raises -> BigInt:
fn multiply(x1: BigInt, x2: BigInt) -> BigInt:
"""Returns the product of two BigInt numbers.

Args:
Expand Down Expand Up @@ -197,25 +206,51 @@ fn floor_divide(x1: BigInt, x2: BigInt) raises -> BigInt:

Returns:
The quotient of x1 / x2, rounded toward negative infinity.
"""

if x2.is_zero():
raise Error("Error in `floor_divide`: Division by zero")

if x1.is_zero():
return BigInt()
Raises:
DeciMojoError: If `decimojo.biguint.arithmetics.floor_divide()` fails.
DeciMojoError: If `decimojo.biguint.arithmetics.ceil_divide()` fails.
"""

# 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

var magnitude: BigUInt

if x1.sign == x2.sign:
# Use floor (truncate) division between magnitudes
return BigInt(x1.magnitude.floor_divide(x2.magnitude), sign=False)
# Use floor division of the magnitudes
try:
magnitude = decimojo.biguint.arithmetics.floor_divide(
x1.magnitude, x2.magnitude
)
except e:
raise Error(
DeciMojoError(
file="src/decimojo/bigint/arithmetics",
function="floor_divide()",
message=None,
previous_error=e,
),
)
return BigInt(magnitude^, sign=False)

else:
# Use ceil division of the magnitudes
return BigInt(x1.magnitude.ceil_divide(x2.magnitude), sign=True)
try:
magnitude = decimojo.biguint.arithmetics.ceil_divide(
x1.magnitude, x2.magnitude
)
except e:
raise Error(
DeciMojoError(
file="src/decimojo/bigint/arithmetics",
function="floor_divide()",
message=None,
previous_error=e,
),
)
return BigInt(magnitude^, sign=True)


fn truncate_divide(x1: BigInt, x2: BigInt) raises -> BigInt:
Expand All @@ -231,15 +266,22 @@ fn truncate_divide(x1: BigInt, x2: BigInt) raises -> BigInt:
The quotient of x1 / x2, truncated toward zero.

Raises:
ValueError: If the divisor is zero.
DeciMojoError: If `decimojo.biguint.arithmetics.floor_divide()` fails.
"""
if x2.is_zero():
raise Error("Error in `truncate_divide`: Division by zero")

if x1.is_zero():
return BigInt() # Return zero

var magnitude = x1.magnitude.floor_divide(x2.magnitude)
var magnitude: BigUInt
try:
magnitude = decimojo.biguint.arithmetics.floor_divide(
x1.magnitude, x2.magnitude
)
except e:
raise Error(
DeciMojoError(
file="src/decimojo/bigint/arithmetics",
function="truncate_divide()",
message=None,
previous_error=e,
),
)
return BigInt(magnitude^, sign=x1.sign != x2.sign)


Expand All @@ -254,21 +296,47 @@ fn floor_modulo(x1: BigInt, x2: BigInt) raises -> BigInt:

Returns:
The remainder of x1 being divided by x2, with the same sign as x2.
"""

if x2.is_zero():
raise Error("Error in `floor_modulo`: Division by zero")
Raises:
DeciMojoError: If `decimojo.biguint.arithmetics.floor_modulo()` fails.
DeciMojoError: If `decimojo.biguint.arithmetics.ceil_modulo()` fails.
"""

if x1.is_zero():
return BigInt() # Return zero
var magnitude: BigUInt

if x1.sign == x2.sign:
# Use floor (truncate) division between magnitudes
return BigInt(x1.magnitude.floor_modulo(x2.magnitude), sign=x2.sign)
try:
magnitude = decimojo.biguint.arithmetics.floor_modulo(
x1.magnitude, x2.magnitude
)
except e:
raise Error(
DeciMojoError(
file="src/decimojo/bigint/arithmetics",
function="floor_modulo()",
message=None,
previous_error=e,
),
)
return BigInt(magnitude^, sign=x2.sign)

else:
# Use ceil division of the magnitudes
return BigInt(x1.magnitude.ceil_modulo(x2.magnitude), sign=x2.sign)
try:
magnitude = decimojo.biguint.arithmetics.ceil_modulo(
x1.magnitude, x2.magnitude
)
except e:
raise Error(
DeciMojoError(
file="src/decimojo/bigint/arithmetics",
function="floor_modulo()",
message=None,
previous_error=e,
),
)
return BigInt(magnitude^, sign=x2.sign)


fn truncate_modulo(x1: BigInt, x2: BigInt) raises -> BigInt:
Expand All @@ -284,13 +352,20 @@ fn truncate_modulo(x1: BigInt, x2: BigInt) raises -> BigInt:
The remainder of x1 being divided by x2, with the same sign as x1.

Raises:
ValueError: If the divisor is zero.
DeciMojoError: If `decimojo.biguint.arithmetics.floor_modulo()` fails.
"""
if x2.is_zero():
raise Error("Error in `truncate_modulo`: Division by zero")

if x1.is_zero():
return BigInt() # Return zero

var magnitude = x1.magnitude.floor_modulo(x2.magnitude)
var magnitude: BigUInt
try:
magnitude = decimojo.biguint.arithmetics.floor_modulo(
x1.magnitude, x2.magnitude
)
except e:
raise Error(
DeciMojoError(
file="src/decimojo/bigint/arithmetics",
function="truncate_modulo()",
message=None,
previous_error=e,
),
)
return BigInt(magnitude^, sign=x1.sign)
45 changes: 33 additions & 12 deletions src/decimojo/bigint/bigint.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import decimojo.bigint.arithmetics
import decimojo.bigint.comparison
from decimojo.bigdecimal.bigdecimal import BigDecimal
from decimojo.biguint.biguint import BigUInt
from decimojo.errors import DeciMojoError
import decimojo.str

# Type aliases
Expand Down Expand Up @@ -463,24 +464,44 @@ struct BigInt(
# ===------------------------------------------------------------------=== #

@always_inline
fn __add__(self, other: Self) raises -> Self:
fn __add__(self, other: Self) -> Self:
return decimojo.bigint.arithmetics.add(self, other)

@always_inline
fn __sub__(self, other: Self) raises -> Self:
fn __sub__(self, other: Self) -> Self:
return decimojo.bigint.arithmetics.subtract(self, other)

@always_inline
fn __mul__(self, other: Self) raises -> Self:
fn __mul__(self, other: Self) -> Self:
return decimojo.bigint.arithmetics.multiply(self, other)

@always_inline
fn __floordiv__(self, other: Self) raises -> Self:
return decimojo.bigint.arithmetics.floor_divide(self, other)
try:
return decimojo.bigint.arithmetics.floor_divide(self, other)
except e:
raise Error(
DeciMojoError(
message=None,
function="BigInt.__floordiv__()",
file="src/decimojo/bigint/bigint.mojo",
previous_error=e,
)
)

@always_inline
fn __mod__(self, other: Self) raises -> Self:
return decimojo.bigint.arithmetics.floor_modulo(self, other)
try:
return decimojo.bigint.arithmetics.floor_modulo(self, other)
except e:
raise Error(
DeciMojoError(
message=None,
function="BigInt.__mod__()",
file="src/decimojo/bigint/bigint.mojo",
previous_error=e,
)
)

@always_inline
fn __pow__(self, exponent: Self) raises -> Self:
Expand All @@ -493,15 +514,15 @@ struct BigInt(
# ===------------------------------------------------------------------=== #

@always_inline
fn __radd__(self, other: Self) raises -> Self:
fn __radd__(self, other: Self) -> Self:
return decimojo.bigint.arithmetics.add(self, other)

@always_inline
fn __rsub__(self, other: Self) raises -> Self:
fn __rsub__(self, other: Self) -> Self:
return decimojo.bigint.arithmetics.subtract(other, self)

@always_inline
fn __rmul__(self, other: Self) raises -> Self:
fn __rmul__(self, other: Self) -> Self:
return decimojo.bigint.arithmetics.multiply(self, other)

@always_inline
Expand All @@ -524,11 +545,11 @@ struct BigInt(
# ===------------------------------------------------------------------=== #

@always_inline
fn __iadd__(mut self, other: Self) raises:
fn __iadd__(mut self, other: Self):
decimojo.bigint.arithmetics.add_inplace(self, other)

@always_inline
fn __iadd__(mut self, other: Int) raises:
fn __iadd__(mut self, other: Int):
# Optimize the case `i += 1`
if (self >= 0) and (other >= 0) and (other <= 999_999_999):
decimojo.biguint.arithmetics.add_inplace_by_uint32(
Expand All @@ -538,11 +559,11 @@ struct BigInt(
decimojo.bigint.arithmetics.add_inplace(self, other)

@always_inline
fn __isub__(mut self, other: Self) raises:
fn __isub__(mut self, other: Self):
self = decimojo.bigint.arithmetics.subtract(self, other)

@always_inline
fn __imul__(mut self, other: Self) raises:
fn __imul__(mut self, other: Self):
self = decimojo.bigint.arithmetics.multiply(self, other)

@always_inline
Expand Down
Loading