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
14 changes: 14 additions & 0 deletions src/decimojo/bigdecimal/bigdecimal.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,20 @@ struct BigDecimal(
# from_string(value: String) -> Self
# ===------------------------------------------------------------------=== #

@staticmethod
fn from_raw_components(
coefficient: BigUInt, scale: Int = 0, sign: Bool = False
) -> Self:
"""Creates a BigDecimal from its raw components."""
return Self(coefficient, scale, sign)

@staticmethod
fn from_raw_components(
coefficient: UInt32, scale: Int = 0, sign: Bool = False
) -> Self:
"""Creates a BigDecimal from its raw components."""
return Self(BigUInt(List[UInt32](coefficient)), scale, sign)

@staticmethod
fn from_int(value: Int) raises -> Self:
"""Creates a BigDecimal from an integer."""
Expand Down
23 changes: 23 additions & 0 deletions src/decimojo/bigdecimal/constants.mojo
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# ===----------------------------------------------------------------------=== #
# Copyright 2025 Yuhao Zhu
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ===----------------------------------------------------------------------=== #
"""
# Implements functions for calculating common constants.
"""

import math as builtin_math

from decimojo.bigdecimal.bigdecimal import BigDecimal
from decimojo.rounding_mode import RoundingMode
116 changes: 115 additions & 1 deletion src/decimojo/bigint/bigint.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ struct BigInt(Absable, IntableRaising, Representable, Stringable, Writable):
return Self(BigUInt(list_of_words^), sign)

@staticmethod
fn from_int(value: Int) raises -> Self:
fn from_int(value: Int) -> Self:
"""Creates a BigInt from an integer."""
if value == 0:
return Self()
Expand Down Expand Up @@ -421,22 +421,46 @@ struct BigInt(Absable, IntableRaising, Representable, Stringable, Writable):
fn __add__(self, other: Self) raises -> Self:
return decimojo.bigint.arithmetics.add(self, other)

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

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

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

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

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

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

@always_inline
fn __floordiv__(self, other: Int) raises -> Self:
return decimojo.bigint.arithmetics.floor_divide(
self, Self.from_int(other)
)

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

@always_inline
fn __mod__(self, other: Int) raises -> Self:
return decimojo.bigint.arithmetics.floor_modulo(
self, Self.from_int(other)
)

@always_inline
fn __pow__(self, exponent: Self) raises -> Self:
return self.power(exponent)
Expand All @@ -445,6 +469,40 @@ struct BigInt(Absable, IntableRaising, Representable, Stringable, Writable):
fn __pow__(self, exponent: Int) raises -> Self:
return self.power(exponent)

# ===------------------------------------------------------------------=== #
# Basic binary right-side arithmetic operation dunders
# These methods are called to implement the binary arithmetic operations
# (+, -, *, @, /, //, %, divmod(), pow(), **, <<, >>, &, ^, |)
# ===------------------------------------------------------------------=== #

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

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

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

@always_inline
fn __rfloordiv__(self, other: Int) raises -> Self:
return decimojo.bigint.arithmetics.floor_divide(
Self.from_int(other), self
)

@always_inline
fn __rmod__(self, other: Int) raises -> Self:
return decimojo.bigint.arithmetics.floor_modulo(
Self.from_int(other), self
)

@always_inline
fn __rpow__(self, base: Int) raises -> Self:
return Self(base).power(self)

# ===------------------------------------------------------------------=== #
# Basic binary augmented arithmetic assignments dunders
# These methods are called to implement the binary augmented arithmetic
Expand All @@ -456,22 +514,46 @@ struct BigInt(Absable, IntableRaising, Representable, Stringable, Writable):
fn __iadd__(mut self, other: Self) raises:
self = decimojo.bigint.arithmetics.add(self, other)

@always_inline
fn __iadd__(mut self, other: Int) raises:
self = decimojo.bigint.arithmetics.add(self, Self.from_int(other))

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

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

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

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

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

@always_inline
fn __ifloordiv__(mut self, other: Int) raises:
self = decimojo.bigint.arithmetics.floor_divide(
self, Self.from_int(other)
)

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

@always_inline
fn __imod__(mut self, other: Int) raises:
self = decimojo.bigint.arithmetics.floor_modulo(
self, Self.from_int(other)
)

# ===------------------------------------------------------------------=== #
# Basic binary comparison operation dunders
# __gt__, __ge__, __lt__, __le__, __eq__, __ne__
Expand All @@ -482,31 +564,63 @@ struct BigInt(Absable, IntableRaising, Representable, Stringable, Writable):
"""Returns True if self > other."""
return decimojo.bigint.comparison.greater(self, other)

@always_inline
fn __gt__(self, other: Int) -> Bool:
"""Returns True if self > other."""
return decimojo.bigint.comparison.greater(self, Self.from_int(other))

@always_inline
fn __ge__(self, other: Self) -> Bool:
"""Returns True if self >= other."""
return decimojo.bigint.comparison.greater_equal(self, other)

@always_inline
fn __ge__(self, other: Int) -> Bool:
"""Returns True if self >= other."""
return decimojo.bigint.comparison.greater_equal(
self, Self.from_int(other)
)

@always_inline
fn __lt__(self, other: Self) -> Bool:
"""Returns True if self < other."""
return decimojo.bigint.comparison.less(self, other)

@always_inline
fn __lt__(self, other: Int) -> Bool:
"""Returns True if self < other."""
return decimojo.bigint.comparison.less(self, Self.from_int(other))

@always_inline
fn __le__(self, other: Self) -> Bool:
"""Returns True if self <= other."""
return decimojo.bigint.comparison.less_equal(self, other)

@always_inline
fn __le__(self, other: Int) -> Bool:
"""Returns True if self <= other."""
return decimojo.bigint.comparison.less_equal(self, Self.from_int(other))

@always_inline
fn __eq__(self, other: Self) -> Bool:
"""Returns True if self == other."""
return decimojo.bigint.comparison.equal(self, other)

@always_inline
fn __eq__(self, other: Int) -> Bool:
"""Returns True if self == other."""
return decimojo.bigint.comparison.equal(self, Self.from_int(other))

@always_inline
fn __ne__(self, other: Self) -> Bool:
"""Returns True if self != other."""
return decimojo.bigint.comparison.not_equal(self, other)

@always_inline
fn __ne__(self, other: Int) -> Bool:
"""Returns True if self != other."""
return decimojo.bigint.comparison.not_equal(self, Self.from_int(other))

# ===------------------------------------------------------------------=== #
# Mathematical methods that do not implement a trait (not a dunder)
# ===------------------------------------------------------------------=== #
Expand Down
11 changes: 6 additions & 5 deletions src/decimojo/biguint/biguint.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -80,11 +80,11 @@ struct BigUInt(Absable, IntableRaising, Stringable, Writable):
# Constructors and life time dunder methods
#
# __init__(out self)
# __init__(out self, empty: Bool)
# __init__(out self, empty: Bool, capacity: Int)
# __init__(out self, *words: UInt32) raises
# __init__(out self, owned words: List[UInt32])
# __init__(out self, owned *words: UInt32)
# __init__(out self, value: Int) raises
# __init__(out self, value: String) raises
# __init__(out self, value: Scalar) raises
# __init__(out self, value: String, ignore_sign: Bool = False) raises
# ===------------------------------------------------------------------=== #

fn __init__(out self):
Expand All @@ -93,7 +93,7 @@ struct BigUInt(Absable, IntableRaising, Stringable, Writable):

fn __init__(out self, owned words: List[UInt32]):
"""Initializes a BigUInt from a list of UInt32 words.
It does not check whether the list is empty or the words are invalid.
It does not verify whether the list is empty or the words are invalid.
See `from_list()` for safer initialization.

Args:
Expand Down Expand Up @@ -163,6 +163,7 @@ struct BigUInt(Absable, IntableRaising, Stringable, Writable):
fn from_list(owned words: List[UInt32]) raises -> Self:
"""Initializes a BigUInt from a list of UInt32 words safely.
If the list is empty, the BigUInt is initialized with value 0.
The words are validated to ensure they are smaller than `999_999_999`.

Args:
words: A list of UInt32 words representing the coefficient.
Expand Down
76 changes: 74 additions & 2 deletions src/decimojo/tests.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,10 @@
Implement structs and functions for tests.
"""

import tomlmojo

struct TestCase(Copyable, Movable):

struct TestCase(Copyable, Movable, Stringable, Writable):
"""Structure to hold test case data.

Attributes:
Expand All @@ -40,7 +42,9 @@ struct TestCase(Copyable, Movable):
self.a = a
self.b = b
self.expected = expected
self.description = description + "\nx1 = " + self.a + "\nx2 = " + self.b
self.description = (
description + " (a = " + self.a + ", b = " + self.b + ")"
)

fn __copyinit__(out self, other: Self):
self.a = other.a
Expand All @@ -53,3 +57,71 @@ struct TestCase(Copyable, Movable):
self.b = other.b^
self.expected = other.expected^
self.description = other.description^

fn __str__(self) -> String:
return (
"TestCase(a: "
+ self.a
+ ", b: "
+ self.b
+ ", expected: "
+ self.expected
+ ", description: "
+ self.description
+ ")"
)

fn write_to[T: Writer](self, mut writer: T):
writer.write("TestCase:\n")
writer.write(" a: " + self.a + "\n")
writer.write(" b: " + self.b + "\n")
writer.write(" expected: " + self.expected + "\n")
writer.write(" description: " + self.description + "\n")


fn load_test_cases(
file_path: String, table_name: String, has_expected_value: Bool = True
) raises -> List[TestCase]:
"""Load test cases from a TOML file for a specific table."""
var toml = tomlmojo.parse_file(file_path)
var test_cases = List[TestCase]()

# Get array of test cases
var cases_array = toml.get_array_of_tables(table_name)

for i in range(len(cases_array)):
var case_table = cases_array[i]
var expected_value = case_table[
"expected"
].as_string() if has_expected_value else String("")
test_cases.append(
TestCase(
case_table["a"].as_string(),
case_table["b"].as_string(),
expected_value,
case_table["description"].as_string(),
)
)

return test_cases


fn load_test_cases(
toml: tomlmojo.parser.TOMLDocument, table_name: String
) raises -> List[TestCase]:
"""Load test cases from a TOMLDocument."""
# Get array of test cases
var cases_array = toml.get_array_of_tables(table_name)

var test_cases = List[TestCase]()
for case_table in cases_array:
test_cases.append(
TestCase(
case_table["a"].as_string(),
case_table["b"].as_string(),
case_table["expected"].as_string(),
case_table["description"].as_string(),
)
)

return test_cases
Loading