flexfloat 0.1.2__py3-none-any.whl → 0.1.5__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- flexfloat/__init__.py +28 -5
- flexfloat/bitarray/__init__.py +31 -0
- flexfloat/bitarray/bitarray.py +298 -0
- flexfloat/bitarray/bitarray_bigint.py +305 -0
- flexfloat/bitarray/bitarray_bool.py +202 -0
- flexfloat/bitarray/bitarray_int64.py +333 -0
- flexfloat/bitarray/bitarray_mixins.py +156 -0
- flexfloat/core.py +482 -94
- flexfloat/types.py +7 -1
- flexfloat-0.1.5.dist-info/METADATA +340 -0
- flexfloat-0.1.5.dist-info/RECORD +15 -0
- flexfloat/bitarray.py +0 -257
- flexfloat-0.1.2.dist-info/METADATA +0 -147
- flexfloat-0.1.2.dist-info/RECORD +0 -10
- {flexfloat-0.1.2.dist-info → flexfloat-0.1.5.dist-info}/WHEEL +0 -0
- {flexfloat-0.1.2.dist-info → flexfloat-0.1.5.dist-info}/licenses/LICENSE +0 -0
- {flexfloat-0.1.2.dist-info → flexfloat-0.1.5.dist-info}/top_level.txt +0 -0
flexfloat/types.py
CHANGED
@@ -1,4 +1,10 @@
|
|
1
|
-
"""Type definitions for the flexfloat package.
|
1
|
+
"""Type definitions for the flexfloat package.
|
2
|
+
|
3
|
+
This module provides type aliases used throughout the flexfloat package.
|
4
|
+
|
5
|
+
Type Aliases:
|
6
|
+
Number: Alias for int | float, used for numeric arguments.
|
7
|
+
"""
|
2
8
|
|
3
9
|
from typing import TypeAlias
|
4
10
|
|
@@ -0,0 +1,340 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: flexfloat
|
3
|
+
Version: 0.1.5
|
4
|
+
Summary: A library for arbitrary precision floating point arithmetic
|
5
|
+
Author: Ferran Sanchez Llado
|
6
|
+
License: MIT
|
7
|
+
Classifier: Development Status :: 3 - Alpha
|
8
|
+
Classifier: Intended Audience :: Developers
|
9
|
+
Classifier: Intended Audience :: Science/Research
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
11
|
+
Classifier: Operating System :: OS Independent
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
15
|
+
Classifier: Topic :: Scientific/Engineering :: Mathematics
|
16
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
17
|
+
Requires-Python: >=3.11
|
18
|
+
Description-Content-Type: text/markdown
|
19
|
+
License-File: LICENSE
|
20
|
+
Provides-Extra: dev
|
21
|
+
Requires-Dist: pytest>=7.0; extra == "dev"
|
22
|
+
Requires-Dist: pytest-cov>=4.0; extra == "dev"
|
23
|
+
Requires-Dist: black>=23.0; extra == "dev"
|
24
|
+
Requires-Dist: isort>=5.0; extra == "dev"
|
25
|
+
Requires-Dist: mypy>=1.0; extra == "dev"
|
26
|
+
Requires-Dist: pylint>=3.0; extra == "dev"
|
27
|
+
Requires-Dist: flake8>=6.0; extra == "dev"
|
28
|
+
Requires-Dist: bump2version>=1.0; extra == "dev"
|
29
|
+
Requires-Dist: build>=0.10; extra == "dev"
|
30
|
+
Requires-Dist: twine>=4.0; extra == "dev"
|
31
|
+
Requires-Dist: check-manifest>=0.49; extra == "dev"
|
32
|
+
Requires-Dist: PyYAML>=6.0; extra == "dev"
|
33
|
+
Dynamic: license-file
|
34
|
+
|
35
|
+
# FlexFloat
|
36
|
+
|
37
|
+
[](https://www.python.org/downloads/)
|
38
|
+
[](https://opensource.org/licenses/MIT)
|
39
|
+
[](https://badge.fury.io/py/flexfloat)
|
40
|
+
|
41
|
+
A high-precision Python library for arbitrary precision floating-point arithmetic with **growable exponents** and **fixed-size fractions**. FlexFloat extends IEEE 754 double-precision format to handle numbers beyond the standard range while maintaining computational efficiency and precision consistency.
|
42
|
+
|
43
|
+
## ✨ Key Features
|
44
|
+
|
45
|
+
- **🔢 Growable Exponents**: Dynamically expand exponent size to handle extremely large (>10^308) or small (<10^-308) numbers
|
46
|
+
- **🎯 Fixed-Size Fractions**: Maintain IEEE 754-compatible 52-bit fraction precision for consistent accuracy
|
47
|
+
- **⚡ Full Arithmetic Support**: Addition, subtraction, multiplication, division, and power operations
|
48
|
+
- **🔧 Multiple BitArray Backends**: Choose between list-based and int64-based implementations for optimal performance
|
49
|
+
- **🌟 Special Value Handling**: Complete support for NaN, ±infinity, and zero values
|
50
|
+
- **🛡️ Overflow Protection**: Automatic exponent growth prevents overflow/underflow errors
|
51
|
+
- **📊 IEEE 754 Baseline**: Fully compatible with standard double-precision format as the starting point
|
52
|
+
|
53
|
+
## 🚀 Quick Start
|
54
|
+
|
55
|
+
### Installation
|
56
|
+
|
57
|
+
```bash
|
58
|
+
pip install flexfloat
|
59
|
+
```
|
60
|
+
|
61
|
+
### Basic Usage
|
62
|
+
|
63
|
+
```python
|
64
|
+
from flexfloat import FlexFloat
|
65
|
+
|
66
|
+
# Create FlexFloat instances
|
67
|
+
a = FlexFloat.from_float(1.5)
|
68
|
+
b = FlexFloat.from_float(2.5)
|
69
|
+
|
70
|
+
# Perform arithmetic operations
|
71
|
+
result = a + b
|
72
|
+
print(result.to_float()) # 4.0
|
73
|
+
|
74
|
+
# Handle very large numbers that would overflow standard floats
|
75
|
+
large_a = FlexFloat.from_float(1e308)
|
76
|
+
large_b = FlexFloat.from_float(1e308)
|
77
|
+
large_result = large_a + large_b
|
78
|
+
|
79
|
+
# Result automatically grows exponent to handle the overflow
|
80
|
+
print(f"Exponent bits: {len(large_result.exponent)}") # > 11 (grown beyond IEEE 754)
|
81
|
+
print(f"Can represent: {large_result}") # No overflow!
|
82
|
+
```
|
83
|
+
|
84
|
+
### Advanced Examples
|
85
|
+
|
86
|
+
```python
|
87
|
+
from flexfloat import FlexFloat
|
88
|
+
|
89
|
+
# Mathematical operations
|
90
|
+
x = FlexFloat.from_float(2.0)
|
91
|
+
y = FlexFloat.from_float(3.0)
|
92
|
+
|
93
|
+
# Power operations
|
94
|
+
power_result = x ** y # 2^3 = 8
|
95
|
+
print(power_result.to_float()) # 8.0
|
96
|
+
|
97
|
+
# Exponential using Euler's number
|
98
|
+
e_result = FlexFloat.e ** x # e^2
|
99
|
+
print(f"e^2 ≈ {e_result.to_float()}")
|
100
|
+
|
101
|
+
# Working with extreme values
|
102
|
+
tiny = FlexFloat.from_float(1e-300)
|
103
|
+
huge = FlexFloat.from_float(1e300)
|
104
|
+
extreme_product = tiny * huge
|
105
|
+
print(f"Product: {extreme_product.to_float()}") # Still computable!
|
106
|
+
|
107
|
+
# Precision demonstration
|
108
|
+
precise_calc = FlexFloat.from_float(1.0) / FlexFloat.from_float(3.0)
|
109
|
+
print(f"1/3 with 52-bit precision: {precise_calc}")
|
110
|
+
```
|
111
|
+
|
112
|
+
## 🔧 BitArray Backends
|
113
|
+
|
114
|
+
FlexFloat supports multiple BitArray implementations for different performance characteristics:
|
115
|
+
|
116
|
+
```python
|
117
|
+
from flexfloat import (
|
118
|
+
FlexFloat,
|
119
|
+
set_default_implementation,
|
120
|
+
get_available_implementations
|
121
|
+
)
|
122
|
+
|
123
|
+
# View available implementations
|
124
|
+
print(get_available_implementations()) # ['list', 'int64']
|
125
|
+
|
126
|
+
# Use list-based implementation (default, more flexible)
|
127
|
+
set_default_implementation('list')
|
128
|
+
flex_list = FlexFloat.from_float(42.0)
|
129
|
+
|
130
|
+
# Use int64-based implementation (faster for small bit arrays)
|
131
|
+
set_default_implementation('int64')
|
132
|
+
flex_int64 = FlexFloat.from_float(42.0)
|
133
|
+
|
134
|
+
# Both produce the same results with different performance characteristics
|
135
|
+
```
|
136
|
+
|
137
|
+
### Implementation Comparison
|
138
|
+
|
139
|
+
| Implementation | Best For | Pros | Cons |
|
140
|
+
|---------------|----------|------|------|
|
141
|
+
| `list[bool]` | Smaller exponents and testing | Flexible, easy to understand | Slower for large numbers |
|
142
|
+
| `list[int64]` | Standard operations | Fast for bigger numbers, efficient memory | Overhead for small numbers |
|
143
|
+
|
144
|
+
## 📚 API Reference
|
145
|
+
|
146
|
+
### Core Operations
|
147
|
+
|
148
|
+
```python
|
149
|
+
# Construction
|
150
|
+
FlexFloat.from_float(value: float) -> FlexFloat
|
151
|
+
FlexFloat(sign: bool, exponent: BitArray, fraction: BitArray)
|
152
|
+
|
153
|
+
# Conversion
|
154
|
+
flexfloat.to_float() -> float
|
155
|
+
|
156
|
+
# Arithmetic
|
157
|
+
a + b, a - b, a * b, a / b, a ** b
|
158
|
+
abs(a), -a
|
159
|
+
|
160
|
+
# Mathematical functions
|
161
|
+
FlexFloat.e ** x # Exponential function
|
162
|
+
```
|
163
|
+
|
164
|
+
### Special Values
|
165
|
+
|
166
|
+
```python
|
167
|
+
from flexfloat import FlexFloat
|
168
|
+
|
169
|
+
# Create special values
|
170
|
+
nan_val = FlexFloat.nan()
|
171
|
+
inf_val = FlexFloat.infinity()
|
172
|
+
neg_inf = FlexFloat.negative_infinity()
|
173
|
+
zero_val = FlexFloat.zero()
|
174
|
+
|
175
|
+
# Check for special values
|
176
|
+
if result.is_nan():
|
177
|
+
print("Result is Not a Number")
|
178
|
+
if result.is_infinite():
|
179
|
+
print("Result is infinite")
|
180
|
+
```
|
181
|
+
|
182
|
+
## 🧪 Development & Testing
|
183
|
+
|
184
|
+
### Development Installation
|
185
|
+
|
186
|
+
```bash
|
187
|
+
git clone https://github.com/ferranSanchezLlado/flexfloat-py.git
|
188
|
+
cd flexfloat-py
|
189
|
+
pip install -e ".[dev]"
|
190
|
+
```
|
191
|
+
|
192
|
+
### Running Tests
|
193
|
+
|
194
|
+
```bash
|
195
|
+
# Run all tests
|
196
|
+
python -m pytest tests/
|
197
|
+
|
198
|
+
# Run with coverage
|
199
|
+
python -m pytest tests/ --cov=flexfloat --cov-report=html
|
200
|
+
|
201
|
+
# Run specific test categories
|
202
|
+
python -m pytest tests/test_arithmetic.py # Arithmetic operations
|
203
|
+
python -m pytest tests/test_conversions.py # Number conversions
|
204
|
+
python -m pytest tests/test_bitarray.py # BitArray implementations
|
205
|
+
```
|
206
|
+
|
207
|
+
### Code Quality
|
208
|
+
|
209
|
+
```bash
|
210
|
+
# Format code
|
211
|
+
black flexfloat/ tests/
|
212
|
+
|
213
|
+
# Sort imports
|
214
|
+
isort flexfloat/ tests/
|
215
|
+
|
216
|
+
# Type checking
|
217
|
+
mypy flexfloat/
|
218
|
+
|
219
|
+
# Linting
|
220
|
+
pylint flexfloat/
|
221
|
+
flake8 flexfloat/
|
222
|
+
```
|
223
|
+
|
224
|
+
## 🎯 Use Cases
|
225
|
+
|
226
|
+
### Scientific Computing
|
227
|
+
```python
|
228
|
+
# Handle calculations that would overflow standard floats
|
229
|
+
from flexfloat import FlexFloat
|
230
|
+
|
231
|
+
# Factorial of large numbers
|
232
|
+
def flex_factorial(n):
|
233
|
+
result = FlexFloat.from_float(1.0)
|
234
|
+
for i in range(1, n + 1):
|
235
|
+
result = result * FlexFloat.from_float(i)
|
236
|
+
return result
|
237
|
+
|
238
|
+
large_factorial = flex_factorial(1000) # No overflow!
|
239
|
+
```
|
240
|
+
|
241
|
+
### Financial Calculations
|
242
|
+
```python
|
243
|
+
# High-precision compound interest calculations
|
244
|
+
principal = FlexFloat.from_float(1000000.0)
|
245
|
+
rate = FlexFloat.from_float(1.05) # 5% annual return
|
246
|
+
years = FlexFloat.from_float(100)
|
247
|
+
|
248
|
+
# Calculate compound interest over very long periods
|
249
|
+
final_amount = principal * (rate ** years)
|
250
|
+
```
|
251
|
+
|
252
|
+
### Physics Simulations
|
253
|
+
```python
|
254
|
+
# Handle extreme values in physics calculations
|
255
|
+
c = FlexFloat.from_float(299792458) # Speed of light
|
256
|
+
mass = FlexFloat.from_float(1e-30) # Atomic mass
|
257
|
+
|
258
|
+
# E = mc² with extreme precision
|
259
|
+
energy = mass * c * c
|
260
|
+
```
|
261
|
+
|
262
|
+
## 🏗️ Architecture
|
263
|
+
|
264
|
+
FlexFloat is built with a modular architecture:
|
265
|
+
|
266
|
+
```
|
267
|
+
flexfloat/
|
268
|
+
├── core.py # Main FlexFloat class
|
269
|
+
├── types.py # Type definitions
|
270
|
+
├── bitarray/ # BitArray implementations
|
271
|
+
│ ├── bitarray.py # Abstract base class
|
272
|
+
│ ├── bitarray_list.py # List-based implementation
|
273
|
+
│ ├── bitarray_int64.py # Int64-based implementation
|
274
|
+
│ └── bitarray_mixins.py # Common functionality
|
275
|
+
└── __init__.py # Public API exports
|
276
|
+
```
|
277
|
+
|
278
|
+
### Design Principles
|
279
|
+
|
280
|
+
1. **IEEE 754 Compatibility**: Start with standard double-precision format
|
281
|
+
2. **Graceful Scaling**: Automatically expand exponent when needed
|
282
|
+
3. **Precision Preservation**: Keep fraction size fixed for consistent accuracy
|
283
|
+
4. **Performance Options**: Multiple backends for different use cases
|
284
|
+
5. **Pythonic Interface**: Natural syntax for mathematical operations
|
285
|
+
|
286
|
+
## 📊 Performance Considerations
|
287
|
+
|
288
|
+
### When to Use FlexFloat
|
289
|
+
|
290
|
+
✅ **Good for:**
|
291
|
+
- Calculations requiring numbers > 10^308 or < 10^-308
|
292
|
+
- Scientific computing with extreme values
|
293
|
+
- Financial calculations requiring high precision
|
294
|
+
- Preventing overflow/underflow in long calculations
|
295
|
+
|
296
|
+
❌ **Consider alternatives for:**
|
297
|
+
- Simple arithmetic with standard-range numbers
|
298
|
+
- Performance-critical tight loops
|
299
|
+
- Applications where standard `float` precision is sufficient
|
300
|
+
|
301
|
+
### Optimization Tips
|
302
|
+
|
303
|
+
```python
|
304
|
+
# Prefer int64 implementation for standard operations
|
305
|
+
set_default_implementation('int64')
|
306
|
+
|
307
|
+
# Batch operations when possible
|
308
|
+
values = [FlexFloat.from_float(x) for x in range(1000)]
|
309
|
+
sum_result = sum(values, FlexFloat.zero())
|
310
|
+
|
311
|
+
# Use appropriate precision for your use case
|
312
|
+
if value_in_standard_range:
|
313
|
+
result = float(flexfloat_result.to_float()) # Convert back if needed
|
314
|
+
```
|
315
|
+
|
316
|
+
## 📋 Roadmap
|
317
|
+
|
318
|
+
- [ ] Additional mathematical functions (sin, cos, tan, log, sqrt)
|
319
|
+
- [ ] Serialization support (JSON, pickle)
|
320
|
+
- [ ] Performance optimizations for large arrays
|
321
|
+
- [ ] Complex number support
|
322
|
+
- [ ] Decimal mode for exact decimal representation
|
323
|
+
|
324
|
+
|
325
|
+
## 📄 License
|
326
|
+
|
327
|
+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
328
|
+
|
329
|
+
## 🙏 Acknowledgments
|
330
|
+
|
331
|
+
- IEEE 754 standard for floating-point arithmetic foundation
|
332
|
+
- Python community for inspiration and best practices
|
333
|
+
- Contributors and users who help improve the library
|
334
|
+
|
335
|
+
## 📞 Support
|
336
|
+
|
337
|
+
- 📚 **Documentation**: Full API documentation available in docstrings
|
338
|
+
- 🐛 **Issues**: Report bugs on [GitHub Issues](https://github.com/ferranSanchezLlado/flexfloat-py/issues)
|
339
|
+
- 💬 **Discussions**: Join conversations on [GitHub Discussions](https://github.com/ferranSanchezLlado/flexfloat-py/discussions)
|
340
|
+
- 📧 **Contact**: Reach out to the maintainer for questions
|
@@ -0,0 +1,15 @@
|
|
1
|
+
flexfloat/__init__.py,sha256=u-B9oE-zA_3wuKYhRMLiXldCKN7Xeclf5gK0vAT2OBI,933
|
2
|
+
flexfloat/core.py,sha256=EQiBMmUtDreWFLjVeuaEiEj-PyNNcOV9BmRtOCs4neU,42821
|
3
|
+
flexfloat/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
4
|
+
flexfloat/types.py,sha256=Enm4-oyGnvxGI-7MOK6eEIH2IzWafk0wQBsPaTqFYrE,266
|
5
|
+
flexfloat/bitarray/__init__.py,sha256=aFnw7HSlFwWnFwmLhmjvRwt6qOakbUochHwT8di0v14,979
|
6
|
+
flexfloat/bitarray/bitarray.py,sha256=L8CYFSxyMgfV-CpvtrKJ_kO3nexsHK2E2pNN9BfnNyI,8428
|
7
|
+
flexfloat/bitarray/bitarray_bigint.py,sha256=yLfAreZ9hhP2f2dIS7ptYSuAFlUTXJiv-LtHhRWN5dc,9986
|
8
|
+
flexfloat/bitarray/bitarray_bool.py,sha256=naTUcTycvP9BfU1_CJRgajgvsJoQz9jvi5aI224pphE,6429
|
9
|
+
flexfloat/bitarray/bitarray_int64.py,sha256=FLfbg2gk_Ia-9_4UjoiWYZNK3CbD4teAYU5SGSV3WF0,10856
|
10
|
+
flexfloat/bitarray/bitarray_mixins.py,sha256=HJkyseP_yat0tE3_XElFEqBgKk8oWEiHEKjzqIRwUnw,5026
|
11
|
+
flexfloat-0.1.5.dist-info/licenses/LICENSE,sha256=uwwkK--SUYUV3lbrv9kXJ_vDiYfHVb-t732g6c4qg7Q,1077
|
12
|
+
flexfloat-0.1.5.dist-info/METADATA,sha256=wAYgXkZWRv9YERXb5-XygV8y506I8GW2Dg-C1uiaIu4,10375
|
13
|
+
flexfloat-0.1.5.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
14
|
+
flexfloat-0.1.5.dist-info/top_level.txt,sha256=82S8dY2UoNZh-9pwg7tUvbwB3uw2s3mfEoyUW6vCMdU,10
|
15
|
+
flexfloat-0.1.5.dist-info/RECORD,,
|
flexfloat/bitarray.py
DELETED
@@ -1,257 +0,0 @@
|
|
1
|
-
"""BitArray implementation for the flexfloat package."""
|
2
|
-
|
3
|
-
from __future__ import annotations
|
4
|
-
|
5
|
-
import struct
|
6
|
-
from typing import Iterator, overload
|
7
|
-
|
8
|
-
|
9
|
-
class BitArray:
|
10
|
-
"""A bit array class that encapsulates a list of booleans with utility methods.
|
11
|
-
|
12
|
-
This class provides all the functionality previously available through utility
|
13
|
-
functions, now encapsulated as methods for better object-oriented design.
|
14
|
-
"""
|
15
|
-
|
16
|
-
def __init__(self, bits: list[bool] | None = None):
|
17
|
-
"""Initialize a BitArray.
|
18
|
-
|
19
|
-
Args:
|
20
|
-
bits: Initial list of boolean values. Defaults to empty list.
|
21
|
-
"""
|
22
|
-
self._bits = bits if bits is not None else []
|
23
|
-
|
24
|
-
@classmethod
|
25
|
-
def from_float(cls, value: float) -> BitArray:
|
26
|
-
"""Convert a floating-point number to a bit array.
|
27
|
-
|
28
|
-
Args:
|
29
|
-
value (float): The floating-point number to convert.
|
30
|
-
Returns:
|
31
|
-
BitArray: A BitArray representing the bits of the floating-point number.
|
32
|
-
"""
|
33
|
-
# Pack as double precision (64 bits)
|
34
|
-
packed = struct.pack("!d", value)
|
35
|
-
# Convert to boolean list
|
36
|
-
bits = [bool((byte >> bit) & 1) for byte in packed for bit in range(7, -1, -1)]
|
37
|
-
return cls(bits)
|
38
|
-
|
39
|
-
@classmethod
|
40
|
-
def from_signed_int(cls, value: int, length: int) -> BitArray:
|
41
|
-
"""Convert a signed integer to a bit array using off-set binary representation.
|
42
|
-
|
43
|
-
Args:
|
44
|
-
value (int): The signed integer to convert.
|
45
|
-
length (int): The length of the resulting bit array.
|
46
|
-
Returns:
|
47
|
-
BitArray: A BitArray representing the bits of the signed integer.
|
48
|
-
Raises:
|
49
|
-
AssertionError: If the value is out of range for the specified length.
|
50
|
-
"""
|
51
|
-
half = 1 << (length - 1)
|
52
|
-
max_value = half - 1
|
53
|
-
min_value = -half
|
54
|
-
|
55
|
-
assert (
|
56
|
-
min_value <= value <= max_value
|
57
|
-
), "Value out of range for specified length."
|
58
|
-
|
59
|
-
# Convert to unsigned integer representation
|
60
|
-
unsigned_value = value - half
|
61
|
-
|
62
|
-
bits = [(unsigned_value >> i) & 1 == 1 for i in range(length - 1, -1, -1)]
|
63
|
-
return cls(bits)
|
64
|
-
|
65
|
-
@classmethod
|
66
|
-
def zeros(cls, length: int) -> BitArray:
|
67
|
-
"""Create a BitArray filled with zeros.
|
68
|
-
|
69
|
-
Args:
|
70
|
-
length: The length of the bit array.
|
71
|
-
Returns:
|
72
|
-
BitArray: A BitArray filled with False values.
|
73
|
-
"""
|
74
|
-
return cls([False] * length)
|
75
|
-
|
76
|
-
@classmethod
|
77
|
-
def ones(cls, length: int) -> BitArray:
|
78
|
-
"""Create a BitArray filled with ones.
|
79
|
-
|
80
|
-
Args:
|
81
|
-
length: The length of the bit array.
|
82
|
-
Returns:
|
83
|
-
BitArray: A BitArray filled with True values.
|
84
|
-
"""
|
85
|
-
return cls([True] * length)
|
86
|
-
|
87
|
-
@staticmethod
|
88
|
-
def parse_bitarray(bitstring: str) -> BitArray:
|
89
|
-
"""Parse a string of bits (with optional spaces) into a BitArray instance."""
|
90
|
-
bits = [c == "1" for c in bitstring if c in "01"]
|
91
|
-
return BitArray(bits)
|
92
|
-
|
93
|
-
def to_float(self) -> float:
|
94
|
-
"""Convert a 64-bit array to a floating-point number.
|
95
|
-
|
96
|
-
Returns:
|
97
|
-
float: The floating-point number represented by the bit array.
|
98
|
-
Raises:
|
99
|
-
AssertionError: If the bit array is not 64 bits long.
|
100
|
-
"""
|
101
|
-
assert len(self._bits) == 64, "Bit array must be 64 bits long."
|
102
|
-
|
103
|
-
byte_values = bytearray()
|
104
|
-
for i in range(0, 64, 8):
|
105
|
-
byte = 0
|
106
|
-
for j in range(8):
|
107
|
-
if self._bits[i + j]:
|
108
|
-
byte |= 1 << (7 - j)
|
109
|
-
byte_values.append(byte)
|
110
|
-
# Unpack as double precision (64 bits)
|
111
|
-
return struct.unpack("!d", bytes(byte_values))[0] # type: ignore
|
112
|
-
|
113
|
-
def to_int(self) -> int:
|
114
|
-
"""Convert the bit array to an unsigned integer.
|
115
|
-
|
116
|
-
Returns:
|
117
|
-
int: The integer represented by the bit array.
|
118
|
-
"""
|
119
|
-
return sum((1 << i) for i, bit in enumerate(reversed(self._bits)) if bit)
|
120
|
-
|
121
|
-
def to_signed_int(self) -> int:
|
122
|
-
"""Convert a bit array into a signed integer using off-set binary
|
123
|
-
representation.
|
124
|
-
|
125
|
-
Returns:
|
126
|
-
int: The signed integer represented by the bit array.
|
127
|
-
Raises:
|
128
|
-
AssertionError: If the bit array is empty.
|
129
|
-
"""
|
130
|
-
assert len(self._bits) > 0, "Bit array must not be empty."
|
131
|
-
|
132
|
-
int_value = self.to_int()
|
133
|
-
# Half of the maximum value
|
134
|
-
bias = 1 << (len(self._bits) - 1)
|
135
|
-
# If the sign bit is set, subtract the bias
|
136
|
-
return int_value - bias
|
137
|
-
|
138
|
-
def shift(self, shift_amount: int, fill: bool = False) -> BitArray:
|
139
|
-
"""Shift the bit array left or right by a specified number of bits.
|
140
|
-
|
141
|
-
This function shifts the bits in the array, filling in new bits with the
|
142
|
-
specified fill value.
|
143
|
-
If the value is positive, it shifts left; if negative, it shifts right.
|
144
|
-
Fills the new bits with the specified fill value (default is False).
|
145
|
-
|
146
|
-
Args:
|
147
|
-
shift_amount (int): The number of bits to shift. Positive for left shift,
|
148
|
-
negative for right shift.
|
149
|
-
fill (bool): The value to fill in the new bits created by the shift.
|
150
|
-
Defaults to False.
|
151
|
-
Returns:
|
152
|
-
BitArray: A new BitArray with the bits shifted and filled.
|
153
|
-
"""
|
154
|
-
if shift_amount == 0:
|
155
|
-
return self.copy()
|
156
|
-
if abs(shift_amount) > len(self._bits):
|
157
|
-
new_bits = [fill] * len(self._bits)
|
158
|
-
elif shift_amount > 0:
|
159
|
-
new_bits = [fill] * shift_amount + self._bits[:-shift_amount]
|
160
|
-
else:
|
161
|
-
new_bits = self._bits[-shift_amount:] + [fill] * (-shift_amount)
|
162
|
-
return BitArray(new_bits)
|
163
|
-
|
164
|
-
def copy(self) -> BitArray:
|
165
|
-
"""Create a copy of the bit array.
|
166
|
-
|
167
|
-
Returns:
|
168
|
-
BitArray: A new BitArray with the same bits.
|
169
|
-
"""
|
170
|
-
return BitArray(self._bits.copy())
|
171
|
-
|
172
|
-
def __len__(self) -> int:
|
173
|
-
"""Return the length of the bit array."""
|
174
|
-
return len(self._bits)
|
175
|
-
|
176
|
-
@overload
|
177
|
-
def __getitem__(self, index: int) -> bool: ...
|
178
|
-
@overload
|
179
|
-
def __getitem__(self, index: slice) -> BitArray: ...
|
180
|
-
|
181
|
-
def __getitem__(self, index: int | slice) -> bool | BitArray:
|
182
|
-
"""Get an item or slice from the bit array."""
|
183
|
-
if isinstance(index, slice):
|
184
|
-
return BitArray(self._bits[index])
|
185
|
-
return self._bits[index]
|
186
|
-
|
187
|
-
@overload
|
188
|
-
def __setitem__(self, index: int, value: bool) -> None: ...
|
189
|
-
@overload
|
190
|
-
def __setitem__(self, index: slice, value: BitArray | list[bool]) -> None: ...
|
191
|
-
|
192
|
-
def __setitem__(
|
193
|
-
self, index: int | slice, value: bool | list[bool] | BitArray
|
194
|
-
) -> None:
|
195
|
-
"""Set an item or slice in the bit array."""
|
196
|
-
if isinstance(index, slice):
|
197
|
-
if isinstance(value, BitArray):
|
198
|
-
self._bits[index] = value._bits
|
199
|
-
elif isinstance(value, list):
|
200
|
-
self._bits[index] = value
|
201
|
-
else:
|
202
|
-
raise TypeError("Cannot assign a single bool to a slice")
|
203
|
-
return
|
204
|
-
if isinstance(value, bool):
|
205
|
-
self._bits[index] = value
|
206
|
-
else:
|
207
|
-
raise TypeError("Cannot assign a list or BitArray to a single index")
|
208
|
-
|
209
|
-
def __iter__(self) -> Iterator[bool]:
|
210
|
-
"""Iterate over the bits in the array."""
|
211
|
-
return iter(self._bits)
|
212
|
-
|
213
|
-
def __add__(self, other: BitArray | list[bool]) -> BitArray:
|
214
|
-
"""Concatenate two bit arrays."""
|
215
|
-
if isinstance(other, BitArray):
|
216
|
-
return BitArray(self._bits + other._bits)
|
217
|
-
return BitArray(self._bits + other)
|
218
|
-
|
219
|
-
def __radd__(self, other: list[bool]) -> BitArray:
|
220
|
-
"""Reverse concatenation with a list."""
|
221
|
-
return BitArray(other + self._bits)
|
222
|
-
|
223
|
-
def __eq__(self, other: object) -> bool:
|
224
|
-
"""Check equality with another BitArray or list."""
|
225
|
-
if isinstance(other, BitArray):
|
226
|
-
return self._bits == other._bits
|
227
|
-
if isinstance(other, list):
|
228
|
-
return self._bits == other
|
229
|
-
return False
|
230
|
-
|
231
|
-
def __bool__(self) -> bool:
|
232
|
-
"""Return True if any bit is set."""
|
233
|
-
return any(self._bits)
|
234
|
-
|
235
|
-
def __repr__(self) -> str:
|
236
|
-
"""Return a string representation of the BitArray."""
|
237
|
-
return f"BitArray({self._bits})"
|
238
|
-
|
239
|
-
def __str__(self) -> str:
|
240
|
-
"""Return a string representation of the bits."""
|
241
|
-
return "".join("1" if bit else "0" for bit in self._bits)
|
242
|
-
|
243
|
-
def any(self) -> bool:
|
244
|
-
"""Return True if any bit is set to True."""
|
245
|
-
return any(self._bits)
|
246
|
-
|
247
|
-
def all(self) -> bool:
|
248
|
-
"""Return True if all bits are set to True."""
|
249
|
-
return all(self._bits)
|
250
|
-
|
251
|
-
def count(self, value: bool = True) -> int:
|
252
|
-
"""Count the number of bits set to the specified value."""
|
253
|
-
return self._bits.count(value)
|
254
|
-
|
255
|
-
def reverse(self) -> BitArray:
|
256
|
-
"""Return a new BitArray with the bits in reverse order."""
|
257
|
-
return BitArray(self._bits[::-1])
|