flexfloat 0.1.3__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/core.py CHANGED
@@ -1,11 +1,25 @@
1
- """Core FlexFloat class implementation."""
1
+ """Core FlexFloat class implementation.
2
+
3
+ This module defines the FlexFloat class, which represents a floating-point number with a
4
+ growable exponent and a fixed-size fraction. The class is designed for arbitrary
5
+ precision floating-point arithmetic, supporting very large or small values by
6
+ dynamically adjusting the exponent size.
7
+
8
+ Example:
9
+ from flexfloat import FlexFloat
10
+ a = FlexFloat(3.14, exponent_length=10, fraction_length=20)
11
+ b = FlexFloat(2.71, exponent_length=10, fraction_length=20)
12
+ c = a + b
13
+ print(c)
14
+ # Output: FlexFloat(...)
15
+ """
2
16
 
3
17
  from __future__ import annotations
4
18
 
5
19
  import math
6
- from typing import ClassVar, Final
20
+ from typing import ClassVar, Final, Type
7
21
 
8
- from .bitarray import BitArray, BitArrayType
22
+ from .bitarray import BitArray, ListBoolBitArray
9
23
  from .types import Number
10
24
 
11
25
  LOG10_2: Final[float] = math.log10(2)
@@ -29,6 +43,26 @@ class FlexFloat:
29
43
  """
30
44
 
31
45
  e: ClassVar[FlexFloat]
46
+ """The mathematical constant e as a FlexFloat instance."""
47
+ _bitarray_implementation: ClassVar[Type[BitArray]] = ListBoolBitArray
48
+ """The BitArray implementation class used for all FlexFloat instances."""
49
+
50
+ sign: bool
51
+ """The sign of the number (True for negative, False for positive)."""
52
+ exponent: BitArray
53
+ """A growable bit array representing the exponent (uses off-set binary
54
+ representation)."""
55
+ fraction: BitArray
56
+ """A fixed-size bit array representing the fraction (mantissa) of the number."""
57
+
58
+ @classmethod
59
+ def set_bitarray_implementation(cls, implementation: Type[BitArray]) -> None:
60
+ """Set the BitArray implementation to use for all FlexFloat instances.
61
+
62
+ Args:
63
+ implementation (Type[BitArray]): The BitArray implementation class to use.
64
+ """
65
+ cls._bitarray_implementation = implementation
32
66
 
33
67
  def __init__(
34
68
  self,
@@ -36,49 +70,70 @@ class FlexFloat:
36
70
  exponent: BitArray | None = None,
37
71
  fraction: BitArray | None = None,
38
72
  ):
39
- """Initialize a FlexFloat instance.
73
+ """Initializes a FlexFloat instance.
74
+
75
+ BitArrays are expected to be LSB-first (least significant bit at index 0,
76
+ increasing to MSB).
40
77
 
41
78
  Args:
42
- sign (bool): The sign of the number (True for negative, False for positive).
43
- exponent (BitArray | None): The exponent bit array (If None, represents 0).
44
- fraction (BitArray | None): The fraction bit array (If None, represents 0).
79
+ sign (bool, optional): The sign of the number (True for negative, False for
80
+ positive). Defaults to False.
81
+ exponent (BitArray | None, optional): The exponent bit array. If None,
82
+ represents 0. Defaults to None.
83
+ fraction (BitArray | None, optional): The fraction bit array. If None,
84
+ represents 0. Defaults to None.
45
85
  """
46
86
  self.sign = sign
47
- self.exponent = exponent if exponent is not None else BitArrayType.zeros(11)
48
- self.fraction = fraction if fraction is not None else BitArrayType.zeros(52)
87
+ self.exponent = (
88
+ exponent
89
+ if exponent is not None
90
+ else self._bitarray_implementation.zeros(11)
91
+ )
92
+ self.fraction = (
93
+ fraction
94
+ if fraction is not None
95
+ else self._bitarray_implementation.zeros(52)
96
+ )
49
97
 
50
98
  @classmethod
51
99
  def from_float(cls, value: Number) -> FlexFloat:
52
- """Create a FlexFloat instance from a number.
100
+ """Creates a FlexFloat instance from a number.
53
101
 
54
102
  Args:
55
103
  value (Number): The number to convert to FlexFloat.
104
+
56
105
  Returns:
57
106
  FlexFloat: A new FlexFloat instance representing the number.
