flexfloat 0.3.1__tar.gz → 0.4.0__tar.gz
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-0.3.1 → flexfloat-0.4.0}/.bumpversion.cfg +1 -1
- {flexfloat-0.3.1 → flexfloat-0.4.0}/PKG-INFO +1 -1
- {flexfloat-0.3.1 → flexfloat-0.4.0}/flexfloat/__init__.py +1 -1
- {flexfloat-0.3.1 → flexfloat-0.4.0}/flexfloat/core.py +67 -220
- {flexfloat-0.3.1 → flexfloat-0.4.0}/flexfloat/math.py +296 -7
- {flexfloat-0.3.1 → flexfloat-0.4.0}/flexfloat.egg-info/PKG-INFO +1 -1
- {flexfloat-0.3.1 → flexfloat-0.4.0}/pyproject.toml +1 -1
- {flexfloat-0.3.1 → flexfloat-0.4.0}/tests/test_addition.py +1 -1
- {flexfloat-0.3.1 → flexfloat-0.4.0}/tests/test_bigint_bitarray.py +0 -4
- {flexfloat-0.3.1 → flexfloat-0.4.0}/tests/test_bitarray_implementations.py +0 -1
- {flexfloat-0.3.1 → flexfloat-0.4.0}/tests/test_math.py +422 -30
- {flexfloat-0.3.1 → flexfloat-0.4.0}/tests/test_multiplication.py +2 -12
- {flexfloat-0.3.1 → flexfloat-0.4.0}/tests/test_power.py +5 -30
- {flexfloat-0.3.1 → flexfloat-0.4.0}/.github/workflows/build-check.yml +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/.github/workflows/docs.yml +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/.github/workflows/manual-release.yml +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/.github/workflows/pr-labeler.yml +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/.github/workflows/release.yml +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/.github/workflows/test.yml +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/.github/workflows/version-bump.yml +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/.github/workflows/version-check.yml +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/.gitignore +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/LICENSE +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/MANIFEST.in +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/README.md +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/docs/Makefile +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/docs/README.md +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/docs/make.bat +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/docs/source/_autosummary/flexfloat.BigIntBitArray.rst +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/docs/source/_autosummary/flexfloat.BitArray.rst +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/docs/source/_autosummary/flexfloat.FlexFloat.rst +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/docs/source/_autosummary/flexfloat.ListBoolBitArray.rst +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/docs/source/_autosummary/flexfloat.ListInt64BitArray.rst +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/docs/source/_autosummary/flexfloat.math.rst +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/docs/source/_static/custom.css +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/docs/source/_templates/autosummary/class.rst +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/docs/source/_templates/layout.html +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/docs/source/api/bitarray.rst +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/docs/source/api/core.rst +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/docs/source/api/math.rst +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/docs/source/api/types.rst +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/docs/source/conf.py +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/docs/source/examples/index.rst +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/docs/source/index.rst +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/docs/source/installation.rst +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/docs/source/quickstart.rst +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/docs/source/user_guide/concepts.rst +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/docs/source/user_guide/index.rst +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/flexfloat/bitarray/__init__.py +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/flexfloat/bitarray/bitarray.py +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/flexfloat/bitarray/bitarray_bigint.py +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/flexfloat/bitarray/bitarray_bool.py +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/flexfloat/bitarray/bitarray_int64.py +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/flexfloat/bitarray/bitarray_mixins.py +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/flexfloat/py.typed +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/flexfloat/types.py +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/flexfloat.egg-info/SOURCES.txt +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/flexfloat.egg-info/dependency_links.txt +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/flexfloat.egg-info/requires.txt +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/flexfloat.egg-info/top_level.txt +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/scripts/validate_cicd.py +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/scripts/version_manager.py +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/setup.cfg +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/setup.py +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/tests/__init__.py +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/tests/test_bitarray.py +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/tests/test_comparison.py +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/tests/test_conversions.py +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/tests/test_division.py +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/tests/test_flexfloat.py +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/tests/test_str_representation.py +0 -0
- {flexfloat-0.3.1 → flexfloat-0.4.0}/tests/test_subtraction.py +0 -0
|
@@ -192,15 +192,18 @@ class FlexFloat:
|
|
|
192
192
|
return cls(sign=sign, exponent=exponent, fraction=fraction)
|
|
193
193
|
|
|
194
194
|
@classmethod
|
|
195
|
-
def zero(cls) -> FlexFloat:
|
|
195
|
+
def zero(cls, sign: bool = False) -> FlexFloat:
|
|
196
196
|
"""Creates a FlexFloat instance representing zero.
|
|
197
197
|
|
|
198
|
+
Args:
|
|
199
|
+
sign (bool, optional): Indicates if the zero is negative. Defaults to False.
|
|
200
|
+
|
|
198
201
|
Returns:
|
|
199
202
|
FlexFloat: A new FlexFloat instance representing zero.
|
|
200
203
|
"""
|
|
201
204
|
exponent = cls._bitarray_implementation.zeros(11)
|
|
202
205
|
fraction = cls._bitarray_implementation.zeros(52)
|
|
203
|
-
return cls(sign=
|
|
206
|
+
return cls(sign=sign, exponent=exponent, fraction=fraction)
|
|
204
207
|
|
|
205
208
|
def _is_special_exponent(self) -> bool:
|
|
206
209
|
"""Checks if the exponent represents a special value (NaN or Infinity).
|
|
@@ -345,7 +348,7 @@ class FlexFloat:
|
|
|
345
348
|
"""
|
|
346
349
|
if isinstance(other, Number):
|
|
347
350
|
other = FlexFloat.from_float(other)
|
|
348
|
-
if not isinstance(other, FlexFloat):
|
|
351
|
+
if not isinstance(other, FlexFloat): # type: ignore[unreachable]
|
|
349
352
|
raise TypeError("Can only add FlexFloat instances.")
|
|
350
353
|
|
|
351
354
|
if self.sign != other.sign:
|
|
@@ -450,7 +453,7 @@ class FlexFloat:
|
|
|
450
453
|
"""
|
|
451
454
|
if isinstance(other, Number):
|
|
452
455
|
other = FlexFloat.from_float(other)
|
|
453
|
-
if not isinstance(other, FlexFloat):
|
|
456
|
+
if not isinstance(other, FlexFloat): # type: ignore[unreachable]
|
|
454
457
|
raise TypeError("Can only subtract FlexFloat instances.")
|
|
455
458
|
|
|
456
459
|
# If signs are different, subtraction becomes addition
|
|
@@ -584,7 +587,7 @@ class FlexFloat:
|
|
|
584
587
|
"""
|
|
585
588
|
if isinstance(other, Number):
|
|
586
589
|
other = FlexFloat.from_float(other)
|
|
587
|
-
if not isinstance(other, FlexFloat):
|
|
590
|
+
if not isinstance(other, FlexFloat): # type: ignore[unreachable]
|
|
588
591
|
raise TypeError("Can only multiply FlexFloat instances.")
|
|
589
592
|
|
|
590
593
|
# OBJECTIVE: Multiply two FlexFloat instances together.
|
|
@@ -713,7 +716,7 @@ class FlexFloat:
|
|
|
713
716
|
"""
|
|
714
717
|
if isinstance(other, Number):
|
|
715
718
|
other = FlexFloat.from_float(other)
|
|
716
|
-
if not isinstance(other, FlexFloat):
|
|
719
|
+
if not isinstance(other, FlexFloat): # type: ignore[unreachable]
|
|
717
720
|
raise TypeError("Can only divide FlexFloat instances.")
|
|
718
721
|
|
|
719
722
|
# OBJECTIVE: Divide two FlexFloat instances.
|
|
@@ -873,241 +876,77 @@ class FlexFloat:
|
|
|
873
876
|
"""
|
|
874
877
|
if isinstance(other, Number):
|
|
875
878
|
other = FlexFloat.from_float(other)
|
|
876
|
-
if not isinstance(other, FlexFloat):
|
|
879
|
+
if not isinstance(other, FlexFloat): # type: ignore[unreachable]
|
|
877
880
|
raise TypeError("Can only raise FlexFloat instances to a power.")
|
|
878
881
|
|
|
879
|
-
#
|
|
880
|
-
#
|
|
881
|
-
# Handle special cases first for performance and correctness
|
|
882
|
-
#
|
|
883
|
-
# Steps:
|
|
884
|
-
# 0. Handle special cases (NaN, infinity, zero, one)
|
|
885
|
-
# 1. Handle negative base with fractional exponent (returns NaN)
|
|
886
|
-
# 2. For general case: compute ln(|base|) * exponent
|
|
887
|
-
# 3. Compute exp(result) to get the final power
|
|
888
|
-
# 4. Handle sign for negative base with integer exponent
|
|
889
|
-
# 5. Return new FlexFloat instance
|
|
890
|
-
|
|
891
|
-
# Step 0: Handle special cases
|
|
892
|
-
if self.is_nan() or other.is_nan():
|
|
893
|
-
return FlexFloat.nan()
|
|
882
|
+
# Handle special cases for power operation (Python float semantics, no overflow/underflow)
|
|
883
|
+
# TODO: Handle integer powers more efficiently
|
|
894
884
|
|
|
895
|
-
#
|
|
896
|
-
if self.is_zero():
|
|
897
|
-
if other.is_zero():
|
|
898
|
-
return FlexFloat.from_float(1.0) # 0^0 = 1 (by convention)
|
|
899
|
-
if other.sign: # negative exponent
|
|
900
|
-
return FlexFloat.infinity(sign=False) # 0^(-n) = +infinity
|
|
901
|
-
return FlexFloat.zero() # 0^n = 0 for positive n
|
|
902
|
-
|
|
903
|
-
# One base: 1^anything = 1
|
|
904
|
-
if (
|
|
905
|
-
not self.sign
|
|
906
|
-
and self.exponent.to_signed_int() == -1
|
|
907
|
-
and not any(self.fraction)
|
|
908
|
-
):
|
|
909
|
-
# Check if self is exactly 1.0 (exponent = -1, fraction = 0)
|
|
910
|
-
return FlexFloat.from_float(1.0)
|
|
911
|
-
|
|
912
|
-
# Zero exponent: anything^0 = 1 (except 0^0 handled above)
|
|
885
|
+
# 1. If exponent is 0.0 or -0.0: result is 1.0
|
|
913
886
|
if other.is_zero():
|
|
914
|
-
return
|
|
915
|
-
|
|
916
|
-
# One exponent: anything^1 = anything
|
|
917
|
-
if (
|
|
918
|
-
not other.sign
|
|
919
|
-
and other.exponent.to_signed_int() == -1
|
|
920
|
-
and not any(other.fraction)
|
|
921
|
-
):
|
|
922
|
-
# Check if other is exactly 1.0 (exponent = -1, fraction = 0)
|
|
923
|
-
return self.copy()
|
|
887
|
+
return ONE
|
|
924
888
|
|
|
925
|
-
#
|
|
926
|
-
if self.
|
|
889
|
+
# 2. If base is nan
|
|
890
|
+
if self.is_nan():
|
|
891
|
+
# nan ** 0 = 1, nan ** x = nan
|
|
927
892
|
if other.is_zero():
|
|
928
|
-
return
|
|
929
|
-
|
|
930
|
-
return FlexFloat.zero() # inf^(-n) = 0
|
|
931
|
-
# inf^n = inf, but need to handle sign for negative infinity
|
|
932
|
-
if not self.sign: # positive infinity
|
|
933
|
-
return FlexFloat.infinity(sign=False) # (+inf)^n = +inf
|
|
934
|
-
|
|
935
|
-
# Check if exponent is an integer for sign determination
|
|
936
|
-
try:
|
|
937
|
-
exp_float = other.to_float()
|
|
938
|
-
if exp_float == int(exp_float): # integer exponent
|
|
939
|
-
result_sign = int(exp_float) % 2 == 1 # odd = negative
|
|
940
|
-
else:
|
|
941
|
-
return FlexFloat.nan() # (-inf)^(non-integer) = NaN
|
|
942
|
-
except (ValueError, OverflowError):
|
|
943
|
-
# For very large exponents, assume positive result
|
|
944
|
-
result_sign = False
|
|
945
|
-
return FlexFloat.infinity(sign=result_sign)
|
|
893
|
+
return ONE
|
|
894
|
+
return FlexFloat.nan()
|
|
946
895
|
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
return (
|
|
954
|
-
FlexFloat.infinity(sign=False)
|
|
955
|
-
if not other.sign
|
|
956
|
-
else FlexFloat.zero()
|
|
957
|
-
)
|
|
958
|
-
# base_abs < 1.0
|
|
959
|
-
return (
|
|
960
|
-
FlexFloat.zero()
|
|
961
|
-
if not other.sign
|
|
962
|
-
else FlexFloat.infinity(sign=False)
|
|
963
|
-
)
|
|
964
|
-
except (ValueError, OverflowError):
|
|
965
|
-
# For very large/small bases, use log-based approach
|
|
966
|
-
pass
|
|
896
|
+
# 3. If exponent is nan
|
|
897
|
+
if other.is_nan():
|
|
898
|
+
# x ** nan = 1 if x is 1 or -1, else nan
|
|
899
|
+
if self == ONE or self == MINUS_ONE:
|
|
900
|
+
return ONE
|
|
901
|
+
return FlexFloat.nan()
|
|
967
902
|
|
|
968
|
-
#
|
|
969
|
-
if self
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
# We need to compute ln(|self|) * other, then exp of that result
|
|
985
|
-
|
|
986
|
-
# For the logarithmic approach, we work with the absolute value
|
|
987
|
-
abs_base = self.abs()
|
|
988
|
-
|
|
989
|
-
# Use the mathematical identity: a^b = exp(b * ln(a))
|
|
990
|
-
# However, since we don't have ln implemented, we'll use Python's math
|
|
991
|
-
# for the core calculation and then convert back to FlexFloat
|
|
992
|
-
try:
|
|
993
|
-
# Convert to float for the mathematical computation
|
|
994
|
-
base_float = abs_base.to_float()
|
|
995
|
-
exp_float = other.to_float()
|
|
996
|
-
|
|
997
|
-
# For very small results that would underflow in float arithmetic,
|
|
998
|
-
# we need to use extended precision
|
|
999
|
-
log_result_estimate = exp_float * math.log(base_float)
|
|
1000
|
-
|
|
1001
|
-
# Check if the result would be too small for standard float
|
|
1002
|
-
if log_result_estimate < -700: # This would underflow to 0 in float
|
|
1003
|
-
# Use extended precision approach
|
|
1004
|
-
# Estimate the required exponent bits for the very small result
|
|
1005
|
-
estimated_exp = int(log_result_estimate / LOG10_2)
|
|
1006
|
-
required_exp_bits = max(11, abs(estimated_exp).bit_length() + 2)
|
|
1007
|
-
|
|
1008
|
-
# Create a small result with extended exponent
|
|
1009
|
-
small_exp = self._bitarray_implementation.from_signed_int(
|
|
1010
|
-
estimated_exp, required_exp_bits
|
|
1011
|
-
)
|
|
1012
|
-
# Use a normalized mantissa (leading 1 + some fraction bits)
|
|
1013
|
-
result = FlexFloat(
|
|
1014
|
-
sign=False,
|
|
1015
|
-
exponent=small_exp,
|
|
1016
|
-
fraction=self._bitarray_implementation.ones(52),
|
|
1017
|
-
)
|
|
903
|
+
# 4. If base is 1.0 or -1.0
|
|
904
|
+
if self == ONE:
|
|
905
|
+
return ONE
|
|
906
|
+
if self == MINUS_ONE:
|
|
907
|
+
# -1.0 ** integer = ±1, -1.0 ** non-integer = nan
|
|
908
|
+
# TODO: Check if exponent is integer
|
|
909
|
+
return FlexFloat.nan()
|
|
910
|
+
|
|
911
|
+
# 5. If base is 0.0 or -0.0
|
|
912
|
+
if self.is_zero():
|
|
913
|
+
if other > ZERO:
|
|
914
|
+
# 0 ** positive = 0 (preserve sign)
|
|
915
|
+
return FlexFloat.zero(sign=self.sign)
|
|
916
|
+
elif other < ZERO:
|
|
917
|
+
# 0 ** negative = inf (preserve sign)
|
|
918
|
+
return FlexFloat.infinity(sign=self.sign)
|
|
1018
919
|
else:
|
|
1019
|
-
#
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
# Handle potential overflow/underflow
|
|
1023
|
-
if math.isinf(result_float):
|
|
1024
|
-
return FlexFloat.infinity(sign=False)
|
|
1025
|
-
if result_float == 0.0:
|
|
1026
|
-
# Even if Python returns 0, we might want extended precision
|
|
1027
|
-
if log_result_estimate < -300: # Very small but not quite underflow
|
|
1028
|
-
estimated_exp = int(log_result_estimate / LOG10_2)
|
|
1029
|
-
required_exp_bits = max(11, abs(estimated_exp).bit_length() + 2)
|
|
1030
|
-
small_exp = self._bitarray_implementation.from_signed_int(
|
|
1031
|
-
estimated_exp, required_exp_bits
|
|
1032
|
-
)
|
|
1033
|
-
result = FlexFloat(
|
|
1034
|
-
sign=False,
|
|
1035
|
-
exponent=small_exp,
|
|
1036
|
-
fraction=self._bitarray_implementation.ones(52),
|
|
1037
|
-
)
|
|
1038
|
-
else:
|
|
1039
|
-
return FlexFloat.zero()
|
|
1040
|
-
if math.isnan(result_float):
|
|
1041
|
-
return FlexFloat.nan()
|
|
1042
|
-
|
|
1043
|
-
# Convert result back to FlexFloat
|
|
1044
|
-
result = FlexFloat.from_float(result_float)
|
|
1045
|
-
|
|
1046
|
-
except (ValueError, OverflowError):
|
|
1047
|
-
# If float computation overflows, use extended precision approach
|
|
1048
|
-
# This is a fallback for when the result is too large for float
|
|
1049
|
-
|
|
1050
|
-
# For very large results, we estimate the exponent growth needed
|
|
1051
|
-
try:
|
|
1052
|
-
# Estimate log(result) = exponent * log(base)
|
|
1053
|
-
log_base = (
|
|
1054
|
-
math.log(abs(self.to_float()))
|
|
1055
|
-
if not self.is_zero()
|
|
1056
|
-
else -float("inf")
|
|
1057
|
-
)
|
|
1058
|
-
exp_float = other.to_float()
|
|
1059
|
-
estimated_log_result = exp_float * log_base
|
|
920
|
+
# 0 ** 0 already handled above
|
|
921
|
+
return FlexFloat.nan()
|
|
1060
922
|
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
923
|
+
# 6. If base is inf or -inf
|
|
924
|
+
if self.is_infinity():
|
|
925
|
+
if other.is_zero():
|
|
926
|
+
return ONE
|
|
927
|
+
elif other > ZERO:
|
|
928
|
+
return FlexFloat.infinity(sign=self.sign)
|
|
929
|
+
else:
|
|
930
|
+
return FlexFloat.zero(sign=self.sign)
|
|
1066
931
|
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
# use arbitrary precision arithmetic
|
|
1070
|
-
if estimated_exp_float > 0:
|
|
1071
|
-
# Very large positive result
|
|
1072
|
-
large_exp = self._bitarray_implementation.from_signed_int(
|
|
1073
|
-
int(estimated_exp_float), required_exp_bits
|
|
1074
|
-
)
|
|
1075
|
-
result = FlexFloat(
|
|
1076
|
-
sign=False,
|
|
1077
|
-
exponent=large_exp,
|
|
1078
|
-
fraction=self._bitarray_implementation.ones(52),
|
|
1079
|
-
)
|
|
1080
|
-
else:
|
|
1081
|
-
# Very small positive result
|
|
1082
|
-
small_exp = self._bitarray_implementation.from_signed_int(
|
|
1083
|
-
int(estimated_exp_float), required_exp_bits
|
|
1084
|
-
)
|
|
1085
|
-
result = FlexFloat(
|
|
1086
|
-
sign=False,
|
|
1087
|
-
exponent=small_exp,
|
|
1088
|
-
fraction=self._bitarray_implementation.ones(52),
|
|
1089
|
-
)
|
|
1090
|
-
|
|
1091
|
-
except (ValueError, OverflowError, ZeroDivisionError):
|
|
1092
|
-
# Ultimate fallback
|
|
1093
|
-
return FlexFloat.nan()
|
|
932
|
+
# TODO: 7. If base < 0 and exponent is not integer: nan
|
|
933
|
+
# if self.sign and self.fraction.to_int() != 0:
|
|
1094
934
|
|
|
1095
|
-
|
|
1096
|
-
if self.sign and is_odd_exponent:
|
|
1097
|
-
result.sign = True
|
|
935
|
+
from . import math # Import to avoid circular import issues (TODO: improve)
|
|
1098
936
|
|
|
1099
|
-
|
|
937
|
+
# Otherwise, use exp(other * log(self))
|
|
938
|
+
return math.exp(other * math.log(self))
|
|
1100
939
|
|
|
1101
|
-
def __rpow__(self,
|
|
940
|
+
def __rpow__(self, other: Number) -> FlexFloat:
|
|
1102
941
|
"""Right-hand power operation for Number types.
|
|
1103
942
|
|
|
1104
943
|
Args:
|
|
1105
|
-
|
|
944
|
+
other (Number): The base to raise to the power of this FlexFloat.
|
|
1106
945
|
|
|
1107
946
|
Returns:
|
|
1108
947
|
FlexFloat: A new FlexFloat instance representing the power.
|
|
1109
948
|
"""
|
|
1110
|
-
return FlexFloat.from_float(
|
|
949
|
+
return FlexFloat.from_float(other) ** self
|
|
1111
950
|
|
|
1112
951
|
def _compare(self, other: FlexFloat) -> ComparisonResult:
|
|
1113
952
|
"""Compare this FlexFloat with another FlexFloat.
|
|
@@ -1338,3 +1177,11 @@ class FlexFloat:
|
|
|
1338
1177
|
if result == ComparisonResult.INCOMPARABLE:
|
|
1339
1178
|
return False
|
|
1340
1179
|
return result in (ComparisonResult.EQUAL, ComparisonResult.GREATER_THAN)
|
|
1180
|
+
|
|
1181
|
+
|
|
1182
|
+
ZERO: Final[FlexFloat] = FlexFloat.from_float(0.0)
|
|
1183
|
+
"""Constant representing the FlexFloat value of 0.0."""
|
|
1184
|
+
ONE: Final[FlexFloat] = FlexFloat.from_float(1.0)
|
|
1185
|
+
"""Constant representing the FlexFloat value of 1.0."""
|
|
1186
|
+
MINUS_ONE: Final[FlexFloat] = FlexFloat.from_float(-1.0)
|
|
1187
|
+
"""Constant representing the FlexFloat value of -1.0."""
|