Skip to main content

Wrapper de int para numeros naturales grandes con slicing por bits

Project description

HugeNat

HugeNat es un wrapper ligero sobre int que mantiene la semántica de los enteros de Python para números naturales (ℕ₀) y añade indexado/slicing por bits, vistas NumPy y un núcleo listo para Numba.

Repositorio: https://github.com/nand0san/huge_nat

Instalación

pip install HugeNats

Creación rápida

import numpy as np
from hugenat import HugeNat

# Desde un entero no negativo
x = HugeNat(123456789)

# Desde limbs (uint64, little-endian: limb 0 es LSB)
limbs = np.array([0xFFFFFFFFFFFFFFFF, 0x1], dtype=np.uint64)
y = HugeNat(limbs)

# Desde una lista/tupla de enteros (se convierten a uint64 y se recortan ceros finales)
z = HugeNat([1, 2, 3])

API tipo int

  • int(x), bool(x), hash(x), str(x) reflejan al entero interno.
  • Métodos compatibles: bit_length(), bit_count(), to_bytes(), from_bytes().
  • Aritmética y bitwise devuelven siempre HugeNat y rechazan resultados negativos en restas.
a = HugeNat(10)
b = HugeNat(7)

int(a + b)        # 17
int(a * b)        # 70
int(a // b)       # 1
int(a % b)        # 3
int(a << 3)       # 80
int(a | b), int(a & b), int(a ^ b)

Indexado de bits

  • Convención: LSB = índice 0. Índices negativos son relativos a bit_length().
  • Fuera de rango lanza IndexError.
  • ~x no está definido y lanza ValueError.
x = HugeNat(0b1101101)  # 109

x[0]    # 1 (LSB)
x[-1]   # 1 (MSB)
# x[100]  # IndexError

Slicing de bits

  • step en {None, 1} usa ruta rápida: normaliza como Python, recorta a [0, nbits] y recompacta para que el bit start pase a ser el bit 0.
  • Cualquier otro step (salvo 0) usa ruta general con semántica completa de slicing de listas y reempaquetado LSB-first.
  • step == 0 -> ValueError.
x = HugeNat(0b1101101)

x[0:3]        # bits 0..2 -> 0b101 (5)
x[2:5]        # 0b110 (6)
x[0:7:2]      # toma cada 2 bits -> 0b10011 (19)
x[5:0:-2]    # slicing con paso negativo

Vista de bits como array

bits(order="msb->lsb" | "lsb->msb", length=None) devuelve np.ndarray de uint8.

x = HugeNat(0b1011)

np.asarray(x.bits())                  # array([1, 0, 1, 1], dtype=uint8)
np.asarray(x.bits(order="lsb->msb")) # array([1, 1, 0, 1], dtype=uint8)
np.asarray(x.bits(length=8))          # padding a la izquierda: 00001011

Cadena de bits agrupados

bits_str(order="msb->lsb" | "lsb->msb", group=64, sep=" ") para depurar o mostrar.

x = HugeNat(0x0123456789ABCDEFFEDCBA9876543210)

x.bits_str(group=4)          # grupos de 4 bits
x.bits_str(group=8)          # grupos de 1 byte
x.bits_str(order="lsb->msb", group=8)

Bytes ida y vuelta

x = HugeNat(2**20 + 123)
length = (x.bit_length() + 7) // 8

b = x.to_bytes(length=length, byteorder="big", signed=False)
y = HugeNat.from_bytes(b, byteorder="big", signed=False)

assert int(y) == int(x)

Rotaciones de bits

Las rotaciones usan el ancho natural (bit_length()):

x = HugeNat(0b100101)

int(x.rotl(2))  # 0b010110
int(x.rotr(2))  # 0b011001

HugeNat(0).rotl(5)  # -> HugeNat(0)

Núcleo Numba-friendly

to_core() devuelve siempre limbs: uint64[::1] (1D contiguo, little-endian por palabra; limb 0 contiene los bits 0..63) y nbits: int. from_core() reconstruye exactamente el mismo valor.

Ejemplo Numba (histograma/unique de nibbles de 4 bits, empezando en el LSB) con signatura estricta y retorno tipado. Observa que seen:uint8 y counts:uint32 requieren types.Tuple, no UniTuple.

import numpy as np
from numba import njit, types

x = HugeNat(2**127 + 0xF00D)
limbs, nbits = x.to_core()

# Asegurar contigüidad y tipos exactos para la signatura
limbs = np.ascontiguousarray(limbs, dtype=np.uint64)
nbits = np.int64(nbits)

RET = types.Tuple((types.Array(types.uint8, 1, "C"), types.Array(types.uint32, 1, "C")))
SIG = RET(types.Array(types.uint64, 1, "C"), types.int64)

@njit(SIG, cache=True)
def unique_nibbles_core(limbs, nbits):
    counts = np.zeros(16, dtype=np.uint32)
    seen = np.zeros(16, dtype=np.uint8)

    if nbits <= 0 or limbs.size == 0:
        return seen, counts

    n_nibbles = nbits >> 2  # solo nibbles completos

    for k in range(n_nibbles):
        bitpos = k << 2       # desplaza 4 bits desde el LSB
        limb_i = bitpos >> 6
        off = bitpos & 63

        x0 = limbs[limb_i]
        if off <= 60:
            nib = (x0 >> np.uint64(off)) & np.uint64(0xF)
        else:
            lo = x0 >> np.uint64(off)
            hi = np.uint64(0)
            if limb_i + 1 < limbs.size:
                hi = limbs[limb_i + 1] << np.uint64(64 - off)
            nib = (lo | hi) & np.uint64(0xF)

        idx = int(nib)
        counts[idx] += np.uint32(1)
        seen[idx] = np.uint8(1)

    return seen, counts

seen, counts = unique_nibbles_core(limbs, nbits)
unique_values = np.nonzero(seen)[0].astype(np.uint8)

# Vuelta al wrapper para seguir trabajando en Python
y = HugeNat.from_core(limbs, nbits)
assert int(y) == int(x)

unique_values, counts[unique_values]

Contrato de dominio

  • Solo enteros >= 0 o arrays 1D de limbs uint64 (little-endian). Valores negativos o dimensiones distintas lanzan ValueError.
  • Los ceros de mayor peso se recortan automáticamente.
  • Las restas que producirían negativos lanzan ValueError.

Desarrollo

  • Dependencias de desarrollo: pytest, numpy.
  • Ejecuta la batería completa: pytest -q.

Las demostraciones completas viven en HugeNat_demo.ipynb y cubren todos los ejemplos anteriores.

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

hugenats-0.1.5.tar.gz (15.3 kB view details)

Uploaded Source

Built Distribution

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

hugenats-0.1.5-py3-none-any.whl (9.2 kB view details)

Uploaded Python 3

File details

Details for the file hugenats-0.1.5.tar.gz.

File metadata

  • Download URL: hugenats-0.1.5.tar.gz
  • Upload date:
  • Size: 15.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for hugenats-0.1.5.tar.gz
Algorithm Hash digest
SHA256 a4b282082cbdefab18ccea9d54fbe946847cd19d608dedb1b4d69be0ee6fcf7f
MD5 17239c3e48dd7b66d6e1fa9645a436de
BLAKE2b-256 57f3b9a3e60afa1355e808b17ee7544e1b7e75a640efcd05a812e5fc3ebf27c3

See more details on using hashes here.

File details

Details for the file hugenats-0.1.5-py3-none-any.whl.

File metadata

  • Download URL: hugenats-0.1.5-py3-none-any.whl
  • Upload date:
  • Size: 9.2 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for hugenats-0.1.5-py3-none-any.whl
Algorithm Hash digest
SHA256 a3cf1e05d30a354f45bd76437701b7b5e2df6df3118cc1b893878cfde29835a2
MD5 58ad350268b3f09ceb94cc7f7b25cbb3
BLAKE2b-256 c45529295f3467883179dcd7bc39fbd1adf03517b97d51293fdbdb96664a21a0

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