Python’s fractions module provides exact rational arithmetic via Fraction. from fractions import Fraction. Construction: Fraction(3, 4) → 3/4; Fraction("3/4") → 3/4; Fraction(0.75) → 3/4 (exact); Fraction("0.75") → 3/4; Fraction(int) → exact integer as Fraction. numerator/denominator: Fraction(2, 6).numerator = 1, .denominator = 3 (always auto-reduces). limit_denominator: Fraction(math.pi).limit_denominator(100) → 22/7; .limit_denominator(10000) → 355/113 — approximates irrational floats as simple fractions. Arithmetic: +, -, *, /, ** all return exact Fractions (no rounding). Comparison: Fraction(1, 3) > Fraction(1, 4) — exact comparison. Mixed: Fraction(1, 3) + 1 → 4/3; Fraction(1, 3) + 0.1 → float (mixed with float loses exactness). from_float: Fraction.from_float(0.1) — exact binary representation (3602879701896397 / 36028797018963968). from_decimal: Fraction.from_decimal(Decimal("0.1")) → 1/10 (exact). Conversion: float(Fraction(1, 3)), int(Fraction(7, 3)) = 2 (truncates). math.floor(Fraction(7, 3)) = 2. Claude Code generates music interval calculators, aspect ratio normalizers, probability fraction reducers, and unit conversion chains.
CLAUDE.md for fractions
## fractions Stack
- Stdlib: from fractions import Fraction
- Create: Fraction(3, 4) Fraction("3/4") Fraction("0.75")
- Reduce: Fraction(6, 8) → 3/4 (always auto-reduces)
- Approx: Fraction(math.pi).limit_denominator(100) → 22/7
- Exact: Fraction(1,3) + Fraction(1,6) → Fraction(1,2) (no float error)
- Mixed: avoid mixing Fraction + float → loses exactness
fractions Rational Arithmetic Pipeline
# app/fracutil.py — fractions, ratios, probability, music, aspect, unit
from __future__ import annotations
import math
from fractions import Fraction
from dataclasses import dataclass
from decimal import Decimal
from typing import NamedTuple
# ─────────────────────────────────────────────────────────────────────────────
# 1. Fraction construction helpers
# ─────────────────────────────────────────────────────────────────────────────
def frac(numerator: int, denominator: int) -> Fraction:
"""
Create a Fraction and return its reduced form.
Example:
frac(6, 8) # Fraction(3, 4)
frac(10, 3) # Fraction(10, 3)
"""
return Fraction(numerator, denominator)
def from_float(x: float) -> Fraction:
"""
Exact Fraction representation of a float.
Note: Fraction.from_float(0.1) ≠ 1/10 due to binary representation.
Example:
from_float(0.5) # Fraction(1, 2)
from_float(0.1) # Fraction(3602879701896397, 36028797018963968)
"""
return Fraction.from_float(x)
def from_decimal(d: Decimal) -> Fraction:
"""
Exact Fraction from a Decimal string (e.g., from user input).
Example:
from_decimal(Decimal("0.1")) # Fraction(1, 10)
from_decimal(Decimal("1.25")) # Fraction(5, 4)
"""
return Fraction.from_decimal(d)
def best_rational(x: float, max_denominator: int = 1000) -> Fraction:
"""
Find the simplest rational approximation to x with denominator ≤ max_denominator.
Example:
best_rational(math.pi, 100) # Fraction(22, 7)
best_rational(math.pi, 10000) # Fraction(355, 113)
best_rational(0.333) # Fraction(1, 3)
"""
return Fraction(x).limit_denominator(max_denominator)
def parse_fraction(s: str) -> Fraction:
"""
Parse a fraction from '3/4', '0.75', '75%', or integer strings.
Example:
parse_fraction("3/4") # Fraction(3, 4)
parse_fraction("75%") # Fraction(3, 4)
parse_fraction("0.75") # Fraction(3, 4)
"""
s = s.strip()
if s.endswith("%"):
return Fraction(s[:-1]) / 100
return Fraction(s)
# ─────────────────────────────────────────────────────────────────────────────
# 2. Fraction arithmetic and display
# ─────────────────────────────────────────────────────────────────────────────
def fraction_add(*fracs: Fraction | int) -> Fraction:
"""
Sum multiple fractions exactly.
Example:
fraction_add(Fraction(1, 3), Fraction(1, 6), Fraction(1, 2)) # Fraction(1, 1)
"""
result = Fraction(0)
for f in fracs:
result += Fraction(f)
return result
def fraction_mul(*fracs: Fraction | int) -> Fraction:
"""
Multiply multiple fractions exactly.
Example:
fraction_mul(Fraction(2, 3), Fraction(3, 4), 2) # Fraction(1, 1)
"""
result = Fraction(1)
for f in fracs:
result *= Fraction(f)
return result
def to_mixed_number(f: Fraction) -> tuple[int, Fraction]:
"""
Return (whole, fractional) representation of f.
E.g., 7/3 → (2, 1/3); -7/3 → (-2, -1/3).
Example:
whole, frac_part = to_mixed_number(Fraction(7, 3))
print(f"{whole} and {frac_part}") # "2 and 1/3"
"""
whole = int(f)
frac_part = f - whole
return whole, frac_part
def format_fraction(f: Fraction, mixed: bool = False) -> str:
"""
Format a Fraction as '3/4' or as a mixed number '2 1/3'.
Example:
format_fraction(Fraction(3, 4)) # "3/4"
format_fraction(Fraction(7, 3), mixed=True) # "2 1/3"
format_fraction(Fraction(4, 1)) # "4"
"""
if f.denominator == 1:
return str(f.numerator)
if not mixed:
return f"{f.numerator}/{f.denominator}"
whole, frac_part = to_mixed_number(f)
if whole == 0:
return f"{frac_part.numerator}/{frac_part.denominator}"
if frac_part == 0:
return str(whole)
return f"{whole} {abs(frac_part.numerator)}/{frac_part.denominator}"
def as_percentage(f: Fraction, decimals: int = 2) -> str:
"""
Return a Fraction as a percentage string.
Example:
as_percentage(Fraction(1, 3)) # "33.33%"
as_percentage(Fraction(1, 4)) # "25.00%"
"""
return f"{float(f) * 100:.{decimals}f}%"
# ─────────────────────────────────────────────────────────────────────────────
# 3. Ratio and proportion
# ─────────────────────────────────────────────────────────────────────────────
def simplify_ratio(a: int, b: int) -> tuple[int, int]:
"""
Simplify an integer ratio a:b to its lowest terms.
Example:
simplify_ratio(1920, 1080) # (16, 9)
simplify_ratio(6, 9) # (2, 3)
"""
g = math.gcd(a, b)
return a // g, b // g
def aspect_ratio(width: int, height: int) -> str:
"""
Return the simplest aspect ratio string e.g. '16:9'.
Example:
aspect_ratio(1920, 1080) # "16:9"
aspect_ratio(800, 600) # "4:3"
"""
w, h = simplify_ratio(width, height)
return f"{w}:{h}"
def distribute_proportionally(total: int, weights: list[int]) -> list[int]:
"""
Distribute total integer units according to weights, using exact fractions.
Guarantees the parts sum exactly to total.
Example:
distribute_proportionally(100, [1, 2, 3]) # [17, 33, 50]
"""
if not weights or total == 0:
return [0] * len(weights)
weight_sum = sum(weights)
fracs = [Fraction(w, weight_sum) * total for w in weights]
# Use floor and distribute remainder by largest fractional parts
floors = [int(math.floor(f)) for f in fracs]
remainders = sorted(
range(len(fracs)),
key=lambda i: -(fracs[i] - floors[i]),
)
deficit = total - sum(floors)
for i in remainders[:deficit]:
floors[i] += 1
return floors
# ─────────────────────────────────────────────────────────────────────────────
# 4. Probability fractions
# ─────────────────────────────────────────────────────────────────────────────
def reduce_probability(favorable: int, total: int) -> Fraction:
"""
Represent a probability as an exact reduced fraction.
Example:
reduce_probability(3, 6) # Fraction(1, 2)
reduce_probability(13, 52) # Fraction(1, 4)
"""
return Fraction(favorable, total)
def combine_independent(*probs: Fraction) -> Fraction:
"""
P(A ∩ B ∩ ...) for independent events.
Example:
combine_independent(Fraction(1,2), Fraction(1,6)) # Fraction(1, 12)
"""
return fraction_mul(*probs)
def at_least_one(*probs: Fraction) -> Fraction:
"""
P(at least one occurs) = 1 - P(none occur), for independent events.
Example:
at_least_one(Fraction(1,6), Fraction(1,6)) # Fraction(11, 36)
"""
none = fraction_mul(*(1 - p for p in probs))
return Fraction(1) - none
# ─────────────────────────────────────────────────────────────────────────────
# 5. Music interval ratios
# ─────────────────────────────────────────────────────────────────────────────
# Just intonation intervals (pure ratios, no equal temperament)
INTERVALS: dict[str, Fraction] = {
"unison": Fraction(1, 1),
"minor_second": Fraction(16, 15),
"major_second": Fraction(9, 8),
"minor_third": Fraction(6, 5),
"major_third": Fraction(5, 4),
"perfect_fourth": Fraction(4, 3),
"tritone": Fraction(45, 32),
"perfect_fifth": Fraction(3, 2),
"minor_sixth": Fraction(8, 5),
"major_sixth": Fraction(5, 3),
"minor_seventh": Fraction(16, 9),
"major_seventh": Fraction(15, 8),
"octave": Fraction(2, 1),
}
def interval_ratio(interval: str) -> Fraction:
"""
Return the just-intonation frequency ratio for a named interval.
Example:
r = interval_ratio("perfect_fifth") # Fraction(3, 2)
print(f"Fifth = {float(r):.4f}") # 1.5000
"""
key = interval.lower().replace(" ", "_")
if key not in INTERVALS:
raise KeyError(f"Unknown interval {interval!r}. Options: {list(INTERVALS)}")
return INTERVALS[key]
def compound_interval(a: str, b: str) -> Fraction:
"""
Compound two named intervals (multiply their ratios).
Example:
compound_interval("perfect_fifth", "major_second") # Fraction(27, 16) ≈ major sixth
"""
return interval_ratio(a) * interval_ratio(b)
# ─────────────────────────────────────────────────────────────────────────────
# Demo
# ─────────────────────────────────────────────────────────────────────────────
if __name__ == "__main__":
print("=== fractions demo ===")
print("\n--- construction ---")
print(f" Fraction(6, 8) = {Fraction(6, 8)}")
print(f" from_float(0.75) = {from_float(0.75)}")
print(f" from_float(0.1) = {from_float(0.1)}") # binary rep
print(f" from_decimal('0.1') = {from_decimal(Decimal('0.1'))}") # exact
print(f" parse_fraction('75%') = {parse_fraction('75%')}")
print(f" best_rational(π, 100) = {best_rational(math.pi, 100)}")
print(f" best_rational(π, 10000) = {best_rational(math.pi, 10000)}")
print("\n--- exact arithmetic ---")
a, b, c = Fraction(1, 3), Fraction(1, 6), Fraction(1, 2)
print(f" 1/3 + 1/6 + 1/2 = {fraction_add(a, b, c)}") # exactly 1
print(f" float approximation: {1/3 + 1/6 + 1/2}") # may not be 1.0
print(f" 2/3 × 3/4 × 2 = {fraction_mul(Fraction(2,3), Fraction(3,4), 2)}")
print("\n--- mixed number / display ---")
f = Fraction(7, 3)
print(f" format {f} → {format_fraction(f)}")
print(f" as mixed: {format_fraction(f, mixed=True)}")
print(f" as pct: {as_percentage(Fraction(1, 3))}")
print("\n--- simplify_ratio / aspect_ratio ---")
print(f" 1920×1080 → {aspect_ratio(1920, 1080)}")
print(f" 2560×1600 → {aspect_ratio(2560, 1600)}")
print(f" simplify(6, 9) → {simplify_ratio(6, 9)}")
print("\n--- distribute_proportionally ---")
parts = distribute_proportionally(100, [1, 2, 3])
print(f" [1,2,3] of 100 → {parts} sum={sum(parts)}")
parts2 = distribute_proportionally(7, [1, 1, 1])
print(f" [1,1,1] of 7 → {parts2} sum={sum(parts2)}")
print("\n--- probability fractions ---")
p_head = reduce_probability(1, 2)
p_six = reduce_probability(1, 6)
p_both = combine_independent(p_head, p_six)
p_either = at_least_one(p_head, p_six)
print(f" P(head) = {p_head}")
print(f" P(six) = {p_six}")
print(f" P(head AND six) = {p_both} = {as_percentage(p_both)}")
print(f" P(head OR six) = {p_either} = {as_percentage(p_either)}")
print("\n--- music intervals ---")
for name in ["perfect_fifth", "major_third", "octave"]:
r = interval_ratio(name)
print(f" {name:20s} = {r} ({float(r):.5f}×)")
fifth_second = compound_interval("perfect_fifth", "major_second")
print(f" fifth + second = {fifth_second} ≈ {float(fifth_second):.4f}")
print("\n=== done ===")
For the decimal.Decimal alternative — Decimal provides arbitrary-precision fixed-point decimal arithmetic with configurable rounding modes; it is ideal for monetary amounts where you need a fixed number of decimal places and IEEE 754 decimal semantics; Fraction provides exact rational arithmetic regardless of how many decimal places the value requires — use Decimal for money and financial calculations where the number of decimal places matters and you want control over rounding policy; use Fraction for exact rational mathematics, music theory, probability, and any domain where you need to represent exact ratios that may not have finite decimal expansions. For the sympy.Rational alternative — sympy.Rational in the SymPy library (PyPI) is part of a full computer algebra system that can simplify expressions, solve equations, and differentiate symbolically; it is far more powerful but requires SymPy as a dependency; fractions.Fraction is stdlib with zero dependencies and covers all purely operational rational arithmetic needs — use sympy for symbolic computation, equation solving, and mathematical proofs; use fractions.Fraction for runtime calculations that just need exact rational numbers in application code. The Claude Skills 360 bundle includes fractions skill sets covering frac()/from_float()/from_decimal()/best_rational()/parse_fraction() construction helpers, fraction_add()/fraction_mul()/to_mixed_number()/format_fraction()/as_percentage() arithmetic and display, simplify_ratio()/aspect_ratio()/distribute_proportionally() ratio and proportion, reduce_probability()/combine_independent()/at_least_one() probability fractions, and INTERVALS/interval_ratio()/compound_interval() just-intonation music ratios. Start with the free tier to try exact rational arithmetic patterns and fractions pipeline code generation.