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
19 changes: 10 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
# DeciMojo

A comprehensive decimal mathematics library for [Mojo](https://www.modular.com/mojo).
A comprehensive decimal and integer mathematics library for [Mojo](https://www.modular.com/mojo).

**[中文·漢字»](./docs/readme_zht.md)** | **[Repository on GitHub»](https://github.com/forfudan/decimojo)**

## Overview

DeciMojo provides a comprehensive decimal mathematics library for Mojo, delivering exact calculations for financial modeling, scientific computing, and applications where floating-point approximation errors are unacceptable. Beyond basic arithmetic, the library includes advanced mathematical functions with guaranteed precision.
DeciMojo provides a comprehensive decimal and integer mathematics library for Mojo, delivering exact calculations for financial modeling, scientific computing, and applications where floating-point approximation errors are unacceptable. Beyond basic arithmetic, the library includes advanced mathematical functions with guaranteed precision.

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_precision]. It features a complete set of mathematical functions including logarithms, exponentiation, roots, and trigonometric operations.
- A fully implemented arbitrary-precision integer type (`BigInt`) supporting unlimited digits. It features base-10^9 internal representation and basic arithmetic operations.
- 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, and trigonometric operations.
- An arbitrary-precision integer type (`BigInt`)[^integer] supporting unlimited digits. It features base-10^9 internal representation and basic arithmetic operations.

The library is expanding to include `BigDecimal` types that support arbitrary precision, allowing for calculations with unlimited digits and decimal places. These extensions are currently under active development.
The library is expanding to include `BigDecimal` types that support arbitrary precision[^arbitrary], allowing for calculations with unlimited digits and decimal places. These extensions are currently under active development.

## Installation

Expand Down Expand Up @@ -125,6 +125,7 @@ fn main() raises:
print(-a) # Negation: -12345678901234567890
print(abs(BigInt("-12345678901234567890"))) # Absolute value: 12345678901234567890
print(a.is_negative()) # Check if negative: False
```

## Objective

Expand Down Expand Up @@ -179,7 +180,7 @@ Regular benchmarks against Python's `decimal` module are available in the `bench

### Future Extensions 🚀 (PLANNED)

- **BigDecimal**: 🔄 **IN PROGRESS** - Arbitrary-precision decimal type with configurable precision[^arbitrary_precision].
- **BigDecimal**: 🔄 **IN PROGRESS** - Arbitrary-precision decimal type with configurable precision[^arbitrary].
- **BigComplex**: 📝 **PLANNED** - Arbitrary-precision complex number type built on BigDecimal.

## Tests and benches
Expand Down Expand Up @@ -208,6 +209,6 @@ If you find DeciMojo useful for your research, consider listing it in your citat

This repository and its contributions are licensed under the Apache License v2.0.

[^fixed_precision]: The `Decimal` type can represent values with up to 29 significant digits and a maximum of 28 digits after the decimal point. When a value exceeds the maximum representable value (`2^96 - 1`), DeciMojo either raises an error or rounds the value to fit within these constraints. For example, the significant digits of `8.8888888888888888888888888888` (29 eights total with 28 after the decimal point) exceeds the maximum representable value (`2^96 - 1`) and is automatically rounded to `8.888888888888888888888888889` (28 eights total with 27 after the decimal point). DeciMojo's `Decimal` type is similar to `System.Decimal` (C#/.NET), `rust_decimal` in Rust, `DECIMAL/NUMERIC` in SQL Server, etc.
[^integer]: Integers are a special case of decimal numbers (with zero fractional part). Our BigInt implementation serves both as a standalone arbitrary-precision integer type and as the foundation for our upcoming BigDecimal implementation.
[^arbitrary_precision]: Similar to `decimal` and `mpmath` in Python, `java.math.BigDecimal` in Java, etc.
[^fixed]: The `Decimal` type can represent values with up to 29 significant digits and a maximum of 28 digits after the decimal point. When a value exceeds the maximum representable value (`2^96 - 1`), DeciMojo either raises an error or rounds the value to fit within these constraints. For example, the significant digits of `8.8888888888888888888888888888` (29 eights total with 28 after the decimal point) exceeds the maximum representable value (`2^96 - 1`) and is automatically rounded to `8.888888888888888888888888889` (28 eights total with 27 after the decimal point). DeciMojo's `Decimal` type is similar to `System.Decimal` (C#/.NET), `rust_decimal` in Rust, `DECIMAL/NUMERIC` in SQL Server, etc.
[^integer]: The BigInt implementation uses a base-10^9 representation for efficient storage and calculations, supporting operations on integers with unlimited precision. It serves both as a standalone arbitrary-precision integer type and as the foundation for our upcoming BigDecimal implementation.
[^arbitrary]: Built on top of our completed BigInt implementation, BigDecimal will support arbitrary precision for both the integer and fractional parts, similar to `decimal` and `mpmath` in Python, `java.math.BigDecimal` in Java, etc.
110 changes: 108 additions & 2 deletions benches/biguint/bench_biguint_truncate_divide.mojo
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ fn run_benchmark_truncate_divide(

# Execute the operations once to verify correctness
try:
var mojo_result = mojo_dividend.truncate_divide(mojo_divisor)
var mojo_result = mojo_dividend // mojo_divisor
var py_result = py_dividend // py_divisor

# Display results for verification
Expand All @@ -91,7 +91,7 @@ fn run_benchmark_truncate_divide(
# Benchmark Mojo implementation
var t0 = perf_counter_ns()
for _ in range(iterations):
_ = mojo_dividend.truncate_divide(mojo_divisor)
_ = mojo_dividend // mojo_divisor
var mojo_time = (perf_counter_ns() - t0) / iterations
if mojo_time == 0:
mojo_time = 1 # Prevent division by zero
Expand Down Expand Up @@ -380,6 +380,112 @@ fn main() raises:
speedup_factors,
)

# Case 23: Division of large numbers
run_benchmark_truncate_divide(
"Division of large numbers (270 digits vs 135 digits)",
"123456789" * 30,
"987654321" * 15,
iterations,
log_file,
speedup_factors,
)

# Case 24: Division of very large numbers
run_benchmark_truncate_divide(
"Division of very large numbers (2250 digits vs 900 digits)",
"123456789" * 250,
"987654321" * 100,
iterations,
log_file,
speedup_factors,
)

# Case 25: Division of very, very large numbers
# x1 is more than 400 words long (>= 10^3600)
# x2 is more than 200 words long (>= 10^1800)
run_benchmark_truncate_divide(
"Division of very, very large numbers (3600 digits vs 1800 digits)",
"123456789" * 400,
"987654321" * 200,
iterations,
log_file,
speedup_factors,
)

# Case 26: Division of large numbers
run_benchmark_truncate_divide(
"Division of very large numbers (256 digits vs 128 digits)",
"1234567890193287491287508917213097405916874098123705160923812345678901932874912875089172130974059168740981237051609238749875089170984701759832708497029875019837409871085709813749870897510749875089170984701759832708497029875019837409871085709813749870897510",
"68740981237051609238123456789019328749128750891721309740591687409812370516092387498750879548759387959978279541709847017598327084",
iterations,
log_file,
speedup_factors,
)

# Case 27: Division of numbers with around 200 and 100 digits
run_benchmark_truncate_divide(
"Division of large numbers (200 digits vs 100 digits)",
(
"314159265358979323846264338327950288419716939937510"
"582097494459230781640628620899862803482534211706798214808651"
"328230664709384460955058223172535940812848111745028410270193"
"852110555964462294895493038196"
),
(
"271828182845904523536028747135266249775724709369995"
"95749669676277240766303535475945713821785251664274"
),
iterations,
log_file,
speedup_factors,
)

# Case 28: Division of numbers with around 200 and 100 digits
run_benchmark_truncate_divide(
"Division of large numbers (200 digits vs 100 digits)",
(
"314159265358979323846264338327950288419716939937510"
"582097494459230781640628620899862803482534211706798214808651"
"328230664709384460955058223172535940812848111745028410270193"
"852110555964462294895493038196"
),
(
"141421356237309504880168872420969807856967187537694"
"80731766797379907324784621070388503875343276400719"
),
iterations,
log_file,
speedup_factors,
)

# Case 29: Division of numbers with around 150 and 50 digits
run_benchmark_truncate_divide(
"Division of large numbers (150 digits vs 50 digits)",
(
"314159265358979323846264338327950288419716939937510"
"582097494459230781640628620899862803482534211706798214808651"
"3282306647093844609550582231725359408128"
),
"141421356237309504880168872420969807856967187537694",
iterations,
log_file,
speedup_factors,
)

# Case 30: Division of numbers with around 150 and 50 digits
run_benchmark_truncate_divide(
"Division of large numbers (150 digits vs 50 digits)",
(
"316227766016824890583648059893174009579947593530458"
"382628078540989121552735792899961040720792717368862335475063"
"5167610057579407944886251958020310186466"
),
"141421356237309504880168872420969807856967187537694",
iterations,
log_file,
speedup_factors,
)

# Calculate average speedup factor (ignoring any cases that might have failed)
if len(speedup_factors) > 0:
var sum_speedup: Float64 = 0.0
Expand Down
2 changes: 1 addition & 1 deletion docs/todo.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
This is a to-do list for Yuhao's personal use.

- [x] (#31) The `exp()` function performs slower than Python's counterpart in specific cases. Detailed investigation reveals the bottleneck stems from multiplication operations between decimals with significant fractional components. These operations currently rely on UInt256 arithmetic, which introduces performance overhead. Optimization of the `multiply()` function is required to address these performance bottlenecks, particularly for high-precision decimal multiplication with many digits after the decimal point.
- [ ] Implement different methods for augmented arithmetic assignments to improve memeory-efficiency and performance.
- [ ] Implement different methods for augmented arithmetic assignments to improve memeory-efficiency and performance.
Loading