58
107
  """
59
108
  value = float(value)
60
- bits = BitArrayType.from_float(value)
109
+ bits = cls._bitarray_implementation.from_float(value)
61
110
 
62
- return cls(sign=bits[0], exponent=bits[1:12], fraction=bits[12:64])
111
+ return cls(sign=bits[63], exponent=bits[52:63], fraction=bits[:52])
63
112
 
64
113
  def to_float(self) -> float:
65
- """Convert the FlexFloat instance back to a 64-bit float.
114
+ """Converts the FlexFloat instance back to a 64-bit float.
66
115
 
67
116
  If float is bigger than 64 bits, it will truncate the value to fit.
68
117
 
69
118
  Returns:
70
119
  float: The floating-point number represented by the FlexFloat instance.
120
+
71
121
  Raises:
72
- ValueError: If the exponent or fraction lengths are not as expected.
122
+ ValueError: If the FlexFloat does not have standard 64-bit exponent and
123
+ fraction.
73
124
  """
74
125
  if len(self.exponent) < 11 or len(self.fraction) < 52:
75
126
  raise ValueError("Must be a standard 64-bit FlexFloat")
76
127
 
77
- bits = BitArrayType([self.sign]) + self.exponent[:11] + self.fraction[:52]
128
+ bits = (
129
+ self.fraction[:52]
130
+ + self.exponent[:11]
131
+ + self._bitarray_implementation.from_bits([self.sign])
132
+ )
78
133
  return bits.to_float()
79
134
 
80
135
  def __repr__(self) -> str:
81
- """Return a string representation of the FlexFloat instance.
136
+ """Returns a string representation of the FlexFloat instance.
82
137
 
83
138
  Returns:
84
139
  str: A string representation of the FlexFloat instance.
@@ -91,7 +146,7 @@ class FlexFloat:
91
146
  )
92
147
 
93
148
  def pretty(self) -> str:
94
- """Return an easier to read string representation of the FlexFloat instance.
149
+ """Returns an easier to read string representation of the FlexFloat instance.
95
150
  Mainly converts the exponent and fraction to integers for readability.
96
151
 
97
152
  Returns:
@@ -104,54 +159,52 @@ class FlexFloat:
104
159
 
105
160
  @classmethod
106
161
  def nan(cls) -> FlexFloat:
107
- """Create a FlexFloat instance representing NaN (Not a Number).
162
+ """Creates a FlexFloat instance representing NaN (Not a Number).
108
163
 
109
164
  Returns:
110
165
  FlexFloat: A new FlexFloat instance representing NaN.
111
166
  """
112
- exponent = BitArrayType.ones(11)
113
- fraction = BitArrayType.ones(52)
167
+ exponent = cls._bitarray_implementation.ones(11)
168
+ fraction = cls._bitarray_implementation.ones(52)
114
169
  return cls(sign=True, exponent=exponent, fraction=fraction)
115
170
 
116
171
  @classmethod
117
172
  def infinity(cls, sign: bool = False) -> FlexFloat:
118
- """Create a FlexFloat instance representing Infinity.
173
+ """Creates a FlexFloat instance representing Infinity.
119
174
 
120
175
  Args:
121
- sign (bool): Indicates if the infinity is negative.
176
+ sign (bool, optional): Indicates if the infinity is negative. Defaults to
177
+ False.
178
+
122
179
  Returns:
123
180
  FlexFloat: A new FlexFloat instance representing Infinity.
124
181
  """
125
- exponent = BitArrayType.ones(11)
126
- fraction = BitArrayType.zeros(52)
182
+ exponent = cls._bitarray_implementation.ones(11)
183
+ fraction = cls._bitarray_implementation.zeros(52)
127
184
  return cls(sign=sign, exponent=exponent, fraction=fraction)
128
185
 
129
186
  @classmethod
130
187
  def zero(cls) -> FlexFloat:
131
- """Create a FlexFloat instance representing zero.
188
+ """Creates a FlexFloat instance representing zero.
132
189
 
133
190
  Returns:
134
191
  FlexFloat: A new FlexFloat instance representing zero.
135
192
  """
136
- exponent = BitArrayType.zeros(11)
137
- fraction = BitArrayType.zeros(52)
193
+ exponent = cls._bitarray_implementation.zeros(11)
194
+ fraction = cls._bitarray_implementation.zeros(52)
138
195
  return cls(sign=False, exponent=exponent, fraction=fraction)
139
196
 
140
197
  def _is_special_exponent(self) -> bool:
141
- """Check if the exponent represents a special value (NaN or Infinity).
198
+ """Checks if the exponent represents a special value (NaN or Infinity).
142
199
 
143
200
  Returns:
144
201
  bool: True if the exponent is at its maximum value, False otherwise.
145
202
  """
