C++/Haskell中的精确实数运算和惰性列表性能

Exact real arithmetic and lazy list performance in C++/Haskell

本文关键字:运算 性能 列表 实数 Haskell C++      更新时间:2023-10-16

在阅读了这篇论文和这篇论文后,我最近遇到了精确实数运算的主题。

我发现许多论文讨论了使用有符号数字流实现精确算术。使用无限流来实现任意精度,可以在函数式语言(如Haskell)中使用惰性列表实现很好的实用性。然而,讨论函数语言中此类实现的论文似乎得出了性能非常差的结论。

现在,我意识到,与标准浮点表示相比,精确的非硬件实现通常具有相对较差的性能,但我有兴趣用命令式语言(特别是C++)和一组运算/函数(算术运算、三角函数、exp、log等)提供更高效的实现

我的问题:有符号数字/惰性流表示是否存在固有的缓慢因素,导致性能不佳,还是Haskell?是什么让它变慢了?有没有可能在C++中使用惰性流来实现一个有符号的数字流表示,它比Haskell实现的性能(显著)更好,或者这是徒劳的?也许重建是迭代?

我知道有两个C++库,RealLib和iRRAM,可以实现高效的实数计算。然而,这些似乎使用了区间算术,将实数表示为收缩的嵌套区间,这似乎不像无限流那样"纯粹"(如果你不同意,请纠正我!)。但也许只有这些方法才能达到良好的效率?

欢迎您提供任何意见!

有符号数字/惰性流表示是否存在固有的缓慢特性,导致了糟糕的性能,还是Haskell?是什么让它变慢了?有没有可能在C++中使用惰性流来实现一个有符号的数字流表示,它比Haskell实现的性能(显著)更好,或者这是徒劳的?也许重建是迭代?

惰性流最有效地表示为具有延迟函数分量的数据。这是GHC中相当高效的Haskell实现所使用的表示,也是您无论如何都需要在C++中使用的表示。在20年的Haskell编译器研究中,没有什么特别的"快速"版本的懒惰可以用C++编写,更多的可以追溯到Algol。

有关如何最有效地实现懒惰数据结构的研究的更多详细信息,请参阅关于GHC实现的好的介绍性文本?

现在,由于缺乏关于基准的信息,有几个可能的答案:

  • 代码写得很差(更好的实现可能不会很慢)
  • 将大数字表示为标记的惰性位会降低空间效率,从而导致各种硬件瓶颈
  • 数字的惰性流表示只允许某些线性算法。更密集的表示可以允许具有更好复杂性或绝对性能的算法

我的猜测是后两点。C++版本的懒惰只会是一项艰苦的工作,以达到GHC已经达到的水平,所以为什么不使用文章中的代码,看看你是否可以让它更快。

我担心"数字是一个懒惰的数字流"方法注定比更直接的方法效率更低,即使数字基数很大(比如2^64或更多):

  • 懒惰评估意味着,在最后,你所认为的数字实际上是代表导致它的计算的DAG。要求多一个数字可能会在这个DAG的每个节点中重新触发计算。一天下来,你花在家务上的时间比花在计算上的时间多得多。

  • 你可能无法使用更复杂的算法进行基本计算。例如,FFT乘法方法显然是不可能的。

  • 这并不意味着算法会很简单。思考如何在加法中处理99999的当前结果。你需要做好准备,为所有这9个做好准备。现在试着想想如何做乘法。一种表达懒散的语言可能有助于表达它,但你会因为第一个问题而受到更大的打击;我很高兴知道编译器能够为此进行优化,但我担心他们没有。