以科学记数法表示的浮点数类

编程语言 2026-07-07

我的应用需要跟踪 float 数字,采用科学计数法的格式(例如 1.23E4)——数据的导入导出也使用这种格式。所以我写了一个简单的 dataclass

@dataclass
class SciNotation:
    significand: float
    exponent: int

    def as_float(self) -> float:
        if self.significand == 0:
            return 0.0
        return float(self.significand * 10 ** self.exponent)

随后我想增加对算术和比较运算符的支持,但希望既能复用现有的 float 函数,又不想为每一个 dunder 方法分别编写实现,于是我给出了如下实现:

    @classmethod
    def handle_dunders(cls, self: SciNotation, other: SciNotation | float | int):
        # get name of caller method
        import traceback
        method_name = traceback.extract_stack()[-2].name

        # get method of normal float
        float_method = getattr(float, method_name)

        # convert second operand if needed
        if isinstance(other, SciNotation):
            other = other.as_float()

        # do the deed
        result = float_method(self.as_float(), other)
        if isinstance(result, float):
            s, e = f"{result:E}".split("E")
            return cls(significand=float(s), exponent=int(e))
        elif isinstance(result, bool):
            return result
        else:
            raise NotImplementedError

    def __add__(self, other: Self | float | int):
        return self.handle_dunders(self, other)

    def __sub__(self, other: Self | float | int):
        return self.handle_dunders(self, other)

    def __mul__(self, other: Self | float | int):
        return self.handle_dunders(self, other)

    def __truediv__(self, other: Self | float | int):
        return self.handle_dunders(self, other)

    def __eq__(self, other: Self):
        return self.handle_dunders(self, other)

    def __lt__(self, other: Self):
        return self.handle_dunders(self, other)

现在这个实现确实能工作,但看起来有点儿…… 诡异。有没有更好的办法来处理这个问题?

解决方案

你完全可以彻底颠倒你的模型的工作方式。不是把数字以科学计数法存储,然后在运算时再把它们转换成浮点数进行运算;而是直接以浮点数存储,在导出时再把它们转换为科学计数法。如你所知,'e' 格式说明符 将为你完成这一步:

>>> n = 12345.6789
>>> f"{n:e}"
'1.234568e+04'
>>> f"{n:.2e}"
'1.23e+04'

这可能会让你的代码更高效,因为你只需要在导入和导出时进行转换,而不是在每次运算时都进行转换。

你甚至可以通过对 float 进行子类化并提供一个对 __str__ 的重写来调用该格式说明符,但那样你大概还是得重载所有的运算操作。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章