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
7 changes: 3 additions & 4 deletions pixi.toml
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
[project]
authors = ["ZHU Yuhao 朱宇浩 <[email protected]>"]
channels = ["https://conda.modular.com/max", "https://repo.prefix.dev/modular-community", "conda-forge"]
# channels = ["https://conda.modular.com/max-nightly", "https://conda.modular.com/max", "https://repo.prefix.dev/modular-community", "conda-forge"]
channels = ["https://conda.modular.com/max-nightly", "https://conda.modular.com/max", "https://repo.prefix.dev/modular-community", "conda-forge"]
description = "An arbitrary-precision decimal and integer mathematics library for Mojo"
license = "Apache-2.0"
name = "decimojo"
platforms = ["osx-arm64", "linux-64"]
readme = "README.md"
version = "0.4.1"
version = "0.5.0"

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

[tasks]
# format the code
Expand Down
44 changes: 24 additions & 20 deletions src/decimojo/bigdecimal/bigdecimal.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -40,12 +40,15 @@ This will be configurable in future when Mojo supports global variables.
"""


@value
struct BigDecimal(
Absable,
AnyType,
Comparable,
Copyable,
FloatableRaising,
IntableRaising,
Movable,
Representable,
Roundable,
Stringable,
Writable,
Expand Down Expand Up @@ -167,7 +170,7 @@ struct BigDecimal(

@staticmethod
fn from_raw_components(
owned words: List[UInt32], scale: Int = 0, sign: Bool = False
var words: List[UInt32], scale: Int = 0, sign: Bool = False
) -> Self:
"""**UNSAFE** Creates a BigDecimal from its raw components.
The raw components are words, scale, and sign.
Expand Down Expand Up @@ -617,32 +620,32 @@ struct BigDecimal(
# ===------------------------------------------------------------------=== #

@always_inline
fn __gt__(self, other: BigDecimal) -> Bool:
fn __gt__(self, other: Self) -> Bool:
"""Returns whether self is greater than other."""
return decimojo.bigdecimal.comparison.compare(self, other) > 0

@always_inline
fn __ge__(self, other: BigDecimal) -> Bool:
fn __ge__(self, other: Self) -> Bool:
"""Returns whether self is greater than or equal to other."""
return decimojo.bigdecimal.comparison.compare(self, other) >= 0

@always_inline
fn __lt__(self, other: BigDecimal) -> Bool:
fn __lt__(self, other: Self) -> Bool:
"""Returns whether self is less than other."""
return decimojo.bigdecimal.comparison.compare(self, other) < 0

@always_inline
fn __le__(self, other: BigDecimal) -> Bool:
fn __le__(self, other: Self) -> Bool:
"""Returns whether self is less than or equal to other."""
return decimojo.bigdecimal.comparison.compare(self, other) <= 0

@always_inline
fn __eq__(self, other: BigDecimal) -> Bool:
fn __eq__(self, other: Self) -> Bool:
"""Returns whether self equals other."""
return decimojo.bigdecimal.comparison.compare(self, other) == 0

@always_inline
fn __ne__(self, other: BigDecimal) -> Bool:
fn __ne__(self, other: Self) -> Bool:
"""Returns whether self does not equal other."""
return decimojo.bigdecimal.comparison.compare(self, other) != 0

Expand Down Expand Up @@ -728,7 +731,7 @@ struct BigDecimal(
fn e(precision: Int) raises -> Self:
"""Returns the mathematical constant e to the specified precision."""
return decimojo.bigdecimal.exponential.exp(
x=BigDecimal(BigUInt.ONE), precision=precision
x=Self(BigUInt.ONE), precision=precision
)

# === Exponentional operations === #
Expand Down Expand Up @@ -914,7 +917,7 @@ struct BigDecimal(
"""
return self.coefficient.number_of_digits() - 1 - self.scale

fn extend_precision(self, precision_diff: Int) -> BigDecimal:
fn extend_precision(self, precision_diff: Int) -> Self:
"""Returns a number with additional decimal places (trailing zeros).
This multiplies the coefficient by 10^precision_diff and increases
the scale accordingly, preserving the numeric value.
Expand All @@ -933,10 +936,11 @@ struct BigDecimal(
In debug mode, negative `precision_diff` raises an assertion error.

Examples:

```
print(BigDecimal("123.456).scale_up(5)) # Output: 123.45600000
print(BigDecimal("123456").scale_up(3)) # Output: 123456.000
print(BigDecimal("123456").scale_up(-1)) # Output: 123456 (no change)
print(BigDecimal("123.456).extend_precision(5)) # Output: 123.45600000
print(BigDecimal("123456").extend_precision(3)) # Output: 123456.000
print(BigDecimal("123456").extend_precision(-1)) # Output: 123456 (no change)
```
"""
debug_assert(
Expand All @@ -949,7 +953,7 @@ struct BigDecimal(
if precision_diff <= 0:
return self

return BigDecimal(
return Self(
decimojo.biguint.arithmetics.multiply_by_power_of_ten(
self.coefficient, precision_diff
),
Expand All @@ -974,9 +978,9 @@ struct BigDecimal(

Examples:
```
print(BigDecimal("123.456).scale_up(5)) # Output: 123.45600000
print(BigDecimal("123456").scale_up(3)) # Output: 123456.000
print(BigDecimal("123456").scale_up(-1)) # Output: 123456 (no change)
BigDecimal("123.456).extend_precision_inplace(5) # Output: 123.45600000
BigDecimal("123456").extend_precision_inplace(3) # Output: 123456.000
BigDecimal("123456").extend_precision_inplace(-1) # Output: 123456 (no change)
```
"""
debug_assert(
Expand Down Expand Up @@ -1107,15 +1111,15 @@ struct BigDecimal(
"""Returns True if this number represents zero."""
return self.coefficient.is_zero()

fn normalize(self) raises -> BigDecimal:
fn normalize(self) raises -> Self:
"""Removes trailing zeros from coefficient while adjusting scale.

Notes:

Only call it when necessary. Do not normalize after every operation.
"""
if self.coefficient.is_zero():
return BigDecimal(BigUInt(UInt32(0)), 0, False)
return Self(BigUInt(UInt32(0)), 0, False)

var number_of_digits_to_remove = self.number_of_trailing_zeros()

Expand Down Expand Up @@ -1146,7 +1150,7 @@ struct BigDecimal(
else: # number_of_remaining_digits_to_remove == 8
coefficient = coefficient // BigUInt(UInt32(100_000_000))

return BigDecimal(
return Self(
coefficient,
self.scale - number_of_digits_to_remove,
self.sign,
Expand Down
2 changes: 1 addition & 1 deletion src/decimojo/bigdecimal/constants.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ fn pi(precision: Int) raises -> BigDecimal:
return pi_chudnovsky_binary_split(precision)


@value
@fieldwise_init
struct Rational:
"""Represents a rational number p/q for exact arithmetic."""

Expand Down
23 changes: 20 additions & 3 deletions src/decimojo/bigint/arithmetics.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@
Implements basic arithmetic functions for the BigInt type.
"""

import time
import testing

from decimojo.bigint.bigint import BigInt
from decimojo.biguint.biguint import BigUInt
from decimojo.rounding_mode import RoundingMode
Expand All @@ -38,8 +35,16 @@ fn add(x1: BigInt, x2: BigInt) raises -> BigInt:
"""
# If one of the numbers is zero, return the other number
if x1.is_zero():
debug_assert[assert_mode="none"](
len(x1.magnitude.words) == 1,
"decimojo.bigint.arithmetics.add(): leading zero words in x1",
)
return x2
if x2.is_zero():
debug_assert[assert_mode="none"](
len(x2.magnitude.words) == 1,
"decimojo.bigint.arithmetics.add(): leading zero words in x2",
)
return x1

# If signs are different, delegate to `subtract`
Expand Down Expand Up @@ -82,9 +87,17 @@ fn subtract(x1: BigInt, x2: BigInt) raises -> BigInt:
"""
# If the subtrahend is zero, return the minuend
if x2.is_zero():
debug_assert[assert_mode="none"](
len(x2.magnitude.words) == 1,
"decimojo.bigint.arithmetics.add(): leading zero words in x2",
)
return x1
# If the minuend is zero, return the negated subtrahend
if x1.is_zero():
debug_assert[assert_mode="none"](
len(x1.magnitude.words) == 1,
"decimojo.bigint.arithmetics.add(): leading zero words in x1",
)
return -x2

# If signs are different, delegate to `add`
Expand Down Expand Up @@ -126,6 +139,10 @@ fn negative(x: BigInt) -> BigInt:
"""
# If x is zero, return zero
if x.is_zero():
debug_assert[assert_mode="none"](
len(x.magnitude.words) == 1,
"decimojo.bigint.arithmetics.add(): leading zero words in x",
)
return BigInt()

var result = x
Expand Down
19 changes: 13 additions & 6 deletions src/decimojo/bigint/bigint.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ mathematical methods that do not implement a trait.
"""

from memory import UnsafePointer
import testing
import time

import decimojo.bigint.arithmetics
import decimojo.bigint.comparison
Expand All @@ -37,8 +35,17 @@ import decimojo.str
alias BInt = BigInt


@value
struct BigInt(Absable, IntableRaising, Representable, Stringable, Writable):
struct BigInt(
Absable,
AnyType,
Comparable,
Copyable,
IntableRaising,
Movable,
Representable,
Stringable,
Writable,
):
"""Represents a base-10 arbitrary-precision signed integer.

Notes:
Expand Down Expand Up @@ -106,7 +113,7 @@ struct BigInt(Absable, IntableRaising, Representable, Stringable, Writable):
self.magnitude = BigUInt(words)
self.sign = sign

fn __init__(out self, owned *words: UInt32, sign: Bool) raises:
fn __init__(out self, var *words: UInt32, sign: Bool) raises:
"""***UNSAFE!*** Initializes a BigInt from raw components.
It does not check whether the words are invalid.
See `from_words()` for safer initialization.
Expand Down Expand Up @@ -175,7 +182,7 @@ struct BigInt(Absable, IntableRaising, Representable, Stringable, Writable):
# ===------------------------------------------------------------------=== #

@staticmethod
fn from_list(owned words: List[UInt32], sign: Bool) raises -> Self:
fn from_list(var words: List[UInt32], sign: Bool) raises -> Self:
"""Initializes a BigInt from a list of UInt32 words safely.
If the list is empty, the BigInt is initialized with value 0.

Expand Down
Loading