Skip to main content

Python bindings for working with 24-bit integers.

Project description

i24: Integer Types for Rust (i24, u24)

i24 Logo

Crates.io Docs.rs PyPI PyDocs License: MIT

The `i24` package provides specialized 24-bit integer types for Python: **I24** (signed) and **U24** (unsigned). These types are implemented in Rust for high performance and provide a Python interface for working with 24-bit integers commonly found in audio processing, embedded systems, network protocols, and binary data formats.

Features

Integer Types

  • I24: 24-bit signed integer (range: -8,388,608 to 8,388,607)
  • U24: 24-bit unsigned integer (range: 0 to 16,777,215)

Core Functionality

  • Full arithmetic and bitwise operations with overflow checking
  • Conversion to/from Python int and bytes
  • Little-endian, big-endian, and native byte order support
  • NumPy integration for array operations
  • Immutable (frozen) types for thread safety
  • High performance Rust implementation
  • Checked arithmetic operations (return None on overflow)
  • Complete set of comparison operators

This package is part of the i24 project, which also provides Rust implementations. The Python bindings were created to support the Wavers audio processing library.

Installation

Requirements

  • Python 3.10 or later
  • NumPy 1.26 or later (automatically installed as a dependency)

From PyPI

pip install i24

Upgrading

pip install --upgrade i24

From Source

For development or to use the latest unreleased features:

git clone https://github.com/jmg049/i24.git
cd i24
pip install maturin
maturin develop --release

Quick Start

Basic Usage

from i24 import I24, U24

# Create 24-bit integers
signed = I24(1000)
unsigned = U24(2000)

# Arithmetic operations
result = signed + I24(500)
print(result.to_int())  # 1500

# Conversions
as_int = int(signed)
print(as_int)  # 1000

Working with Bytes

from i24 import I24, U24

# Create from bytes (little-endian)
bytes_le = bytes([0x00, 0x10, 0x00])
value = I24.from_bytes(bytes_le, byteorder='little')
print(value.to_int())  # 4096

# Convert to bytes (big-endian)
be_bytes = value.to_bytes(byteorder='big')
print(be_bytes)  # b'\x00\x10\x00'

# Create from big-endian bytes
bytes_be = bytes([0x12, 0x34, 0x56])
value = I24.from_bytes(bytes_be, byteorder='big')
print(hex(value.to_int()))  # 0x123456

Checked Arithmetic

Checked arithmetic methods return None on overflow instead of raising exceptions:

from i24 import I24

a = I24(8_000_000)
b = I24(500_000)

# Safe addition
result = a.checked_add(b)
if result is None:
    print("Addition would overflow")
else:
    print(f"Result: {result.to_int()}")

# Other checked operations
result = a.checked_sub(b)  # Checked subtraction
result = a.checked_mul(I24(2))  # Checked multiplication
result = a.checked_div(b)  # Checked division (also checks for division by zero)

Value Ranges and Overflow Behavior

Value Ranges

  • I24: [-8,388,608, 8,388,607]
  • U24: [0, 16,777,215]

Overflow Behavior

Standard operators raise OverflowError when results exceed the valid range:

from i24 import I24

a = I24(8_000_000)
b = I24(500_000)

try:
    result = a + b  # This will overflow
except OverflowError as e:
    print(f"Overflow: {e}")

Use checked arithmetic methods when you want to handle overflow explicitly without exceptions.

Division by Zero

Division operations raise ZeroDivisionError:

from i24 import I24

a = I24(1000)
zero = I24(0)

try:
    result = a / zero
except ZeroDivisionError as e:
    print(f"Error: {e}")

Supported Operations

Arithmetic Operations

from i24 import I24, U24

a = I24(1000)
b = I24(500)

# Standard operators
sum_val = a + b       # Addition
diff = a - b          # Subtraction
prod = a * b          # Multiplication
quot = a / b          # Division (returns float)
floor_div = a // b    # Floor division
mod = a % b           # Modulo
neg = -a              # Negation
pos = +a              # Unary plus

# Checked operations (return None on overflow)
safe_sum = a.checked_add(b)
safe_diff = a.checked_sub(b)
safe_prod = a.checked_mul(b)
safe_quot = a.checked_div(b)

Bitwise Operations

from i24 import I24, U24

a = I24(0b111100001111)
b = I24(0b110011001100)

# Bitwise operators
and_result = a & b    # Bitwise AND
or_result = a | b     # Bitwise OR
xor_result = a ^ b    # Bitwise XOR
not_result = ~a       # Bitwise NOT
left_shift = a << 4   # Left shift
right_shift = a >> 2  # Right shift

Comparison Operations