146
- # In IEEE 754, special values have all exponent bits set to 1
147
- # This corresponds to the maximum value in the unsigned representation
148
- # For signed offset binary, the maximum value is 2^(n-1) - 1
149
- # where n is the number of bits
150
203
  max_signed_value = (1 << (len(self.exponent) - 1)) - 1
151
204
  return self.exponent.to_signed_int() == max_signed_value
152
205
 
153
206
  def is_nan(self) -> bool:
154
- """Check if the FlexFloat instance represents NaN (Not a Number).
207
+ """Checks if the FlexFloat instance represents NaN (Not a Number).
155
208
 
156
209
  Returns:
157
210
  bool: True if the FlexFloat instance is NaN, False otherwise.
@@ -159,7 +212,7 @@ class FlexFloat:
159
212
  return self._is_special_exponent() and any(self.fraction)
160
213
 
161
214
  def is_infinity(self) -> bool:
162
- """Check if the FlexFloat instance represents Infinity.
215
+ """Checks if the FlexFloat instance represents Infinity.
163
216
 
164
217
  Returns:
165
218
  bool: True if the FlexFloat instance is Infinity, False otherwise.
@@ -167,7 +220,7 @@ class FlexFloat:
167
220
  return self._is_special_exponent() and not any(self.fraction)
168
221
 
169
222
  def is_zero(self) -> bool:
170
- """Check if the FlexFloat instance represents zero.
223
+ """Checks if the FlexFloat instance represents zero.
171
224
 
172
225
  Returns:
173
226
  bool: True if the FlexFloat instance is zero, False otherwise.
@@ -175,7 +228,7 @@ class FlexFloat:
175
228
  return not any(self.exponent) and not any(self.fraction)
176
229
 
177
230
  def copy(self) -> FlexFloat:
178
- """Create a copy of the FlexFloat instance.
231
+ """Creates a copy of the FlexFloat instance.
179
232
 
180
233
  Returns:
181
234
  FlexFloat: A new FlexFloat instance with the same data as the original.
@@ -185,12 +238,13 @@ class FlexFloat:
185
238
  )
186
239
 
187
240
  def __str__(self) -> str:
188
- """Float representation of the FlexFloat using a generic algorithm.
241
+ """Returns a float representation of the FlexFloat using a generic algorithm.
189
242
 
190
- This implementation doesn't rely on Python's float conversion and instead
191
- implements the formatting logic directly, making it work for any exponent size.
243
+ Currently, it only operates in one format: scientific notation with 5 decimal
244
+ places.
192
245
 
193
- Currently, it only operates in scientific notation with 5 decimal places.
246
+ Returns:
247
+ str: The string representation in scientific notation.
194
248
  """
195
249
  sign_str = "-" if self.sign else ""
196
250
  # Handle special cases first
@@ -208,7 +262,7 @@ class FlexFloat:
208
262
  # Convert fraction to decimal value between 1 and 2
209
263
  # (starting with 1.0 for the implicit leading bit)
210
264
  mantissa = 1.0
211
- for i, bit in enumerate(self.fraction):
265
+ for i, bit in enumerate(reversed(self.fraction)):
212
266
  if bit:
213
267
  mantissa += 1.0 / (1 << (i + 1))
214
268
 
@@ -235,7 +289,11 @@ class FlexFloat:
235
289
  return f"{sign_str}{normalized_mantissa:.5f}e{decimal_exponent:+03d}"
236
290
 
237
291
  def __neg__(self) -> FlexFloat:
238
- """Negate the FlexFloat instance."""
292
+ """Negates the FlexFloat instance.
293
+
294
+ Returns:
295
+ FlexFloat: A new FlexFloat instance with the sign flipped.
296
+ """
239
297
  return FlexFloat(
240
298
  sign=not self.sign,
241
299
  exponent=self.exponent.copy(),
@@ -244,11 +302,12 @@ class FlexFloat:
244
302
 
245
303
  @staticmethod
246
304
  def _grow_exponent(exponent: int, exponent_length: int) -> int:
247
- """Grow the exponent if it exceeds the maximum value for the current length.
305
+ """Grows the exponent if it exceeds the maximum value for the current length.
248
306
 
249
307
  Args:
250
308
  exponent (int): The current exponent value.
251
309
  exponent_length (int): The current length of the exponent in bits.
310
+
252
311
  Returns:
253
312
  int: The new exponent length if it needs to be grown, otherwise the same
254
313
  length.
@@ -265,12 +324,16 @@ class FlexFloat:
265
324
  return exponent_length
266
325
 
267
326
  def __add__(self, other: FlexFloat | Number) -> FlexFloat:
268
- """Add two FlexFloat instances together.
327
+ """Adds two FlexFloat instances together.
269
328
 
270
329
  Args:
271
- other (FlexFloat | float | int): The other FlexFloat instance to add.
330
+ other (FlexFloat | Number): The other FlexFloat instance to add.
331
+
272
332
  Returns:
273
333
  FlexFloat: A new FlexFloat instance representing the sum.
334
+
335
+ Raises:
336
+ TypeError: If other is not a FlexFloat or numeric type.
274
337
  """
