任意精度分数算术(C/C++)中的浮点数与有理数
Floats vs rationals in arbitrary precision fractional arithmetic (C/C++)
由于有两种实现AP分数的方法,一种是模拟double
数据类型的存储和行为,只使用更多的字节,另一种是使用现有的整数APA实现将分数表示为有理数,即表示为一对整数、分子和分母,就性能而言,这两种方法中哪一种更有可能提供高效的算术?(内存使用确实是个小问题。)
我知道现有的C/C++库,其中一些库提供带有"浮点"的分数APA,另一些库提供有理数(然而,它们都没有定点APA)。当然,我可以将依赖于"浮点"实现的库与使用合理实现的库进行比较,但结果在很大程度上取决于那些特定库的实现细节,我必须从近十个可用库中随机选择。因此,我感兴趣的两种方法(如果考虑到定点APA,则为三种)的更多理论利弊。
问题是您在标题中提到的任意精度是什么意思。它的意思是"任意的,但在编译时预先确定,在运行时固定"吗?或者它的意思是"无限的,即在运行时可扩展以表示任何有理数"?
在前一种情况下(在编译时可以自定义精度,但稍后会修复),我认为最有效的解决方案之一实际上是定点算术(即,您提到的两种都没有)。
首先,定点算术不需要任何用于基本算术运算的专用库。它只是一个覆盖在整数算术之上的概念。这意味着,如果你真的需要在点后有很多数字,你可以取任何一个大整数库,把所有数据乘以2^64,你基本上立即得到点后有64个二进制数字的定点算术(至少就算术运算而言,需要对乘法和除法进行一些额外的调整)。这通常比浮点或有理表示更有效。
还要注意的是,在许多实际应用中,乘法运算通常伴随着相互"补偿"的除法运算(如x = y * a / b
),这意味着通常没有必要对这种乘法和除法进行任何调整。这也有助于提高定点运算的效率。
其次,定点运算在整个范围内提供统一的精度。浮点表示或有理表示都不是这样,在某些应用程序中,这可能是后两种方法的一个显著缺点(或好处,取决于您需要什么)。
那么,为什么只考虑浮点和有理表示呢。是否有什么东西阻止您考虑定点表示?
由于似乎没有其他人提到这一点,有理数和浮点数代表不同的数字集。值1/3
可以用有理数精确表示,但不能用浮点表示。即使是任意精度的浮点,也需要无限多的尾数位来表示像1/3
这样的重复小数。这是因为浮点实际上像有理数,但分母被限制为2的幂。任意精度有理数可以表示任意精度浮点数所能表示的一切,甚至更多,因为分母可以是任何整数,而不是2的幂。(也就是说,除非我严重误解了任意精度浮点的实现方式。)
这是对你提出的理论利弊的回应。
我知道你没有问记忆使用情况,但这里有一个理论比较,以防其他人感兴趣。如上所述,有理数专门用于可以用分数表示法简单表示的数字,如1/3
或492113/203233
,而浮点数专门用于用2次方的科学表示法简单表达的数字,例如5*2^45
或91537*2^203233
。以人类可读的形式表示数字所需的ascii类型的数量与它们的内存使用量成比例。
如果我有任何错误,请在评论中纠正我。
无论哪种方式,都需要对任意大小的整数进行乘法运算。这将是您性能的主要因素,因为它的复杂性比O(n*log(n))
更差。像对齐操作数和加减大整数这样的操作是O(n)
,所以我们将忽略这些操作。
对于简单的加法和减法,浮点*不需要乘法运算,有理数不需要3次乘法运算。浮子轻而易举地获胜。
对于乘法,浮点数需要一次乘法运算,有理数需要两次乘法运算。浮子有优势。
分工有点复杂,理性可能会在这里获胜,但这绝非必然。我认为这是一场平局。
因此,总的来说,IMHO,加法对于理性至少是O(n*log(n))
,对于浮点至少是O(n)
,这一事实清楚地为浮点表示带来了胜利。
*如果你的指数基数和数字基数不同,你可能需要一次乘法来执行加法。否则,如果使用2的幂作为基数,则对齐操作数需要进行位移位。如果你不使用二的幂,那么你可能还必须乘以一个数字,这也是O(n)
运算。
你实际上在问一个问题:"我需要和我选择的动物一起参加比赛。我应该选择乌龟还是蜗牛?"。
第一个建议"模拟双精度"听起来像是交错精度:使用一个双精度数组,其和是定义的数字。Douglas M.Priest的一篇论文《任意精度浮点运算的算法》描述了该算法的实现方法。我实现了这一点,我的经验非常糟糕:进行此运行所需的开销会使性能下降100-1000倍!使用分数的另一种方法也有严重的缺点:你需要实现gcd和kgv,不幸的是,分子或分母中的每个素数都有很好的机会破坏你的数字,扼杀你的性能。
因此,根据我的经验,它们是性能方面最差的选择。
我建议使用MPFR库,它是C和C++中速度最快的AP包之一。
有理数不会给出任意精度,而是给出精确的答案。然而,就存储而言,它们更昂贵,使用它们的某些操作变得昂贵,并且一些操作根本不允许,例如取平方根,因为它们不一定会产生合理的答案。
就我个人而言,我认为在你的情况下,AP浮动会更合适。
- 在C++中,将大的无符号浮点数四舍五入为整数的最佳方法是什么
- 如何修复此错误:未定义对"距离(浮点数,浮点数,浮点数,浮点数,浮点数)"的引用
- C++浮点数据类型和字符串数据类型无法子到模板函数中
- 使用提升将数据从 PyObject 复制到浮点数 *
- 使用浮点数和双精度数的非常小数字的数学
- 使用英特尔内联函数将打包的 8 位整数乘以浮点数向量
- 如何在 c++ 中将小数点后两位数的浮点数分配给另一个浮点数
- 返回浮点数的小数位数
- txt 文件中浮点数的最大和最小值
- 为什么 std::cout 打印浮点数、双精度和长双精度到相同的小数精度?
- 将浮点数转换为无符号字符数组并打印出来
- 如何将时间字符串 (M:SS) 转换为浮点数
- 如何将浮点数(*)[6]转换为浮点**类型?
- C++将浮点数乘以分数
- 如何将浮点数转换为uint8_t?
- 将字符串转换为浮点数或整数,而无需使用内置函数(如 atoi 或 atof)
- 如何在C++(Arduino)中将浮点数组转换为字节数组
- 在数学上将浮点数四舍五入到 N 位小数
- Cython通过浮点数的最快方式,用于高频控制回路
- 复制 -nan 表示浮点数,AVX __m256 复制后显示 0