from i24 import I24

a = I24(1000)
b = I24(2000)

# All standard comparison operators
is_equal = a == b      # Equality
not_equal = a != b     # Inequality
less = a < b           # Less than
less_eq = a <= b       # Less than or equal
greater = a > b        # Greater than
greater_eq = a >= b    # Greater than or equal

Byte Operations and Endianness

All byte operations support three byte orders:

  • 'little': Little-endian (least significant byte first)
  • 'big': Big-endian (most significant byte first)
  • 'native': Native byte order (platform-dependent)

Converting to Bytes

from i24 import I24

value = I24(0x123456)

# Little-endian (LSB first)
le_bytes = value.to_bytes(byteorder='little')
print(le_bytes)  # b'\x56\x34\x12'

# Big-endian (MSB first)
be_bytes = value.to_bytes(byteorder='big')
print(be_bytes)  # b'\x12\x34\x56'

# Native byte order (platform-dependent)
native_bytes = value.to_bytes(byteorder='native')

Creating from Bytes

from i24 import I24

# From little-endian bytes
bytes_le = bytes([0x12, 0x34, 0x56])
value = I24.from_bytes(bytes_le, byteorder='little')
print(hex(value.to_int()))  # 0x563412

# From big-endian bytes
bytes_be = bytes([0x12, 0x34, 0x56])
value = I24.from_bytes(bytes_be, byteorder='big')
print(hex(value.to_int()))  # 0x123456

Use Cases

Audio Processing

24-bit integers are commonly used in professional audio applications:

from i24 import I24

# Read 24-bit audio samples
def read_24bit_samples(data: bytes) -> list[I24]:
    samples = []
    for i in range(0, len(data), 3):
        sample_bytes = data[i:i+3]
        sample = I24.from_bytes(sample_bytes, byteorder='little')
        samples.append(sample)
    return samples

Binary Protocols

Handling network protocols with 24-bit fields:

from i24 import U24

# Parse a 24-bit packet ID
packet_bytes = bytes([0x12, 0x34, 0x56])
packet_id = U24.from_bytes(packet_bytes, byteorder='big')
print(f"Packet ID: {packet_id.to_int()}")

Embedded Systems

Working with hardware that uses 24-bit data types:

from i24 import U24

# Read 24-bit sensor value
sensor_data = bytes([0xFF, 0x00, 0x12])
sensor_value = U24.from_bytes(sensor_data, byteorder='little')
print(f"Sensor reading: {sensor_value.to_int()}")

Type Safety

Both I24 and U24 are immutable (frozen) types, making them safe for use in multi-threaded environments:

from i24 import I24

value = I24(1000)
# value.some_attribute = 42  # This would raise an error
# I24 instances cannot be modified after creation

Performance

The i24 package is implemented in Rust using PyO3, providing:

  • Near-native performance for arithmetic operations
  • Similar to i32 and u32 performance

Documentation

Full documentation is available at: https://jmg049.github.io/i24/

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Visit the main repository at: https://github.com/jmg049/i24

License

This project is licensed under MIT - see the LICENSE file for details.

Links

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

i24_type-2.3.2.tar.gz (1.6 MB view details)

Uploaded Source

Built Distribution

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

i24_type-2.3.2-cp314-cp314-manylinux_2_34_x86_64.whl (257.8 kB view details)

Uploaded CPython 3.14manylinux: glibc 2.34+ x86-64

File details

Details for the file i24_type-2.3.2.tar.gz.

File metadata

  • Download URL: i24_type-2.3.2.tar.gz
  • Upload date:
  • Size: 1.6 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: maturin/1.11.2

File hashes

Hashes for i24_type-2.3.2.tar.gz
Algorithm Hash digest
SHA256 96b7c5a73699fb70e2abf0dc1f384d3e493fded879c30bf79e25176bad4afc87
MD5 b6f246bdd02c513814a2e4e515a28180
BLAKE2b-256 a2de4f0a83e6cd976048291f14b36b01f8bd778b00ba1761d089ef1f8dedc902

See more details on using hashes here.

File details

Details for the file i24_type-2.3.2-cp314-cp314-manylinux_2_34_x86_64.whl.

File metadata

File hashes

Hashes for i24_type-2.3.2-cp314-cp314-manylinux_2_34_x86_64.whl
Algorithm Hash digest
SHA256 c1ac0e88c958812f06c9bc758e1730469636d19f1d460281693bedd24d9e64e3
MD5 44206c17ce898ee2fee8f7ce72224357
BLAKE2b-256 9c6e2c390ac511fc9c8937faaec8a46dfad2a6a8913d3fb4f868459d8d525a8f

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