275
338
  if isinstance(other, Number):
276
339
  other = FlexFloat.from_float(other)
@@ -312,9 +375,9 @@ class FlexFloat:
312
375
  exponent_self = self.exponent.to_signed_int() + 1
313
376
  exponent_other = other.exponent.to_signed_int() + 1
314
377
 
315
- # Step 2: Prepend leading 1 to form the mantissa
316
- mantissa_self = [True] + self.fraction
317
- mantissa_other = [True] + other.fraction
378
+ # Step 2: Append the implicit leading 1 to form the mantissa
379
+ mantissa_self = self.fraction + [True]
380
+ mantissa_other = other.fraction + [True]
318
381
 
319
382
  # Step 3: Compare exponents (self is always larger or equal)
320
383
  if exponent_self < exponent_other:
@@ -335,9 +398,10 @@ class FlexFloat:
335
398
  f"got {len(mantissa_other)} bits."
336
399
  )
337
400
 
338
- mantissa_result = BitArrayType.zeros(53) # 1 leading bit + 52 fraction bits
401
+ # 1 leading bit + 52 fraction bits
402
+ mantissa_result = self._bitarray_implementation.zeros(53)
339
403
  carry = False
340
- for i in range(52, -1, -1):
404
+ for i in range(53):
341
405
  total = mantissa_self[i] + mantissa_other[i] + carry
342
406
  mantissa_result[i] = total % 2 == 1
343
407
  carry = total > 1
@@ -355,22 +419,26 @@ class FlexFloat:
355
419
  exponent_self - (1 << (exp_result_length - 1)) < 2
356
420
  ), "Exponent growth should not exceed 1 bit."
357
421
 
