64 位中的 32 位浮点数学 Python

32-bit floating point math in 64-bit Python

我编写在 32 位硬件中运行 32 位数学运算的嵌入式软件。我经常调查浮点不精确问题。

目标内调试是例行公事,但为了方便起见,我希望能够在我的桌面 Python 环境中进行快速计算,使其表现得像目标,即在 32 中进行数学运算位。

桌面硬件,OS 和 Python 安装是 64 位。

我们正在谈论IEEE floats

理想情况下,在配置之后,我希望能够在 Python 解释器中键入 0.1+0.2,并且它已经知道使用 32 位数学来处理和存储所有内容.

我有哪些选择?

直接的方法本质上是 运行 为与您的目标匹配的环境构建 Python,即为目标构建它并 运行 在桌面硬件上的模拟器中构建它.请务必使用适当的浮点类型构建它,因为编译器将具有对更广泛类型的软件支持。这将是非常低效的,但与您的模拟器一样准确。

如果你能凑合使用存储行为,你可以使用 numpy.float32ctypes.c_float,但两者都不会让你获得将浮点文字映射到该类型的直接行为,它们会可能使用 64 或 80 位操作,这会导致您想要避免的舍入差异。如果包装自己的 REPL,则可以在 AST 级别执行文字重映射;虽然 Python 在 codeast 模块中对此有一些库帮助,但这是一个相当复杂的主题。

扩展 Yann Vernier 的想法,这将是一个可能的转换器,它注入一个 numpy 导入并将每个 float 文字包装在 numpy.float32.

import ast

class Float32Visitor(ast.NodeTransformer):
    def visit_Module(self, node):
        # add numpy import
        imp = ast.Import([ast.alias("numpy")])
        node.body = [imp] + node.body
        return node

    def visit_Num(self, node):
        if not isinstance(node.n, float):
            return node

        return ast.Call(
            func=ast.Attribute(
                value=ast.Name(id="numpy", ctx=ast.Load()),
                attr="float32", ctx=ast.Load()
            ),
            args=[node],
            keywords=[],
            starargs=None,
            kwargs=None
        )

然而,将其连接到 compile 中有点棘手和老套。要针对一段代码执行此操作,您需要执行以下操作:

import ast
parsed = ast.parse(my_code, "my_code.py", mode="exec")
parsed = Float32Visitor().visit(parsed)
code = compile(parsed, "my_code.py", mode="exec")
my_code = eval(code)