Python 如何保持浮点/双精度算术确定性?

Python 如何保持浮点/双精度算术确定性?,python,c,precision,floating-accuracy,Python,C,Precision,Floating Accuracy,如果我们使用带双精度和浮点运算的算法,我们如何保证在Python和C、x86和x64 Linux和Windows计算机以及ARM微控制器中运行它的结果是相同的 我们使用的算法使用: double + double double + float double exp(double) float * float 双人+双人 双+浮点数 双经验(双) 浮动*浮动 在同一台计算机上,为x86和x64 MinGW编译它会得到不同的结果。该算法需要大量的数学运算,因此任何微小的错误最终都会产生影响 目

如果我们使用带双精度和浮点运算的算法,我们如何保证在Python和C、x86和x64 Linux和Windows计算机以及ARM微控制器中运行它的结果是相同的

我们使用的算法使用:

double + double
double + float
double exp(double)
float * float
  • 双人+双人
  • 双+浮点数
  • 双经验(双)
  • 浮动*浮动
在同一台计算机上,为x86和x64 MinGW编译它会得到不同的结果。该算法需要大量的数学运算,因此任何微小的错误最终都会产生影响

目前,ARM mcu实现给出了与x86相同的结果,但在看到这一点后,我不确定是否正确

编辑

在这种情况下,精度损失不是问题,只要在所有实现中都是一样的

编辑2

我发现这些链接非常有用,评论中已经有一些提示:


    • 这很难。双打和浮标在C或C++标准中没有形式化,其精度取决于编译器/ CPU的实现。例如,float和double都允许相同

      来自C++17草稿(与其他论文类似)

      有三种浮点类型:浮点型、双精度型和长双精度型。double类型提供的精度至少与float类型相同,long double类型提供的精度至少与double类型相同。float类型的值集是double类型的值集的子集;double类型的值集是long double类型的值集的子集。浮点类型的值表示由实现定义。[ 注:本文件对浮点运算的精度无任何要求;另请参见[support.limits]- [完注]

      我不认为C或C++标准中提到过。< /P> Python派生了这一点,在C实现中引用了浮动类型,而形式化是必要的

      有三种不同的数字类型:整数、浮点数和复数。此外,布尔是整数的一个子类型。整数有无限的精度。浮点数通常在C中使用双精度实现

      如果我们使用带双精度和浮点运算的算法,我们如何保证在Python和C、x86和x64 Linux和Windows计算机以及ARM微控制器中运行它的结果是相同的

      一般来说,除非小心地实施自己的FP操作,否则您不能这样做。如果您使用的是各种语言的标准运算符和库以及底层的浮点硬件,则无法确保结果在不同实现之间的精确再现性

      首先,浮点数的内部表示存在问题。C没有指定要使用的表示形式,即使其他所有表示形式都相同,也意味着您不能依赖运行在不同实现(例如x86_64和ARM)上的同一个C程序来计算相同的结果

      实际上,现在大多数人都使用ieee754浮点格式,CPython使用底层C实现的
      double
      类型来支持其浮点。然而,即使如此,IEEE也允许一致性实现之间存在一定的微小差异。即使是要求严格遵守IEEE规范的指令和编译选项也无法完全解决这一问题

      此外,您还指定希望在C和Python中同时处理
      double
      float
      ,但Python没有本机模拟的
      float
      。其本机浮点格式(可能)对应于C
      double
      。对不同浮点数据类型执行的操作必然会产生不同的结果,即使操作数在数值上是等效的,并且这种差异可能会在类型转换中持续存在,例如将
      double
      结果转换为
      float

      还有另外的细节要考虑,在(机器)代码生成级别,例如中间结果是否从FPU寄存器复制到主存储器(可能涉及舍入)和执行操作的顺序。< /P> 我们使用的算法使用:

      double + double
      double + float
      double exp(double)
      float * float
      
      如果希望最小化计算值之间的差异,那么首先选择一种浮点数据类型,并在任何地方使用它。为了保证Python和C实现之间的一致性,这应该是
      double

      您还应该考虑禁用任何可能更改FP操作被评估的顺序的所有优化。这可能是所有的优化。如果您的C编译器中有强制执行严格的IEEE一致性的选项,那么打开这些选项

      您还应该在所有相关平台上测试
      exp()
      函数的等效性。您可能需要提供自己的实现


      无论您做什么,您都应该认识到,如果您的各种实现产生不同的结果,尽管在某种算法意义上都是正确的,那么这本身就是一个结果。它告诉您一些关于计算的实际精度的信息


      您永远不要忘记,大多数计算机FP操作都会产生近似结果,因此,即使您成功地使所有实现产生相同的结果,但这并不意味着这些结果在绝对意义上一定比附近的其他FP值更正确。如果数值一致性是一项要求,那么您应该根据结果的特定精度对其进行量化,以提供该精度的方式实现算法,并忽略精度高于所选精度的差异。

      我认为您只能依赖于非常特定的配置