由 Mojo 程序設計語言 🔥 實現的任意精度小數和整數運算庫。
English | 更新日誌 | GitHub 倉庫» | Discord 頻道» |
DeciMojo 爲 Mojo 提供任意精度小數和整數運算庫,爲金融建模、科學計算以及浮點近似誤差不可接受的應用提供精確計算。除了基本算術運算外,該庫還包括具有保證精度的高級數學函數。
核心類型包括:
BigInt
) 和任意精度無符號整數類型 (BigUInt
),支持無限位數1。它具有全面的算術運算、比較功能,並能高效支持超大整數計算。BigDecimal
),允許進行無限位數和小數位的計算2。它提供完整的算術運算、比較以及數學函數集合,如對數、指數、根、三角函數等。它還支持捨入模式以及與內建類型的轉換。Decimal128
),支持最多 29 位有效數字,小數點後最多 28 位數字3。它具有完整的數學函數集合,包括對數、指數、根等。此倉庫包含 TOMLMojo,一個純 Mojo 實現的輕量級 TOML 解析器。它解析配置文件和測試數據,支持基本類型、數組和嵌套表。雖然爲 DeciMojo 的測試框架而創建,但它提供通用的結構化數據解析,具有簡潔的 API。
類型 | 別名 | 信息 | 內部表示 |
---|---|---|---|
BigUInt |
BUInt |
任意精度無符號整數 | List[UInt32] |
BigInt |
BInt |
任意精度整數 | BigUInt , Bool |
BigDecimal |
BDec , Decimal |
任意精度小數 | BigUInt , Int , Bool |
Decimal128 |
Dec128 |
128 位定點精度小數 | UInt32 ,UInt32 ,UInt32 ,UInt32 |
DeciMojo 可在 modular-community 包倉庫中獲取。您可以使用以下任一方法進行安裝:
從 pixi
CLI,運行命令 pixi add decimojo
。這會獲取最新版本並使其立即可用於導入。
在您項目的 mojoproject.toml
文件中,添加以下依賴:
decimojo = "==0.5.0"
然後運行 pixi install
來下載並安裝包。
對於 main
分支中的最新開發版本,請克隆 此 GitHub 倉庫 並使用命令 pixi run package
在本地構建包。
下表總結了包版本及其對應的 Mojo 版本:
decimojo |
mojo |
包管理器 |
---|---|---|
v0.1.0 | ==25.1 | magic |
v0.2.0 | ==25.2 | magic |
v0.3.0 | ==25.2 | magic |
v0.3.1 | >=25.2, <25.4 | pixi |
v0.4.x | ==25.4 | pixi |
v0.5.0 | ==25.5 | pixi |
您可以通過導入 decimojo
模塊開始使用 DeciMojo。一個簡單的方法是從 prelude
模塊導入所有內容,它提供最常用的類型。
from decimojo import *
這將導入以下類型或別名到您的命名空間:
dm
: decimojo
模塊的別名。BigInt
(別名 BInt
):任意精度有符號整數類型。BigDecimal
(別名 BDec
和 Decimal
):任意精度小數類型。Decimal128
(別名 Dec128
):128 位定點精度小數類型。RoundingMode
(別名 RM
):捨入模式的枚舉。ROUND_DOWN
、ROUND_HALF_UP
、ROUND_HALF_EVEN
、ROUND_UP
:常用捨入模式的常量。以下是一些展示 BigDecimal
類型(別名:BDec
和 Decimal
)任意精度特性的例子。對於某些數學運算,默認精度(有效數字位數)設為 36
。您可以通過向函數傳遞 precision
參數來更改精度。當 Mojo 支持全局變量時,此默認精度將可以全局配置。
from decimojo.prelude import *
fn main() raises:
var a = BDec("123456789.123456789") # BDec 是 BigDecimal 的別名
var b = Decimal(
"1234.56789"
) # Decimal 是類似 Python 的 BigDecimal 別名
# === 基本算術 === #
print(a + b) # 123458023.691346789
print(a - b) # 123455554.555566789
print(a * b) # 152415787654.32099750190521
print(a.true_divide(b + 1)) # 99919.0656560820700835791386582569736
# === 指數函數 === #
print(a.sqrt(precision=80))
# 11111.111066111110969430554981749302328338130654689094538188579359566416821203641
print(a.cbrt(precision=80))
# 497.93385938415242742001134219007635925452951248903093962731782327785111102410518
print(a.root(b, precision=80))
# 1.0152058862996527138602610522640944903320735973237537866713119992581006582644107
print(a.power(b, precision=80))
# 3.3463611024190802340238135400789468682196324482030786573104956727660098625641520E+9989
print(a.exp(precision=80))
# 1.8612755889649587035842377856492201091251654136588338983610243887893287518637652E+53616602
print(a.log(b, precision=80))
# 2.6173300266565482999078843564152939771708486260101032293924082259819624360226238
print(a.ln(precision=80))
# 18.631401767168018032693933348296537542797015174553735308351756611901741276655161
# === 三角函數 === #
print(a.sin(precision=200))
# 0.99985093087193092464780008002600992896256609588456
# 91036188395766389946401881352599352354527727927177
# 79589259132243649550891532070326452232864052771477
# 31418817041042336608522984511928095747763538486886
print(b.cos(precision=1000))
# -0.9969577603867772005841841569997528013669868536239849713029893885930748434064450375775817720425329394
# 9756020177557431933434791661179643984869397089102223199519409695771607230176923201147218218258755323
# 7563476302904118661729889931783126826250691820526961290122532541861737355873869924820906724540889765
# 5940445990824482174517106016800118438405307801022739336016834311018727787337447844118359555063575166
# 5092352912854884589824773945355279792977596081915868398143592738704592059567683083454055626123436523
# 6998108941189617922049864138929932713499431655377552668020889456390832876383147018828166124313166286
# 6004871998201597316078894718748251490628361253685772937806895692619597915005978762245497623003811386
# 0913693867838452088431084666963414694032898497700907783878500297536425463212578556546527017688874265
# 0785862902484462361413598747384083001036443681873292719322642381945064144026145428927304407689433744
# 5821277763016669042385158254006302666602333649775547203560187716156055524418512492782302125286330865
# === 數字的內部表示 === #
(
Decimal(
).power(2, precision=60)
).print_internal_representation()
# Internal Representation Details of BigDecimal
# ----------------------------------------------
# number: 9.8696044010893586188344909998
# 761511353136994072407906264133
# 5
# coefficient: 986960440108935861883449099987
# 615113531369940724079062641335
# negative: False
# scale: 59
# word 0: 62641335
# word 1: 940724079
# word 2: 113531369
# word 3: 99987615
# word 4: 861883449
# word 5: 440108935
# word 6: 986960
# ----------------------------------------------
以下是展示 BigInt
類型(BInt
)每個主要功能的綜合快速入門指南。
from decimojo.prelude import *
fn main() raises:
# === 構造 ===
var a = BigInt("12345678901234567890") # 從字符串
var b = BInt(12345) # 從整數
# === 基本算術 ===
print(a + b) # 加法: 12345678901234580235
print(a - b) # 減法: 12345678901234555545
print(a * b) # 乘法: 152415787814108380241050
# === 除法運算 ===
print(a // b) # 向下整除: 999650944609516
print(a.truncate_divide(b)) # 截斷除法: 999650944609516
print(a % b) # 取模: 9615
# === 冪運算 ===
print(BInt(2).power(10)) # 冪: 1024
print(BInt(2) ** 10) # 冪(使用 ** 運算符): 1024
# === 比較 ===
print(a > b) # 大於: True
print(a == BInt("12345678901234567890")) # 相等: True
print(a.is_zero()) # 檢查是否爲零: False
# === 類型轉換 ===
print(String(a)) # 轉換爲字符串: "12345678901234567890"
# === 符號處理 ===
print(-a) # 取負: -12345678901234567890
print(abs(BInt("-12345678901234567890"))) # 絕對值: 12345678901234567890
print(a.is_negative()) # 檢查是否爲負: False
# === 超大數字 ===
# 3600 位數 // 1800 位數
print(BInt("123456789" * 400) // BInt("987654321" * 200))
以下是展示 Decimal128
類型(Dec128
)每個主要功能的綜合快速入門指南。
from decimojo.prelude import *
fn main() raises:
# === 構造 ===
var a = Dec128("123.45") # 從字符串
var b = Dec128(123) # 從整數
var c = Dec128(123, 2) # 帶精度的整數 (1.23)
var d = Dec128.from_float(3.14159) # 從浮點數
# === 基本算術 ===
print(a + b) # 加法: 246.45
print(a - b) # 減法: 0.45
print(a * b) # 乘法: 15184.35
print(a / b) # 除法: 1.0036585365853658536585365854
# === 捨入與精度 ===
print(a.round(1)) # 捨入到 1 位小數: 123.5
print(a.quantize(Dec128("0.01"))) # 格式化到 2 位小數: 123.45
print(a.round(0, RoundingMode.ROUND_DOWN)) # 向下捨入到整數: 123
# === 比較 ===
print(a > b) # 大於: True
print(a == Dec128("123.45")) # 相等: True
print(a.is_zero()) # 檢查是否爲零: False
print(Dec128("0").is_zero()) # 檢查是否爲零: True
# === 類型轉換 ===
print(Float64(a)) # 轉換爲浮點數: 123.45
print(a.to_int()) # 轉換爲整數: 123
print(a.to_str()) # 轉換爲字符串: "123.45"
print(a.coefficient()) # 獲取係數: 12345
print(a.scale()) # 獲取精度: 2
# === 數學函數 ===
print(Dec128("2").sqrt()) # 平方根: 1.4142135623730950488016887242
print(Dec128("100").root(3)) # 立方根: 4.641588833612778892410076351
print(Dec128("2.71828").ln()) # 自然對數: 0.9999993273472820031578910056
print(Dec128("10").log10()) # 以 10 爲底的對數: 1
print(Dec128("16").log(Dec128("2"))) # 以 2 爲底的對數: 3.9999999999999999999999999999
print(Dec128("10").exp()) # e^10: 22026.465794806716516957900645
print(Dec128("2").power(10)) # 冪: 1024
# === 符號處理 ===
print(-a) # 取負: -123.45
print(abs(Dec128("-123.45"))) # 絕對值: 123.45
print(Dec128("123.45").is_negative()) # 檢查是否爲負: False
# === 特殊值 ===
print(Dec128.PI()) # π 常數: 3.1415926535897932384626433833
print(Dec128.E()) # e 常數: 2.7182818284590452353602874714
print(Dec128.ONE()) # 值 1: 1
print(Dec128.ZERO()) # 值 0: 0
print(Dec128.MAX()) # 最大值: 79228162514264337593543950335
# === 便利方法 ===
print(Dec128("123.400").is_integer()) # 檢查是否爲整數: False
print(a.number_of_significant_digits()) # 計算有效數字位數: 5
print(Dec128("12.34").to_str_scientific()) # 科學計數法: 1.234E+1
金融計算和數據分析需要精確的小數算術,而浮點數無法可靠地提供這種精確性。作爲一名從事金融學研究和信用風險模型驗證工作的人員,在將個人項目從 Python 遷移到 Mojo 時,我需要一個可靠的、能够正確捨入的、固定精度的數值類型。
由於 Mojo 目前在其標準庫中缺乏原生的 Decimal 類型,我決定創建自己的實現來填補這一空白。
本項目從多個已建立的小數實現和文檔中汲取靈感,例如 Python 内置的 Decimal
類型,Rust 的 rust_decimal
crate,Microsoft 的 Decimal
實現,通用小數算術規範 等。非常感謝前輩們的貢獻及其對開放知識共享的促進。
得此魔咒者,即脱凡相,識天數,斬三尸,二十七日飛升。 —— 《太上靈通感應二十七章經》
DeciMojo 結合了 “Deci” 和 “Mojo” 兩詞,反映了其目的和實現語言。”Deci”(源自拉丁詞根”decimus”,意爲”十分之一”)強調了我們對人類自然用於計數和計算的十進制數字系統的關注。
雖然名稱強調了帶小數部分的十進制數,但 DeciMojo 涵蓋了十進制數學的全部範圍。我們的 BigInt
類型雖然只處理整數,但專爲十進制數字系統設計,採用以 10 爲基數的内部表示。這種方法在保持人類可讀的十進制語義的同時提供最佳性能,與專注於二進制的庫形成對比。此外,BigInt
作爲我們 BigDecimal
實現的基礎,使得在整數和小數領域都能進行任意精度的計算。
這個名稱最終強調了我們的使命:爲 Mojo 生態系統帶來精確、可靠的十進制計算,滿足浮點表示無法提供的精確算術的基本需求。
羅馬不是一日建成的。DeciMojo 目前正在積極開發中。它已成功通過 “讓它工作” 階段,並已深入 “讓它正確” 階段,同時已實施多項優化。歡迎錯誤報告和功能請求!如果您遇到問題,請在此提交。
定期對比 Python 的 decimal
模塊的基準測試可在 bench/
文件夾中找到,記錄了性能優勢以及需要不同方法的少數特定操作。
在將倉庫克隆到本地磁盤後,您可以:
pixi run test
運行測試。pixi run bdec
生成對比 python.decimal
模塊的基準測試日誌。日誌文件保存在 benches/bigdecimal/logs/
中。如果您發現 DeciMojo 對您的研究有用,請考慮將它加入您的引用中。
@software{Zhu.2025,
author = {Zhu, Yuhao},
year = {2025},
title = {An arbitrary-precision decimal and integer mathematics library for Mojo},
url = {https://github.com/forfudan/decimojo},
version = {0.5.0},
note = {Computer Software}
}
本倉庫及其所有貢獻内容均採用 Apache 許可證 2.0 版本授權。
BigInt 實現對用戶使用基於 10 的表示(保持十進制語義),而內部使用優化的基於 10^9 的存儲系統進行高效計算。這種方法在人類可讀的十進制操作與高性能計算之間取得平衡。它提供向下整除(向負無窮舍入)和截斷除法(向零舍入)語義,無論操作數符號如何,都能確保除法操作具有正確的數學行爲。 ↩
建立在我們已完成的 BigInt 實現之上,BigDecimal 將支持整數和小數部分的任意精度,類似於 Python 中的 decimal
和 mpmath
、Java 中的 java.math.BigDecimal
等。 ↩
Decimal128
類型可以表示最多 29 位有效數字,小數點後最多 28 位數字的值。當數值超過最大可表示值(2^96 - 1
)時,DeciMojo 會拋出錯誤或將數值捨入以符合這些約束。例如,8.8888888888888888888888888888
(總共 29 個 8,小數點後 28 位)的有效數字超過了最大可表示值(2^96 - 1
),會自動捨入爲 8.888888888888888888888888889
(總共 28 個 8,小數點後 27 位)。DeciMojo 的 Decimal128
類型類似於 System.Decimal
(C#/.NET)、Rust 中的 rust_decimal
、SQL Server 中的 DECIMAL/NUMERIC
等。 ↩