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
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,9 @@ DeciMojo provides an arbitrary-precision decimal and integer mathematics library

The core types are:

- A 128-bit fixed-point decimal implementation (`Decimal`) supporting up to 29 significant digits with a maximum of 28 decimal places[^fixed]. It features a complete set of mathematical functions including logarithms, exponentiation, roots, etc.
- An arbitrary-precision decimal implementation `BigDecimal` allowing for calculations with unlimited digits and decimal places[^arbitrary].
- A base-10 arbitrary-precision signed integer type (`BigInt`) and a base-10 arbitrary-precision unsigned integer type (`BigUInt`) supporting unlimited digits[^integer]. It features comprehensive arithmetic operations, comparison functions, and supports extremely large integer calculations efficiently.
- An arbitrary-precision decimal implementation `BigDecimal` allowing for calculations with unlimited digits and decimal places[^arbitrary].
- A 128-bit fixed-point decimal implementation (`Decimal`) supporting up to 29 significant digits with a maximum of 28 decimal places[^fixed]. It features a complete set of mathematical functions including logarithms, exponentiation, roots, etc.

This repository includes [TOMLMojo](https://github.com/forfudan/decimojo/tree/main/src/tomlmojo), a lightweight TOML parser in pure Mojo. It parses configuration files and test data, supporting basic types, arrays, and nested tables. While created for DeciMojo's testing framework, it offers general-purpose structured data parsing with a clean, simple API.

Expand All @@ -39,7 +39,7 @@ DeciMojo is available in the [modular-community](https://repo.prefix.dev/modular

From the `pixi` CLI, simply run ```pixi add decimojo```. This fetches the latest version and makes it immediately available for import.

For projects with a `mojoproject.toml`file, add the dependency ```decimojo = "==0.4.0"```. Then run `pixi install` to download and install the package.
For projects with a `mojoproject.toml`file, add the dependency ```decimojo = "==0.4.1"```. Then run `pixi install` to download and install the package.

For the latest development version, clone the [GitHub repository](https://github.com/forfudan/decimojo) and build the package locally.

Expand All @@ -49,11 +49,11 @@ For the latest development version, clone the [GitHub repository](https://github
| v0.2.0 | ==25.2 | magic |
| v0.3.0 | ==25.2 | magic |
| v0.3.1 | >=25.2, <25.4 | pixi |
| v0.4.0 | ==25.4 | pixi |
| v0.4.x | ==25.4 | pixi |

## Quick start

Here are some examples showcasing the arbitrary-precision feature of the `BigDecimal` type.
Here are some examples showcasing the arbitrary-precision feature of the `BigDecimal` type. Note that Mojo does not support global variables at the moment, so we need to pass the `precision` parameter explicitly to each function call. In future, we will add a global precision setting with the default value of, *e.g.*, `28`, to avoid passing it around.

```mojo
from decimojo import BDec, RM
Expand Down Expand Up @@ -218,7 +218,7 @@ If you find DeciMojo useful for your research, consider listing it in your citat
year = {2025},
title = {An arbitrary-precision decimal and integer mathematics library for Mojo},
url = {https://github.com/forfudan/decimojo},
version = {0.4.0},
version = {0.4.1},
note = {Computer Software}
}
```
Expand Down
81 changes: 80 additions & 1 deletion docs/changelog.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,85 @@
# DeciMojo changelog

This is a list of RELEASED changes for the DeciMojo Package. For the unreleased changes, please refer to **[changelog_unreleased](https://zhuyuhao.com/decimojo/docs/changelog_unreleased.html)**.
This is a list of RELEASED changes for the DeciMojo Package.

## 01/07/2025 (v0.4.1)

Version 0.4.1 of DeciMojo introduces implicit type conversion between built-in integral types and arbitrary-precision types.

### ⭐️ New

Now DeciMojo supports implicit type conversion between built-in integeral types (`Int`, `UInt`, `Int8`, `UInt8`, `Int16`, `UInt16`, `Int32`, `UInt32`, `Int64`, `UInt64`, `Int128`,`UInt128`, `Int256`, and `UInt256`) and the arbitrary-precision integer types (`BigUInt`, `BigInt`, and `BigDecimal`). This allows you to use these built-in types directly in arithmetic operations with `BigInt` and `BigUInt` without explicit conversion. The merged type will always be the most compatible one (PR #89, PR #90).

For example, you can now do the following:

```mojo
from decimojo.prelude import *

fn main() raises:
var a = BInt(Int256(-1234567890))
var b = BigUInt(31415926)
var c = BDec("3.14159265358979323")

print("a =", a)
print("b =", b)
print("c =", c)

print(a * b) # Merged to BInt
print(a + c) # Merged to BDec
print(b + c) # Merged to BDec
print(a * Int(-128)) # Merged to BInt
print(b * UInt(8)) # Merged to BUInt
print(c * Int256(987654321123456789)) # Merged to BDec

var lst = [a, b, c, UInt8(255), Int64(22222), UInt256(1234567890)]
# The list is of the type `List[BigDecimal]`
for i in lst:
print(i, end=", ")
```

Running the code will give your the following results:

```console
a = -1234567890
b = 31415926
c = 3.14159265358979323
-38785093474216140
-1234567886.85840734641020677
31415929.14159265358979323
158024689920
251327408
3102807559527666386.46423202534973847
-1234567890, 31415926, 3.14159265358979323, 255, 22222, 1234567890,
```

### 🦋 Changed

Optimize the case when you increase the value of a `BigInt` object in-place by 1, *i.e.*, `i += 1`. This allows you to iterate faster (PR #89). For example, we can compute the time taken to iterate from `0` to `1_000_000` using `BigInt` and compare it with the built-in `Int` type:

```mojo
from decimojo.prelude import *

fn main() raises:
i = BigInt(0)
end = BigInt(1_000_000)
while i < end:
print(i)
i += 1
```

| scenario | Time taken |
| --------------- | ---------- |
| v0.4.0 `BigInt` | 1.102s |
| v0.4.1 `BigInt` | 0.912s |
| Built-in `Int` | 0.893s |

### 🛠️ Fixed

Fix a bug in `BigDecimal` where it cannot create a correct value from a integral scalar, e.g., `BDec(UInt16(0))` returns an unitialized `BigDecimal` object (PR #89).

### 📚 Documentation and testing

Update the `tests` module and refactor the test files for `BigUInt` (PR #88).

## 25/06/2025 (v0.4.0)

Expand Down
3 changes: 0 additions & 3 deletions docs/changelog_unreleased.md

This file was deleted.

6 changes: 3 additions & 3 deletions docs/readme_zht.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ DeciMojo 可在 [modular-community](https://repo.prefix.dev/modular-community)

從 `pixi` CLI,只需運行 ```pixi add decimojo```。這會獲取最新版本並使其立即可用於導入。

對於帶有 `mojoproject.toml` 文件的項目,添加依賴 ```decimojo = "==0.4.0"```。然後運行 `pixi install` 來下載並安裝包。
對於帶有 `mojoproject.toml` 文件的項目,添加依賴 ```decimojo = "==0.4.1"```。然後運行 `pixi install` 來下載並安裝包。

如需最新的開發版本,請克隆 [GitHub 倉庫](https://github.com/forfudan/decimojo) 並在本地構建包。

Expand All @@ -30,7 +30,7 @@ DeciMojo 可在 [modular-community](https://repo.prefix.dev/modular-community)
| v0.2.0 | >=25.2 | magic |
| v0.3.0 | >=25.2 | magic |
| v0.3.1 | >=25.2, <25.4 | pixi |
| v0.4.0 | ==25.4 | pixi |
| v0.4.x | ==25.4 | pixi |

## 快速入門

Expand Down Expand Up @@ -218,7 +218,7 @@ DeciMojo 相較於 Python 的 `decimal` 模塊提供了卓越的性能,同時
year = {2025},
title = {DeciMojo: A fixed-point decimal arithmetic library in Mojo},
url = {https://github.com/forfudan/decimojo},
version = {0.4.0},
version = {0.4.1},
note = {Computer Software}
}
```
Expand Down
2 changes: 1 addition & 1 deletion pixi.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ license = "Apache-2.0"
name = "decimojo"
platforms = ["osx-arm64", "linux-64"]
readme = "README.md"
version = "0.4.0"
version = "0.4.1"

[dependencies]
max = "==25.4"
Expand Down
12 changes: 12 additions & 0 deletions src/decimojo/bigdecimal/bigdecimal.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@ struct BigDecimal(
"""
self = Self.from_int(value)

@implicit
fn __init__(out self, value: UInt):
"""Constructs a BigDecimal from an `UInt` object.
See `from_uint()` for more information.
"""
self = Self.from_uint(value)

@implicit
fn __init__(out self, value: Scalar):
"""Constructs a BigDecimal from an integral scalar.
Expand Down Expand Up @@ -179,6 +186,11 @@ struct BigDecimal(

return Self(coefficient=BigUInt(words^), scale=0, sign=sign)

@staticmethod
fn from_uint(value: Int) -> Self:
"""Creates a BigDecimal from an unsigned integer."""
return Self(coefficient=BigUInt.from_uint(value), scale=0, sign=False)

@staticmethod
fn from_integral_scalar[dtype: DType, //](value: SIMD[dtype, 1]) -> Self:
"""Initializes a BigDecimal from an integral scalar.
Expand Down
16 changes: 16 additions & 0 deletions src/decimojo/bigint/arithmetics.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,22 @@ fn add(x1: BigInt, x2: BigInt) raises -> BigInt:
return BigInt(magnitude^, sign=x1.sign)


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

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

# Same sign: add magnitudes in place
x1.magnitude += x2.magnitude


fn subtract(x1: BigInt, x2: BigInt) raises -> BigInt:
"""Returns the difference of two numbers.
Expand Down
69 changes: 18 additions & 51 deletions src/decimojo/bigint/bigint.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,13 @@ struct BigInt(Absable, IntableRaising, Representable, Stringable, Writable):
"""
self = Self.from_int(value)

@implicit
fn __init__(out self, value: UInt):
"""Initializes a BigInt from an `UInt` object.
See `from_uint()` for more information.
"""
self = Self.from_uint(value)

@implicit
fn __init__(out self, value: Scalar):
"""Constructs a BigInt from an integral scalar.
Expand All @@ -164,7 +171,6 @@ struct BigInt(Absable, IntableRaising, Representable, Stringable, Writable):
#
# from_words(*words: UInt32, sign: Bool) -> Self
# from_int(value: Int) -> Self
# from_uint128(value: UInt128, sign: Bool = False) -> Self
# from_string(value: String) -> Self
# ===------------------------------------------------------------------=== #

Expand Down Expand Up @@ -251,6 +257,11 @@ struct BigInt(Absable, IntableRaising, Representable, Stringable, Writable):

return Self(BigUInt(words^), sign)

@staticmethod
fn from_uint(value: UInt) -> Self:
"""Creates a BigInt from an unsignd integer."""
return Self(magnitude=BigUInt.from_uint(value), sign=False)

@staticmethod
fn from_integral_scalar[dtype: DType, //](value: SIMD[dtype, 1]) -> Self:
"""Initializes a BigInt from an integral scalar.
Expand Down Expand Up @@ -448,54 +459,26 @@ 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)

@always_inline
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
Expand Down Expand Up @@ -535,48 +518,32 @@ struct BigInt(Absable, IntableRaising, Representable, Stringable, Writable):

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

@always_inline
fn __iadd__(mut self, other: Int) raises:
self = decimojo.bigint.arithmetics.add(self, Self.from_int(other))
# Optimize the case `i += 1`
if other == 1:
self.magnitude.add_inplace_by_1()
else:
decimojo.bigint.arithmetics.add_inplace(self, 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 Down
Loading