Source code for elasticai.creator.arithmetic.fxp_params

from dataclasses import dataclass
from typing import Protocol, TypeVar, Union, cast, overload, runtime_checkable

T = TypeVar("T", bound="ConvertableToFixedPointValues")


[docs] @runtime_checkable class ConvertableToFixedPointValues(Protocol[T]):
[docs] def round(self: T) -> T: ...
[docs] def int(self: T) -> T: ...
[docs] def float(self: T) -> T: ...
[docs] def __gt__(self: T, other: Union[int, float, T]) -> T: # type: ignore ...
[docs] def __lt__(self: T, other: Union[int, float, T]) -> T: # type: ignore ...
[docs] def __or__(self: T, other: T) -> T: ...
[docs] def __mul__(self: T, other: Union[int, T, float]) -> T: # type: ignore ...
[docs] def __truediv__(self: T, other: Union[int, float]) -> T: # type: ignore ...
[docs] @dataclass(frozen=True) class FxpParams: total_bits: int frac_bits: int signed: bool = True
[docs] def __post_init__(self): if self.total_bits <= 0: raise Exception( f"total bits need to be > 0 for {self.__class__.__name__}. " f"You have set {self.total_bits=}." ) if self.frac_bits > self.total_bits: raise Exception( f"total bits-1 needs to be > frac bits for {self.__class__.__name__}. " f"You have set {self.total_bits=} and {self.frac_bits=}." )
@property def minimum_as_integer(self) -> int: return 2 ** (self.total_bits - 1) * (-1) if self.signed else 0 @property def maximum_as_integer(self) -> int: return 2 ** (self.total_bits - 1) - 1 if self.signed else 2**self.total_bits - 1 @property def minimum_as_rational(self) -> float: return self.minimum_as_integer * self.minimum_step_as_rational @property def minimum_step_as_rational(self) -> float: return 1 / (1 << self.frac_bits) @property def maximum_as_rational(self) -> float: return self.maximum_as_integer * self.minimum_step_as_rational @overload def integer_out_overflow(self, number: T) -> T: ... @overload def integer_out_overflow(self, number: int) -> bool: ...
[docs] def integer_out_overflow(self, number: int | T) -> bool | T: return number > self.maximum_as_integer
@overload def integer_out_underflow(self, number: T) -> T: ... @overload def integer_out_underflow(self, number: int) -> bool: ...
[docs] def integer_out_underflow(self, number: int | T) -> bool | T: return number < self.minimum_as_integer
@overload def integer_out_of_bounds(self, number: T) -> T: ... @overload def integer_out_of_bounds(self, number: int) -> bool: ...
[docs] def integer_out_of_bounds(self, number: int | T) -> bool | T: if isinstance(number, ConvertableToFixedPointValues): return self._check_integer_out_of_bounds(cast(T, number)) else: return self._check_integer_out_of_bounds(number)
def _check_integer_out_of_bounds(self, number) -> bool | T: return self.integer_out_underflow(number) | self.integer_out_overflow(number) @overload def rational_out_overflow(self, number: T) -> T: ... @overload def rational_out_overflow(self, number: float) -> bool: ...
[docs] def rational_out_overflow(self, number: float | T) -> bool | T: return number > self.maximum_as_rational
@overload def rational_out_underflow(self, number: T) -> T: ... @overload def rational_out_underflow(self, number: float) -> bool: ...
[docs] def rational_out_underflow(self, number: float | T) -> bool | T: return number < self.minimum_as_rational
@overload def rational_out_of_bounds(self, number: T) -> T: ... @overload def rational_out_of_bounds(self, number: float) -> bool: ...
[docs] def rational_out_of_bounds(self, number) -> bool | T: return self.rational_out_underflow(number) | self.rational_out_overflow(number)