This release is a pre-release and may not be stable for production use.
decimo
A drop-in replacement for Python's decimal, written in
Mojo.
⚠️ Development release. The API is settled enough to use, but the versions carry a timestamp:
0.14.0.devYYYYMMDDHHMMSS, where0.14.0is the version of the Mojo library the wheel packages. Wheels: macOS arm64 (11 and later), CPython 3.13 and 3.14. Everywhere else, build from source.
Change one import and your program keeps working:
# from decimal import Decimal, getcontext
from decimo import Decimal, getcontext
getcontext().prec = 50
print(Decimal(1) / Decimal(7))
# 0.14285714285714285714285714285714285714285714285714
The two libraries agree digit for digit. The test suite checks every
operation against the standard library rather than against a table of
expected strings, so "agrees with decimal" is a property that is measured,
not a claim.
How fast is it?
The same benchmark file run against both libraries -- python/benchmarks/compare.py
in the repository, which imports one or the other and runs identical code.
Best of five, on an Apple M-series laptop:
| Program | decimo | decimal | |
|---|---|---|---|
| add/sub/mul/div, 28 digits | 90.6 ns | 73.0 ns | 1.24× slower |
| add/sub/mul/div, 200 digits | 331.8 ns | 409.0 ns | 1.23× faster |
| add/sub/mul/div, 1000 digits | 2.02 µs | 5.89 µs | 2.91× faster |
| compound interest, 150 years | 12.71 µs | 13.08 µs | about the same |
| e from its series, 500 digits | 197.92 µs | 162.75 µs | 1.22× slower |
| sqrt by Newton, 1000 digits | 143.29 µs | 232.29 µs | 1.62× faster |
| pi by Machin, 500 digits | 620.12 µs | 520.17 µs | 1.19× slower |
| parse and print, 1000 digits | 3.28 µs | 2.60 µs | 1.26× slower |
decimo is faster once the numbers are large, and 20-25% behind on small
ones. The small-number gap is not the arithmetic: measured against
libmpdec directly, without an interpreter in the way, decimo is 2-4× faster
at 9 digits and faster at every operation at 1000 digits. What is left is the
cost of the Python call itself -- building the result object and converting
the operands -- which CPython's decimal has had thirty years to shave. See
the benchmarks.
What works
Everything a decimal program normally touches:
- all the operators, including
//,%,divmod()and** getcontext().precandgetcontext().rounding,setcontext(),localcontext()(with keyword overrides),Contextobjects- all the rounding modes:
ROUND_HALF_EVEN,ROUND_HALF_UP,ROUND_HALF_DOWN,ROUND_DOWN,ROUND_UP,ROUND_CEILING,ROUND_FLOOR, exact for arithmetic,quantize,round()andto_integral_value() int(),float(),round(),math.floor/ceil/trunc,hash(),format()Contextyou can compute with:ctx.divide(x, y),ctx.sqrt(x),ctx.quantize(x, y)and the rest, none of them touching the current context- keyword arguments where
decimaltakes them:quantize(exp, rounding=ROUND_HALF_UP),to_integral_value(rounding=...),sqrt(context=...) Decimal((sign, digits, exponent)), soas_tuple()round-tripspow(x, y, modulus), by modular exponentiationquantize,normalize,as_tuple,as_integer_ratio,compare,fma,sqrt,exp,ln,log10,scaleb,adjusted,copy_abs,copy_negate,copy_sign,same_quantum,to_eng_string,max,min- the rest of the specification's surface:
remainder_near,next_plus,next_minus,next_toward,shift,rotate,logical_and,logical_or,logical_xor,logical_invert,logb,compare_total,compare_total_mag,compare_signal,max_mag,min_mag,number_class,to_integral_exact,is_normal,is_subnormal,from_number - the same coercion rules:
intconverts in arithmetic,floatdoes not, and both convert in a comparison copy,deepcopyandpickleZeroDivisionErrorwhere you expect it, and hashes that agree withint,floatanddecimal.Decimal
Three things decimal does not have
decimo.pi(1000) # 1000 digits of pi, by Chudnovsky with binary splitting
decimo.e(50) # 50 digits of e
Decimal(2).sqrt(rounding=ROUND_FLOOR) # and exp, ln, log10 too
pi() and e() use the context precision when given no argument; decimal
has neither, and its documentation gives a recipe to write your own.
rounding= on sqrt, exp, ln and log10 is decimo's own: decimal
ignores the context mode for these and always rounds half to even. And the
answer under any mode is decided rather than approximated. The library
computes wider than you asked, takes the interval its own error bound allows,
and checks that the whole of it rounds to one answer; if a boundary falls
inside, it widens and looks again. The same check now guards the default half
to even, where before the last digit was assumed rather than known -- so
ROUND_FLOOR really does stay under the true value, and a tie really is a
tie.
What does not
decimo refuses these rather than answering differently:
- NaN and infinity. decimo has no non-finite values.
is_nan()andis_infinite()are alwaysFalse. ROUND_05UP. Nothing implements it; setting it raisesNotImplementedError.sqrt,exp,lnandlog10ignore the context rounding, as they do indecimal, and round half to even unless you passrounding=.**follows the context, also as indecimal. All of them are correctly rounded whichever mode applies, as are arithmetic,quantizeandround().//,%,divmod()andremainder_nearwith a long quotient.decimalraisesInvalidOperationwhen the integer quotient has more digits than the precision; decimo answers. The remainder is rounded to the context, as indecimal.Eminonly reaches four methods. Exponents are unbounded, soEminchanges nothing except whatnext_plus(0),next_minus(0),is_subnormal()andnumber_class()say, wheredecimal's answers need a smallest exponent.- Signals and traps.
Context.flagsandContext.trapsexist and stay empty.Inexact,Roundedand the rest are importable but never raised. Emin/Emax. Exponents are unbounded, so nothing ever underflows to zero or overflows to infinity. A loop that waits for a term to become exactly zero will not stop; wait for the sum to stop changing instead.- One context per process, not per thread.
DivisionByZero and InvalidOperation are aliases for ZeroDivisionError
and ValueError, which is what decimo actually raises, so except clauses
written against decimal still catch.
Installing
pip install decimo
Wheels are built for macOS arm64 (macOS 11 and later), for CPython 3.13 and 3.14. On anything else -- Linux included, until its build is verified -- build from source with pixi:
git clone https://github.com/forfudan/decimo && cd decimo
pixi run -e py314 release # or py313; the wheel lands in python/dist/
pip install python/dist/*.whl
Links
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file decimo-0.14.0.dev20260829141518-cp314-cp314-macosx_11_0_arm64.whl.
File metadata
- Download URL: decimo-0.14.0.dev20260829141518-cp314-cp314-macosx_11_0_arm64.whl
- Upload date:
- Size: 939.2 kB
- Tags: CPython 3.14, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1733b2026d9263f52fb01c7895ca99a7da8bd9cfd089e6e13bd43d442222b37f
|
|
| MD5 |
5c186359de63f1a4f324af11d5d43d08
|
|
| BLAKE2b-256 |
6d8299e9b81884d9b51faa76aebb44282431fee84051f0198a4ce42db7d1cec5
|
Provenance
The following attestation bundles were made for decimo-0.14.0.dev20260829141518-cp314-cp314-macosx_11_0_arm64.whl:
Publisher:
release_python.yaml on forfudan/decimo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
decimo-0.14.0.dev20260829141518-cp314-cp314-macosx_11_0_arm64.whl -
Subject digest:
1733b2026d9263f52fb01c7895ca99a7da8bd9cfd089e6e13bd43d442222b37f - Sigstore transparency entry: 2638514514
- Sigstore integration time:
-
Permalink:
forfudan/decimo@2340115d5f8675d51e677926ea3793a890e4d10a -
Branch / Tag:
refs/heads/main - Owner: https://github.com/forfudan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release_python.yaml@2340115d5f8675d51e677926ea3793a890e4d10a -
Trigger Event:
push
-
Statement type:
File details
Details for the file decimo-0.14.0.dev20260829141518-cp313-cp313-macosx_11_0_arm64.whl.
File metadata
- Download URL: decimo-0.14.0.dev20260829141518-cp313-cp313-macosx_11_0_arm64.whl
- Upload date:
- Size: 939.2 kB
- Tags: CPython 3.13, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d88f3437fab8073623642780983ebb17946421d284687bdcb8189e7fa04c407c
|
|
| MD5 |
a4d927746618f3884d037785fa684f0f
|
|
| BLAKE2b-256 |
09bb3caf33054f35a7524b439751dc1e5eeec6460bb52ccc5be83512f06d78ec
|
Provenance
The following attestation bundles were made for decimo-0.14.0.dev20260829141518-cp313-cp313-macosx_11_0_arm64.whl:
Publisher:
release_python.yaml on forfudan/decimo
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
decimo-0.14.0.dev20260829141518-cp313-cp313-macosx_11_0_arm64.whl -
Subject digest:
d88f3437fab8073623642780983ebb17946421d284687bdcb8189e7fa04c407c - Sigstore transparency entry: 2638514489
- Sigstore integration time:
-
Permalink:
forfudan/decimo@2340115d5f8675d51e677926ea3793a890e4d10a -
Branch / Tag:
refs/heads/main - Owner: https://github.com/forfudan
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release_python.yaml@2340115d5f8675d51e677926ea3793a890e4d10a -
Trigger Event:
push
-
Statement type: