decimojo

DeciMojo

Mojo 程序設計語言 🔥 實現的定點數和整數運算庫。

GitHub 倉庫»

概述

DeciMojo 爲 Mojo 提供了全面的定點數和整數運算庫,專爲處理金融計算、工程計算、以及其他需要避免浮點數捨入誤差的場景而設計。

核心類型包括:

安裝

DeciMojo 可在 modular-community 包倉庫中獲取。您可以使用以下任一方法進行安裝:

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

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

如需最新的開發版本,請克隆 GitHub 倉庫 並在本地構建包。

decimojo mojo
v0.1.0 >=25.1
v0.2.0 >=25.2
v0.3.0 >=25.2

快速入門

以下是展示 Decimal 類型每個主要功能的全面快速入門指南。

from decimojo import Decimal, RoundingMode

fn main() raises:
    # === 構造 ===
    var a = Decimal("123.45")                        # 從字符串
    var b = Decimal(123)                             # 從整數
    var c = Decimal(123, 2)                          # 帶比例的整數 (1.23)
    var d = Decimal.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(Decimal("0.01")))               # 格式化到2位小數: 123.45
    print(a.round(0, RoundingMode.ROUND_DOWN))       # 向下捨入到整數: 123
    
    # === 比較 ===
    print(a > b)                                     # 大於: True
    print(a == Decimal("123.45"))                    # 等於: True
    print(a.is_zero())                               # 檢查是否爲零: False
    print(Decimal("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(Decimal("2").sqrt())                       # 平方根: 1.4142135623730950488016887242
    print(Decimal("100").root(3))                    # 立方根: 4.641588833612778892410076351
    print(Decimal("2.71828").ln())                   # 自然對數: 0.9999993273472820031578910056
    print(Decimal("10").log10())                     # 10爲底的對數: 1
    print(Decimal("16").log(Decimal("2")))           # 以2爲底的對數: 3.9999999999999999999999999999
    print(Decimal("10").exp())                       # e^10: 22026.465794806716516957900645
    print(Decimal("2").power(10))                    # 冪: 1024
    
    # === 符號處理 ===
    print(-a)                                        # 取反: -123.45
    print(abs(Decimal("-123.45")))                   # 絕對值: 123.45
    print(Decimal("123.45").is_negative())           # 檢查是否爲負: False
    
    # === 特殊值 ===
    print(Decimal.PI())                              # π常數: 3.1415926535897932384626433833
    print(Decimal.E())                               # e常數: 2.7182818284590452353602874714
    print(Decimal.ONE())                             # 值1: 1
    print(Decimal.ZERO())                            # 值0: 0
    print(Decimal.MAX())                             # 最大值: 79228162514264337593543950335
    
    # === 便捷方法 ===
    print(Decimal("123.400").is_integer())           # 檢查是否爲整數: False
    print(a.number_of_significant_digits())          # 計算有效數字: 5
    print(Decimal("12.34").to_str_scientific())      # 科學計數法: 1.234E+1

以下是展示 BigInt 類型每個主要功能的全面快速入門指南。

from decimojo import BigInt

fn main() raises:
    # === 構造 ===
    var a = BigInt("12345678901234567890")         # 從字符串構造
    var b = BigInt(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(BigInt(2).power(10))                     # 冪: 1024
    print(BigInt(2) ** 10)                         # 冪 (使用 ** 運算符): 1024
    
    # === 比較 ===
    print(a > b)                                   # 大於: True
    print(a == BigInt("12345678901234567890"))     # 等於: True
    print(a.is_zero())                             # 檢查是否爲零: False
    
    # === 類型轉換 ===
    print(a.to_str())                              # 轉爲字符串: "12345678901234567890"
    
    # === 符號處理 ===
    print(-a)                                      # 取反: -12345678901234567890
    print(abs(BigInt("-12345678901234567890")))    # 絕對值: 12345678901234567890
    print(a.is_negative())                         # 檢查是否爲負: False

    # === 超大數值計算 ===
    # 3600 位數 // 1800 位數
    print(BigInt("123456789" * 400) // BigInt("987654321" * 200))

目標

金融計算和數據分析需要精確的小數算術,而浮點數無法可靠地提供這種精確性。作爲一名從事金融學研究和信用風險模型驗證工作的人員,在將個人項目從 Python 遷移到 Mojo 時,我需要一個可靠的、能够正確捨入的、固定精度的數值類型。

由於 Mojo 目前在其標準庫中缺乏原生的 Decimal 類型,我決定創建自己的實現來填補這一空白。

本項目從多個已建立的小數實現和文檔中汲取靈感,例如 Python 内置的 Decimal 類型Rust 的 rust_decimal crateMicrosoft 的 Decimal 實現通用小數算術規範 等。非常感謝前輩們的貢獻及其對開放知識共享的促進。

命名

得此魔咒者,即脱凡相,識天數,斬三尸,二十七日飛升。 —— 《太上靈通感應二十七章經》

DeciMojo 結合了 “Deci” 和 “Mojo” 兩詞,反映了其目的和實現語言。”Deci”(源自拉丁詞根”decimus”,意爲”十分之一”)強調了我們對人類自然用於計數和計算的十進制數字系統的關注。

雖然名稱強調了帶小數部分的十進制數,但 DeciMojo 涵蓋了十進制數學的全部範圍。我們的 BigInt 類型雖然只處理整數,但專爲十進制數字系統設計,採用以 10 爲基數的内部表示。這種方法在保持人類可讀的十進制語義的同時提供最佳性能,與專注於二進制的庫形成對比。此外,BigInt 作爲我們 BigDecimal 實現的基礎,使得在整數和小數領域都能進行任意精度的計算。

這個名稱最終強調了我們的使命:爲 Mojo 生態系統帶來精確、可靠的十進制計算,滿足浮點表示無法提供的精確算術的基本需求。

狀態

羅馬不是一日建成的。DeciMojo 目前正在積極開發中。對於 128 位的 Decimal 類型,它已成功通過 “讓它工作” 階段,並已深入 “讓它正確” 階段,同時已實施多項優化。歡迎錯誤報告和功能請求!如果您遇到問題,請在此提交

讓它工作 ✅(已完成)

讓它正確 🔄(大部分完成)

讓它快速 ⚡(顯著進展)

DeciMojo 相較於 Python 的 decimal 模塊提供了卓越的性能,同時保持計算精確度。這一性能差異源於基本設計選擇:

此架構差異解釋了我們的基準測試結果:

bench/ 文件夾中提供了與 Python 的 decimal 模塊的定期基準測試,記錄了性能優勢以及需要不同方法的少數特定操作。

未來擴展 🚀(計劃中)

測試與基準

在將倉庫克隆到本地磁盤後,您可以:

引用

如果您發現 DeciMojo 對您的研究有用,請考慮將它加入您的引用中。

@software{Zhu.2025,
    author       = {Zhu, Yuhao},
    year         = {2025},
    title        = {DeciMojo: A fixed-point decimal arithmetic library in Mojo},
    url          = {https://github.com/forfudan/decimojo},
    version      = {0.3.0},
    note         = {Computer Software}
}

許可證

本倉庫及其所有貢獻内容均採用 Apache 許可證 2.0 版本授權。

  1. Decimal 類型可以表示最多 29 位有效數字,小數點後最多 28 位數字的值。當數值超過最大可表示值(2^96 - 1)時,DeciMojo 會拋出錯誤或將數值捨入以符合這些約束。例如,8.8888888888888888888888888888(總共 29 個 8,小數點後 28 位)的有效數字超過了最大可表示值(2^96 - 1),會自動捨入爲 8.888888888888888888888888889(總共 28 個 8,小數點後 27 位)。DeciMojo 的 Decimal 類型類似於 System.Decimal(C#/.NET)、Rust 中的 rust_decimal、SQL Server 中的 DECIMAL/NUMERIC 等。 

  2. BigInt 實現使用基於 10 的表示進行高效存儲和計算,支持對具有無限精度的整數進行操作。它提供了向下整除(向負無窮舍入)和截斷除法(向零舍入)語義,無論操作數符號如何,都能確保除法操作處理具有正確的數學行爲。 

  3. 基於已完成的 BigInt 實現構建,BigDecimal 將支持整數和小數部分的任意精度,類似於 Python 中的 decimal 和 mpmath、Java 中的 java.math.BigDecimal 等。