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.float32
或 ctypes.c_float
,但两者都不会让你获得将浮点文字映射到该类型的直接行为,它们会可能使用 64 或 80 位操作,这会导致您想要避免的舍入差异。如果包装自己的 REPL,则可以在 AST 级别执行文字重映射;虽然 Python 在 code
和 ast
模块中对此有一些库帮助,但这是一个相当复杂的主题。
扩展 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)
我编写在 32 位硬件中运行 32 位数学运算的嵌入式软件。我经常调查浮点不精确问题。
目标内调试是例行公事,但为了方便起见,我希望能够在我的桌面 Python 环境中进行快速计算,使其表现得像目标,即在 32 中进行数学运算位。
桌面硬件,OS 和 Python 安装是 64 位。
我们正在谈论IEEE floats。
理想情况下,在配置之后,我希望能够在 Python 解释器中键入 0.1+0.2
,并且它已经知道使用 32 位数学来处理和存储所有内容.
我有哪些选择?
直接的方法本质上是 运行 为与您的目标匹配的环境构建 Python,即为目标构建它并 运行 在桌面硬件上的模拟器中构建它.请务必使用适当的浮点类型构建它,因为编译器将具有对更广泛类型的软件支持。这将是非常低效的,但与您的模拟器一样准确。
如果你能凑合使用存储行为,你可以使用 numpy.float32
或 ctypes.c_float
,但两者都不会让你获得将浮点文字映射到该类型的直接行为,它们会可能使用 64 或 80 位操作,这会导致您想要避免的舍入差异。如果包装自己的 REPL,则可以在 AST 级别执行文字重映射;虽然 Python 在 code
和 ast
模块中对此有一些库帮助,但这是一个相当复杂的主题。
扩展 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)