Exact fraction arithmetic, mixed fractions, and recurring decimal conversion.
Project description
fracpylib
fracpylib is a small, dependency-free Python library for exact fraction arithmetic, mixed fractions, and recurring decimal conversion.
It keeps fractions normalized, supports natural operators, and can round-trip values such as 1.1(6) without losing precision to floats.
Contents
- Highlights
- Installation
- Quick start
- Fraction API
- Mixed fractions
- Periodic decimals
- Utilities
- Development
- License
Highlights
| Feature | Example |
|---|---|
| Canonical immutable fractions | Fraction(6, -8) becomes Fraction(-3, 4) |
| Integer-friendly operators | 1 + Fraction(1, 2) == Fraction(3, 2) |
| Mixed fractions | MixedFraction(1, 5, 4) becomes 2 1/4 |
| Periodic decimal parsing | Fraction.from_decimal("0.(09)") == Fraction(1, 11) |
| Periodic decimal rendering | Fraction(1, 6).to_periodic() == "0.1(6)" |
| Decimal utility checks | FracMisc.is_terminating(Fraction(1, 8)) |
Installation
pip install fracpylib
Quick Start
from fracpylib.fractionlib import Fraction, MixedFraction
a = Fraction(2, 4)
b = Fraction.from_decimal("1.1(6)")
print(a) # 1/2
print(b) # 7/6
print(a + b) # 5/3
print(2 * a) # 1
print(float(b)) # 1.1666666666666667
mixed = MixedFraction(1, 5, 4)
print(mixed) # 2 1/4
print(mixed.to_fraction()) # 9/4
Fraction API
Fraction stores every value in reduced form with a positive denominator. Values are immutable after construction, so equality, hashing, string output, and comparisons all use the same canonical representation.
from fracpylib.fractionlib import Fraction
x = Fraction(4, 8)
y = Fraction(3, 4)
assert x.as_tuple() == (1, 2)
assert x + y == Fraction(5, 4)
assert x - 1 == Fraction(-1, 2)
assert x * y == Fraction(3, 8)
assert x / y == Fraction(2, 3)
assert x ** -2 == Fraction(4, 1)
Helpful methods:
from fracpylib.fractionlib import Fraction, MixedFraction
half = Fraction(1, 2)
assert half.reciprocal() == Fraction(2, 1)
assert half.to_mixed() == MixedFraction(0, 1, 2)
assert half.to_periodic() == "0.5"
Mixed Fractions
MixedFraction accepts whole, numerator, and denominator pieces, then normalizes itself through an improper Fraction. Pass the sign on the whole part and keep the fractional numerator non-negative.
from fracpylib.fractionlib import Fraction, MixedFraction
mf = MixedFraction(1, 5, 4)
assert str(mf) == "2 1/4"
assert mf.to_fraction() == Fraction(9, 4)
assert mf + Fraction(1, 4) == Fraction(5, 2)
assert 3 - mf == Fraction(3, 4)
Negative values are normalized too:
assert str(MixedFraction.from_fraction(Fraction(-3, 2))) == "-1 1/2"
assert str(MixedFraction.from_fraction(Fraction(-1, 2))) == "-1/2"
Periodic Decimals
Use Fraction.from_decimal() when you already have a decimal string. Repeating digits go in parentheses.
from decimal import Decimal
from fracpylib.fractionlib import Fraction
assert Fraction.from_decimal("0.(3)") == Fraction(1, 3)
assert Fraction.from_decimal("1.1(6)") == Fraction(7, 6)
assert Fraction.from_decimal("-0.1(6)") == Fraction(-1, 6)
assert Fraction.from_decimal(".125") == Fraction(1, 8)
assert Fraction.from_decimal(Decimal("1.20")) == Fraction(6, 5)
Use Fraction.from_periodic() when the whole, non-repeating, and repeating parts are already separated:
assert Fraction.from_periodic(whole=1, non_repeating="1", repeating="6") == Fraction(7, 6)
assert Fraction.from_periodic(whole=0, non_repeating="1", repeating="6", sign=-1) == Fraction(-1, 6)
Render exact decimals with to_periodic():
assert Fraction(1, 2).to_periodic() == "0.5"
assert Fraction(1, 3).to_periodic() == "0.(3)"
assert Fraction(1, 6).to_periodic() == "0.1(6)"
assert Fraction(-22, 7).to_periodic() == "-3.(142857)"
Utilities
FracMath exposes arithmetic helpers for users who prefer function calls over operators. FracMisc contains common fraction predicates.
from fracpylib.fractionlib import Fraction, FracMath, FracMisc
assert FracMath.add(Fraction(1, 2), Fraction(1, 3)) == Fraction(5, 6)
assert FracMisc.is_proper(Fraction(2, 3)) is True
assert FracMisc.is_improper(Fraction(3, 2)) is True
assert FracMisc.is_terminating(Fraction(1, 8)) is True
assert FracMisc.has_repeating_decimal(Fraction(1, 3)) is True
The old camelCase utility names are still available:
assert FracMisc.isProper(Fraction(2, 3)) is True
assert FracMisc.isImproper(Fraction(3, 2)) is True
Development
Create or activate a virtual environment, then run:
python -m pip install -e . pytest
python -m pytest -q
Build the package locally with:
python -m build
Publishing is automated by GitHub Actions on pushes to main and version tags. Add a repository secret named PYPI_API_TOKEN; the workflow checks the project files, runs hatch run test, then runs hatch run publish.
License
fracpylib is distributed under the terms of the MIT license.
find me on daily.dev:
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
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 fracpylib-2.2.0.tar.gz.
File metadata
- Download URL: fracpylib-2.2.0.tar.gz
- Upload date:
- Size: 12.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
af01cb8aa82e4977a541fb12aad5995b0ee93ba2b31c849196d8f0dc758160b2
|
|
| MD5 |
bd96191cdd515802bb6b7e15188341b0
|
|
| BLAKE2b-256 |
8876fc3adcbf07453fb3267d9f93ae23f8958a5c515bfacd4cf0f2331a2f263e
|
File details
Details for the file fracpylib-2.2.0-py3-none-any.whl.
File metadata
- Download URL: fracpylib-2.2.0-py3-none-any.whl
- Upload date:
- Size: 10.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6d32644b6b2655647d23a5ec382c131d0759146be5c8d28924948d5bd624a11d
|
|
| MD5 |
5b8206496f5bd3ba47b66cb4568efdc0
|
|
| BLAKE2b-256 |
e72f2b73e58051840189ca03401592968c308bf2db32c599c784db6fdc4bb19e
|