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.

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.1.2.tar.gz (11.8 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.1.2-py3-none-any.whl (10.5 kB view details)

Uploaded Python 3

File details

Details for the file fracpylib-2.1.2.tar.gz.

File metadata

  • Download URL: fracpylib-2.1.2.tar.gz
  • Upload date:
  • Size: 11.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for fracpylib-2.1.2.tar.gz
Algorithm Hash digest
SHA256 7d795a27d945e1bb22add49ab27011d5bc4b41adf408ecd998e690f2700a4118
MD5 21a945af454b87660b4ed3e9b47c8c9d
BLAKE2b-256 efe00b77c79bc0d6be220b9a424ca9d383b26bf231798473a0e43c3261768c45

See more details on using hashes here.

File details

Details for the file fracpylib-2.1.2-py3-none-any.whl.

File metadata

  • Download URL: fracpylib-2.1.2-py3-none-any.whl
  • Upload date:
  • Size: 10.5 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.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 c19b5492025f5a2839b3b97bbd78f4fb5a0b74bc5802d2158ede62d53bb79845
MD5 b85510b762d3afe22f131656d589b6d3
BLAKE2b-256 bbe1331f7195d32af79a7108f43d4b94ea3696b9dfcf676006c08fe314104a05

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