Skip to main content

cabal

Números reales exactos (computables) en Python puro, cero dependencias, un solo archivo.

Cada Real es un nodo perezoso de un grafo de expresión que cumple un contrato verificable:

x.aprox(p) -> entero m  con  |m − x·2^p| ≤ 1        (para todo p ∈ ℤ)

La precisión se propaga hacia atrás bajo demanda. No eliges una precisión de trabajo y rezas: pides dígitos y el grafo calcula lo necesario para certificarlos.

from cabal import R, PI, E, raiz, exp, ln, sen

R("0.1") + R("0.2") == R("0.3")        # True — decidible y exacto (atajo racional)
PI.decimales(1000)                      # 1000 decimales correctamente redondeados (~ms)
exp(ln(R("1234.5678"))).decimales(30)   # '1234.567800000000000000000000000000'
PI.intervalo(100)                       # cerco racional certificado: (Fraction, Fraction), ancho 2^-99
(raiz(2)**2 - 2).signo(tope=1024)       # Inseparables: igualdad de opacos = semidecidible. Honesto.

📊 Validación y rendimiento → — 3 599 comprobaciones diferenciales contra mpmath (0 fallos) y un benchmark honesto frente a mpmath / decimal / sympy. Reproducible con bench/.

Garantías y cómo se verifican

  • Contrato ≤ 1 ulp por nodo, con la cota de error demostrada en comentario junto a cada implementación, y verificado empíricamente contra Fraction (oráculo exacto) en cientos de árboles aleatorios de expresiones (test_cabal.py, ancla A1).
  • Dígitos decimales correctamente redondeados (empates exactos hacia +∞), o Inseparables si el presupuesto no alcanza — nunca un dígito silenciosamente falso.
  • Atajo racional: las subexpresiones racionales viajan como Fraction; igualdad y signo de racionales son decidibles y exactos. R("0.1") es 1/10 exacto, no el double más cercano.
  • Cercos exportables: intervalo(bits) devuelve fracciones exactas lo ≤ x ≤ hi — un certificado que puedes verificar fuera de la librería.
  • Semidecidibilidad explícita: el signo de un opaco igual a 0 no es computable (Teorema de Rice de fondo). cabal lo declara con Inseparables en vez de colgar o mentir.
  • Validación cruzada reproducible: a 10 000 dígitos contra mpmath (π, e, ln 2, √2, sen 1, e^π), por fórmulas independientes en enteros puros (π vía atan(1/2)+atan(1/3), ln 2 vía Σ1/(k·2^k), e vía Σ1/k!), y en las fronteras adversariales de cada rama (reducción trigonométrica pegada a k·π/2, atan en ±3/4, ±1, ±3/2, ln junto a potencias de 2, subnormales de float). Arneses en el repo: audit_cabal.py, audit2_cabal.py, stress_cabal.py (usan mpmath; la librería, nada).

Estado del arte (claims calibrados)

No es la primera aritmética real exacta. Es una síntesis distinta:

enfoque deps contrato verificado por tests cercos racionales igualdad
cabal entero escalado (Boehm) + DAG memoizado 0 sí (vs Fraction) sí exacta en ℚ, semidecidible declarada
reals fracciones continuas (Gosper) 0 no no implícita
mpmath flotante de precisión fija 0 n/a (sin certificación) no tolerancia
python-flint (Arb) bolas, C C n/a sí bolas

El aporte es incremental en concepto (Boehm 1986) e innovador en empaque: contrato falsable + atajo racional + semidecidibilidad como API + microlibrería auditable (~1000 líneas).

API

R(v) (int/Fraction/str-decimal/float), operadores + − × ÷ ** abs (también reflejados: 2 ** PI), comparaciones (±inf/nan con la semántica de Python), bool(x) = «x ≠ 0 certificado», raiz, exp, ln, sen, cos, tan, atan, constantes PI, E, LN2. Métodos: aprox(p), decimales(n), intervalo(bits), signo(tope), comparar(otro, tope), iguales_hasta(otro, bits), float(). Exponentes racionales (aunque lleguen como Real o float entero) usan el atajo exacto: (-R(2))**2.0 == 4 es decidible; el resto va por exp(y·ln x) y exige x > 0.

Como ==, < y bool() pueden lanzar Inseparables (dos opacos iguales no se separan nunca), el código robusto usa los equivalentes explícitos con presupuesto: signo(tope), comparar(otro, tope), o el siempre-total iguales_hasta(otro, bits). Cuidado con if real: sobre valores que pueden ser un cero opaco.

Límites de recursos por bloque (se restauran al salir; PresupuestoExcedido al superarlos):

with cabal.contexto(tope=2**20, max_bits=10**6, max_nodos=10**5, max_digitos=10**4):
    ...   # también max_cadena / max_exp10 para el parser de R(str)

