Skip to main content

Exact fraction arithmetic, mixed fractions, and recurring decimal conversion.

Project description

fracpylib

PyPI - Version PyPI - Python Version

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

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:

Brickboss's Dev Card

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

fracpylib-2.2.0.tar.gz (12.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

fracpylib-2.2.0-py3-none-any.whl (10.7 kB view details)

Uploaded Python 3

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

Hashes for fracpylib-2.2.0.tar.gz
Algorithm Hash digest
SHA256 af01cb8aa82e4977a541fb12aad5995b0ee93ba2b31c849196d8f0dc758160b2
MD5 bd96191cdd515802bb6b7e15188341b0
BLAKE2b-256 8876fc3adcbf07453fb3267d9f93ae23f8958a5c515bfacd4cf0f2331a2f263e

See more details on using hashes here.

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

Hashes for fracpylib-2.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6d32644b6b2655647d23a5ec382c131d0759146be5c8d28924948d5bd624a11d
MD5 5b8206496f5bd3ba47b66cb4568efdc0
BLAKE2b-256 e72f2b73e58051840189ca03401592968c308bf2db32c599c784db6fdc4bb19e

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page