358
- exponent_result = BitArrayType.from_signed_int(
422
+ exponent_result = self._bitarray_implementation.from_signed_int(
359
423
  exponent_self - 1, exp_result_length
360
424
  )
361
425
  return FlexFloat(
362
426
  sign=self.sign,
363
427
  exponent=exponent_result,
364
- fraction=mantissa_result[1:], # Exclude leading bit
428
+ fraction=mantissa_result[:-1], # Exclude leading bit
365
429
  )
366
430
 
367
431
  def __sub__(self, other: FlexFloat | Number) -> FlexFloat:
368
- """Subtract one FlexFloat instance from another.
432
+ """Subtracts one FlexFloat instance from another.
369
433
 
370
434
  Args:
371
- other (FlexFloat | float | int): The FlexFloat instance to subtract.
435
+ other (FlexFloat | Number): The FlexFloat instance to subtract.
436
+
372
437
  Returns:
373
438
  FlexFloat: A new FlexFloat instance representing the difference.
439
+
440
+ Raises:
441
+ TypeError: If other is not a FlexFloat or numeric type.
374
442
  """
375
443
  if isinstance(other, Number):
376
444
  other = FlexFloat.from_float(other)
@@ -417,9 +485,9 @@ class FlexFloat:
417
485
  exponent_self = self.exponent.to_signed_int() + 1
418
486
  exponent_other = other.exponent.to_signed_int() + 1
419
487
 
420
- # Step 2: Prepend leading 1 to form the mantissa
421
- mantissa_self = [True] + self.fraction
422
- mantissa_other = [True] + other.fraction
488
+ # Step 2: Append the implicit leading 1 to form the mantissa
489
+ mantissa_self = self.fraction + [True]
490
+ mantissa_other = other.fraction + [True]
423
491
 
424
492
  # Step 3: Align mantissas by shifting the smaller exponent
425
493
  result_sign = self.sign
@@ -455,9 +523,9 @@ class FlexFloat:
455
523
  f"got {len(smaller_mantissa)} bits."
456
524
  )
457
525
 
458
- mantissa_result = BitArrayType.zeros(53)
526
+ mantissa_result = self._bitarray_implementation.zeros(53)
459
527
  borrow = False
460
- for i in range(52, -1, -1):
528
+ for i in range(53):
461
529
  diff = int(larger_mantissa[i]) - int(smaller_mantissa[i]) - int(borrow)
462
530
 
463
531
  mantissa_result[i] = diff % 2 == 1
@@ -468,7 +536,8 @@ class FlexFloat:
468
536
  # Step 6: Normalize mantissa and adjust exponent if necessary
469
537
  # Find the first 1 bit (leading bit might have been canceled out)
470
538
  leading_zero_count = next(
471
- (i for i, bit in enumerate(mantissa_result) if bit), len(mantissa_result)
539
+ (i for i, bit in enumerate(reversed(mantissa_result)) if bit),
540
+ len(mantissa_result),
472
541
  )
473
542
 
474
543
  # Handle case where result becomes zero or denormalized
@@ -483,23 +552,27 @@ class FlexFloat:
483
552
  # Step 7: Grow exponent if necessary (handle underflow)
484
553
  exp_result_length = self._grow_exponent(result_exponent, len(self.exponent))
485
554
 
486
- exp_result = BitArrayType.from_signed_int(
555
+ exp_result = self._bitarray_implementation.from_signed_int(
487
556
  result_exponent - 1, exp_result_length
488
557
  )
489
558
 
490
559
  return FlexFloat(
491
560
  sign=result_sign,
492
561
  exponent=exp_result,
493
- fraction=mantissa_result[1:], # Exclude leading bit
562
+ fraction=mantissa_result[:-1], # Exclude leading bit
494
563
  )
495
564
 
496
565
  def __mul__(self, other: FlexFloat | Number) -> FlexFloat:
497
- """Multiply two FlexFloat instances together.
566
+ """Multiplies two FlexFloat instances together.
498
567
 
499
568
  Args:
500
- other (FlexFloat | float | int): The other FlexFloat instance to multiply.
569
+ other (FlexFloat | Number): The other FlexFloat instance to multiply.
570
+
501
571
  Returns:
502
572
  FlexFloat: A new FlexFloat instance representing the product.
573
+
574
+ Raises:
575
+ TypeError: If other is not a FlexFloat or numeric type.
503
576
  """
504
577
  if isinstance(other, Number):
505
578
  other = FlexFloat.from_float(other)
@@ -543,9 +616,9 @@ class FlexFloat:
543
616
  result_exponent = exponent_self + exponent_other
544
617
 
545
618
  # Step 4: Multiply mantissas
546
- # Prepend leading 1 to form the mantissa (1.fraction)
547
- mantissa_self = [True] + self.fraction
548
- mantissa_other = [True] + other.fraction
619
+ # Append the implicit leading 1 to form the mantissa
620
+ mantissa_self = self.fraction + [True]
621
+ mantissa_other = other.fraction + [True]
549
622
 
550
623
  # Convert mantissas to integers for multiplication
551
624
  mantissa_self_int = mantissa_self.to_int()
@@ -559,8 +632,8 @@ class FlexFloat:
559
632
  if product == 0:
560
633
  return FlexFloat.zero()
561
634
 
562
- product_bits = BitArrayType.zeros(106)
563
- for i in range(105, -1, -1):
635
+ product_bits = self._bitarray_implementation.zeros(106)
636
+ for i in range(106):
564
637
  product_bits[i] = product & 1 == 1
565
638
  product >>= 1
566
639
  if product <= 0:
@@ -568,22 +641,28 @@ class FlexFloat:
568
641
 
569
642
  # Step 5: Normalize mantissa and adjust exponent if necessary
570
643
  # Find the position of the most significant bit
571
- msb_position = next((i for i, bit in enumerate(product_bits) if bit), None)
644
+ msb_position = next(
645
+ (i for i, bit in enumerate(reversed(product_bits)) if bit), None
646
+ )
572
647
 
573
648
  assert msb_position is not None, "Product should not be zero here."
574
649
 
575
- # The mantissa multiplication gives us a result with 2 integer bits
650
+ # The mantissa multiplication gives us a result with a 2 integer bits
576
651
  # We need to normalize to have exactly 1 integer bit
577
652
  # If MSB is at position 0, we have a 2-bit integer part (11.xxxxx)
578
653
  # If MSB is at position 1, we have a 1-bit integer part (1.xxxxx)
654
+ # Mantissa goes from LSB to MSB, so we need to adjust the exponent accordingly
579
655
  if msb_position == 0:
580
656
  result_exponent += 1
581
- normalized_mantissa = product_bits[msb_position : msb_position + 53]
657
+
658
+ # Extract the normalized mantissa
659
+ lsb_position = 53 - msb_position
660
+ normalized_mantissa = product_bits[lsb_position : lsb_position + 53]
582
661
 
583
662
  # Pad with zeros if we don't have enough bits
584
663
  missing_bits = 53 - len(normalized_mantissa)
585
664
  if missing_bits > 0:
586
- normalized_mantissa += [False] * missing_bits
665
+ normalized_mantissa = normalized_mantissa.shift(-missing_bits, fill=False)
587
666
 
588
667
  # Step 6: Grow exponent if necessary to accommodate the result
589
668
  exp_result_length = max(len(self.exponent), len(other.exponent))
@@ -591,33 +670,38 @@ class FlexFloat:
591
670
  # Check if we need to grow the exponent to accommodate the result
592
671
  exp_result_length = self._grow_exponent(result_exponent, exp_result_length)
593
672
 
594
- exp_result = BitArrayType.from_signed_int(
673
+ exp_result = self._bitarray_implementation.from_signed_int(
595
674
  result_exponent - 1, exp_result_length
596
675
  )
597
676
 
598
677
  return FlexFloat(
599
678
  sign=result_sign,
600
679
  exponent=exp_result,
601
- fraction=normalized_mantissa[1:], # Exclude leading bit
680
+ fraction=normalized_mantissa[:-1], # Exclude leading bit
602
681
  )
603
682
 
604
683
  def __rmul__(self, other: Number) -> FlexFloat:
605
684
  """Right-hand multiplication for Number types.
606
685
 
607
686
  Args:
608
- other (float | int): The number to multiply with this FlexFloat.
687
+ other (Number): The number to multiply with this FlexFloat.
688
+
609
689
  Returns:
610
690
  FlexFloat: A new FlexFloat instance representing the product.
611
691
  """
612
- return self * other
692
+ return self * FlexFloat.from_float(other)
613
693
 
614
694
  def __truediv__(self, other: FlexFloat | Number) -> FlexFloat:
615
- """Divide this FlexFloat by another FlexFloat or number.
695
+ """Divides this FlexFloat by another FlexFloat or number.
616
696
 
617
697
  Args:
618
- other (FlexFloat | float | int): The divisor.
698
+ other (FlexFloat | Number): The divisor.
699
+
619
700
  Returns:
620
701
  FlexFloat: A new FlexFloat instance representing the quotient.
702
+
703
+ Raises:
704
+ TypeError: If other is not a FlexFloat or numeric type.
621
705
  """
622
706
  if isinstance(other, Number):
623
707
  other = FlexFloat.from_float(other)
@@ -670,9 +754,9 @@ class FlexFloat:
670
754
  result_exponent = exponent_self - exponent_other
671
755
 
672
756
  # Step 4: Divide mantissas
673
- # Prepend leading 1 to form the mantissa (1.fraction)
674
- mantissa_self = [True] + self.fraction
675
- mantissa_other = [True] + other.fraction
757
+ # Append the implicit leading 1 to form the mantissa
758
+ mantissa_self = self.fraction + [True]
759
+ mantissa_other = other.fraction + [True]
676
760
 
677
761
  # Convert mantissas to integers for division
678
762
  mantissa_self_int = mantissa_self.to_int()
@@ -691,26 +775,32 @@ class FlexFloat:
691
775
  return FlexFloat.zero()
692
776
 
693
777
  # Convert quotient to BitArray for easier bit manipulation
694
- quotient_bitarray = BitArrayType.zeros(64) # Use a fixed size for consistency
778
+ # Use a fixed size for consistency
779
+ quotient_bitarray = self._bitarray_implementation.zeros(64)
695
780
  temp_quotient = quotient
696
- bit_pos = 63
697
- while temp_quotient > 0 and bit_pos >= 0:
781
+ bit_pos = 0
782
+ while temp_quotient > 0 and bit_pos < 64:
698
783
  quotient_bitarray[bit_pos] = (temp_quotient & 1) == 1
699
784
  temp_quotient >>= 1
700
- bit_pos -= 1
785
+ bit_pos += 1
701
786
 
702
787
  # Step 5: Normalize mantissa and adjust exponent if necessary
703
788
  # Find the position of the most significant bit (first 1)
704
- msb_pos = next((i for i, bit in enumerate(quotient_bitarray) if bit), None)
789
+ msb_pos = next(
790
+ (i for i, bit in enumerate(reversed(quotient_bitarray)) if bit), None
791
+ )
705
792
 
706
793
  if msb_pos is None:
707
794
  return FlexFloat.zero()
708
795
 
709
796
  # Extract exactly 53 bits starting from the MSB (1 integer + 52 fraction)
710
- normalized_mantissa = quotient_bitarray[msb_pos : msb_pos + 53]
711
- normalized_mantissa = normalized_mantissa.shift(
712
- 53 - len(normalized_mantissa), fill=False
713
- )
797
+ lsb_pos = 11 - msb_pos
798
+ normalized_mantissa = quotient_bitarray[lsb_pos : lsb_pos + 53]
799
+
800
+ # If we don't have enough bits, pad with zeros
801
+ missing_bits = 53 - len(normalized_mantissa)
802
+ if missing_bits > 0:
803
+ normalized_mantissa = normalized_mantissa.shift(-missing_bits, fill=False)
714
804
 
715
805
  # Step 6: Grow exponent if necessary to accommodate the result
716
806
  exp_result_length = max(len(self.exponent), len(other.exponent))
@@ -718,32 +808,33 @@ class FlexFloat:
718
808
  # Check if we need to grow the exponent to accommodate the result
719
809
  exp_result_length = self._grow_exponent(result_exponent, exp_result_length)
720
810
 
721
- exp_result = BitArrayType.from_signed_int(
811
+ exp_result = self._bitarray_implementation.from_signed_int(
722
812
  result_exponent - 1, exp_result_length
723
813
  )
724
814
 
725
815
  return FlexFloat(
726
816
  sign=result_sign,
727
817
  exponent=exp_result,
728
- fraction=normalized_mantissa[1:], # Exclude leading bit
818
+ fraction=normalized_mantissa[:-1], # Exclude leading bit
729
819
  )
730
820
 
731
821
  def __rtruediv__(self, other: Number) -> FlexFloat:
732
822
  """Right-hand division for Number types.
733
823
 
734
824
  Args:
735
- other (float | int): The number to divide by this FlexFloat.
825
+ other (Number): The number to divide by this FlexFloat.
826
+
736
827
  Returns:
737
828
  FlexFloat: A new FlexFloat instance representing the quotient.
738
829
  """
739
830
  return FlexFloat.from_float(other) / self
740
831
 
741
832
  def __abs__(self) -> FlexFloat:
742
- """Return the absolute value of the FlexFloat instance.
833
+ """Returns the absolute value of the FlexFloat instance.
743
834
 
744
835
  Returns:
745
- FlexFloat: A new FlexFloat instance with the same exponent and fraction,
746
- but with the sign set to False (positive).
836
+ FlexFloat: A new FlexFloat instance with the same exponent and fraction, but
837
+ with the sign set to False (positive).
747
838
  """
748
839
  return FlexFloat(
749
840
  sign=False,
@@ -752,31 +843,35 @@ class FlexFloat:
752
843
  )
753
844
 
754
845
  def abs(self) -> FlexFloat:
755
- """Calculate the absolute value of the FlexFloat instance.
846
+ """Calculates the absolute value of the FlexFloat instance.
756
847
 
757
848
  Returns:
758
- FlexFloat: A new FlexFloat instance with the same exponent and fraction,
759
- but with the sign set to False (positive).
849
+ FlexFloat: A new FlexFloat instance with the same exponent and fraction, but
850
+ with the sign set to False (positive).
760
851
  """
761
852
  return abs(self)
762
853
 
763
854
  def exp(self) -> FlexFloat:
764
- """Calculate the exponential of the FlexFloat instance.
855
+ """Calculates the exponential of the FlexFloat instance.
765
856
 
766
857
  Returns:
767
- FlexFloat: A new FlexFloat instance representing e raised to the power
768
- of this instance.
858
+ FlexFloat: A new FlexFloat instance representing e raised to the power of
859
+ this instance.
769
860
  """
770
861
  # Use Python's math.exp for the base calculation
771
862
  return FlexFloat.e**self
772
863
 
773
864
  def __pow__(self, other: FlexFloat | Number) -> FlexFloat:
774
- """Power operation for FlexFloat instances.
865
+ """Raises this FlexFloat to the power of another FlexFloat or number.
775
866
 
776
867
  Args:
777
868
  other (FlexFloat | Number): The exponent.
869
+
778
870
  Returns:
779
871
  FlexFloat: A new FlexFloat instance representing the power.
872
+
873
+ Raises:
874
+ TypeError: If other is not a FlexFloat or numeric type.
780
875
  """
781
876
  if isinstance(other, Number):
782
877
  other = FlexFloat.from_float(other)
@@ -913,12 +1008,14 @@ class FlexFloat:
913
1008
  required_exp_bits = max(11, abs(estimated_exp).bit_length() + 2)
914
1009
 
915
1010
  # Create a small result with extended exponent
916
- small_exp = BitArrayType.from_signed_int(
1011
+ small_exp = self._bitarray_implementation.from_signed_int(
917
1012
  estimated_exp, required_exp_bits
918
1013
  )
919
1014
  # Use a normalized mantissa (leading 1 + some fraction bits)
920
1015
  result = FlexFloat(
921
- sign=False, exponent=small_exp, fraction=BitArrayType.ones(52)
1016
+ sign=False,
1017
+ exponent=small_exp,
1018
+ fraction=self._bitarray_implementation.ones(52),
922
1019
  )
923
1020
  else:
924
1021
  # Compute the power using Python's built-in pow
@@ -932,13 +1029,13 @@ class FlexFloat:
932
1029
  if log_result_estimate < -300: # Very small but not quite underflow
933
1030
  estimated_exp = int(log_result_estimate / LOG10_2)
934
1031
  required_exp_bits = max(11, abs(estimated_exp).bit_length() + 2)
935
- small_exp = BitArrayType.from_signed_int(
1032
+ small_exp = self._bitarray_implementation.from_signed_int(
936
1033
  estimated_exp, required_exp_bits
937
1034
  )
938
1035
  result = FlexFloat(
939
1036
  sign=False,
940
1037
  exponent=small_exp,
941
- fraction=BitArrayType.ones(52),
1038
+ fraction=self._bitarray_implementation.ones(52),
942
1039
  )
943
1040
  else:
944
1041
  return FlexFloat.zero()
@@ -974,19 +1071,23 @@ class FlexFloat:
974
1071
  # use arbitrary precision arithmetic
975
1072
  if estimated_exp_float > 0:
976
1073
  # Very large positive result
977
- large_exp = BitArrayType.from_signed_int(
1074
+ large_exp = self._bitarray_implementation.from_signed_int(
978
1075
  int(estimated_exp_float), required_exp_bits
979
1076
  )
980
1077
  result = FlexFloat(
981
- sign=False, exponent=large_exp, fraction=BitArrayType.ones(52)
1078
+ sign=False,
1079
+ exponent=large_exp,
1080
+ fraction=self._bitarray_implementation.ones(52),
982
1081
  )
983
1082
  else:
984
1083
  # Very small positive result
985
- small_exp = BitArrayType.from_signed_int(
1084
+ small_exp = self._bitarray_implementation.from_signed_int(
986
1085
  int(estimated_exp_float), required_exp_bits
987
1086
  )
988
1087
  result = FlexFloat(
989
- sign=False, exponent=small_exp, fraction=BitArrayType.ones(52)
1088
+ sign=False,
1089
+ exponent=small_exp,
1090
+ fraction=self._bitarray_implementation.ones(52),
990
1091
  )
991
1092
 
992
1093
  except (ValueError, OverflowError, ZeroDivisionError):
@@ -1003,7 +1104,8 @@ class FlexFloat:
1003
1104
  """Right-hand power operation for Number types.
1004
1105
 
1005
1106
  Args:
1006
- base (float | int): The base to raise to the power of this FlexFloat.
1107
+ base (Number): The base to raise to the power of this FlexFloat.
1108
+
1007
1109
  Returns:
1008
1110
  FlexFloat: A new FlexFloat instance representing the power.
1009
1111
  """