sencos(x) devuelve (sen x, cos x) compartiendo la reducción certificada del argumento (tan la usa por dentro). backend("gmp") activa la aceleración opcional con gmpy2: solo los kernels pesados convierten al entrar y devuelven int puro, así que el contrato, la suite y los resultados son bit a bit idénticos en ambos backends (ancla A16); backend("python") vuelve a la referencia auditable. El default es Python puro, cero dependencias; un benchmark honesto reporta cada backend como producto distinto.

Límites (léelos)

  • Comparar dos opacos iguales —o bool/if de un cero opaco— lanza Inseparables al agotar cabal.TOPE (default 65 536 bits). Es matemática, no un bug.
  • decimales(n) necesita ~3.4·n bits de presupuesto: con TOPE default el máximo es ~19 400 dígitos; más allá, el error lo dice claro y basta subir tope=.
  • Cadenas opacas de >~10³ nodos anidados dan RecursionError (límite de CPython; sube sys.setrecursionlimit si construyes grafos muy profundos).
  • raiz certifica el signo del argumento: un negativo —aunque sea diminuto y opaco— lanza ValueError; un opaco indistinguible de 0 lanza Inseparables en vez de inventar √x = 0.
  • R(str) rechaza con ValueError cadenas de más de MAX_CADENA caracteres o con |exponente decimal| > MAX_EXP10 (anti-abuso, configurables; sin esos topes, R("1e100000000") materializa un entero de ~3·10⁸ bits).
  • float(x) lanza OverflowError si |x| excede el double máximo (como float(Fraction)); un opaco con |x| < 2⁻²²⁰⁰ devuelve +0.0 canónico (el bit de signo del cero no se certifica; un racional exacto sí conserva el -0.0 de CPython).
  • repr() es estructural y barato: nunca evalúa el grafo (muestra el racional exacto, su tamaño, o la pista del cache). Los dígitos certificados se piden con decimales(n).
  • exp de argumentos enormes (|x| ≳ 10⁵) genera enteros del tamaño del resultado, y las torres (exp(exp(exp(3)))) son números de 10⁹ bits: cuelgan por aritmética, no por bug.
  • Motores: π (Machin) y LN2 van por binary splitting (suma exacta + una división); exp racional usa binary splitting factorial y el resto de exp/sen/cos Taylor por rectangular splitting. Medido sin cache (CPython 3.13): π a 40 000 dígitos ≈ 0.36 s (≈ 0.16 s con backend("gmp")), e a 10 000 ≈ 7 ms, sen(1) a 10 000 ≈ 0.12 s. atan/ln de argumento general conservan la serie clásica O(p²). raiz es subcuadrática (10⁶ dígitos ≈ 11 s). El presupuesto tope/TOPE debe ser int; es estricto (nunca se sondea más allá).
  • Sin soporte de hash (igualdad semidecidible ⇒ no hashable). No es thread-safe.
  • Construir exp/ln/sen/cos evalúa una sonda barata del argumento.

Autoría

Creado por Escribano Silente. Coautor: esraderey.

MIT. python3 test_cabal.py corre las 922 anclas sin dependencias (926 con gmpy2 presente, que habilita la equivalencia de backends; --gmp corre toda la suite bajo gmp); los arneses de auditoría y estrés añaden ~3 400 verificaciones contra oráculos independientes.

Metadata

Release files for cabal 0.3.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for cabal 0.3.0
File Size Uploaded
cabal-0.3.0.tar.gz 18.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for cabal 0.3.0
File Interpreter ABI Platform
cabal-0.3.0-py3-none-any.whl Python 3 none any Details

Total release size: 35.9 kB

Release files / cabal-0.3.0.tar.gz

Download URL cabal-0.3.0.tar.gz
Size 18.0 kB
Tags Source
SHA-256 checksum
How to use checksums
1f4f96e6f23dec16921f3b1a2387000888990c97fbbb1bc2f65c72f2e51a4050
BLAKE2b-256 checksum
How to use checksums
39a8d27827e60ab1a2ccd4586793786c559d030f44c84b52a2482572ec08494a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release files / cabal-0.3.0-py3-none-any.whl

Download URL cabal-0.3.0-py3-none-any.whl
Size 17.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
cc0e442268c2a7334edb36969a4368ab4d5ef78cd4a3896697c59745901dbeea
BLAKE2b-256 checksum
How to use checksums
8ea125a6f8eeddc39c0d7ad9b83e820b22767f9be82594a3a18fd5f2d83a0cd2
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.13.2

Release history Release notifications | RSS feed

This release

0.3.0 This release

2 release files

0.2.1

2 release files

0.2.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page