在 C 中存储和使用具有 1,000,000 位有效数字的浮点数的最有效方法是啥?
Posted
技术标签:
【中文标题】在 C 中存储和使用具有 1,000,000 位有效数字的浮点数的最有效方法是啥?【英文标题】:What is the most efficient way to store and work with a floating point number with 1,000,000 significant digits in C?在 C 中存储和使用具有 1,000,000 位有效数字的浮点数的最有效方法是什么? 【发布时间】:2009-10-05 23:39:26 【问题描述】:我正在编写一个实用程序来计算 π 到小数点后一百万位。在 32 位或 64 位消费者桌面系统上,存储和处理如此精确到百万位数的大量数字的最有效方法是什么?
澄清:语言将是 C。
【问题讨论】:
我必须说,这延伸了“效用”的概念。 是的,但我一直对此感到困惑...用谷歌搜索它,在文章中查找它,但仍然不确定最好的解决方法。 你指的是十进制还是二进制?您看过哪些任意精度算术包? (GMP、PARI 是我想到的两个,还有 OpenSSL 中的算术和 Dave Hanson 为他的 C 接口书所做的东西;还有很多其他的。) 十进制数字。仅举几例,有 apfloat、FMLIB、BMP、mpmath... 如果您问“我如何有效地计算 pi 的连续数字”这个问题,那么一些答案不会涉及处理大量数字。 【参考方案1】:忘记浮点,你需要表示整数的位串
每个数字占用的空间不到 1/2 兆字节。 “高效”可能意味着很多事情。节省空间?省时?易于编程?
您的问题被标记为 floating-point,但我很确定您根本不想要浮点数。浮点的整个想法是,我们的数据只有少数有效数字知道,即使是著名的物理和化学常数也只有少数或两位数字知道。因此,保留合理数量的数字然后简单地记录指数是有意义的。
但你的任务完全不同。您必须考虑每一位。鉴于此,除非它是一个可以任意大小的模板,否则任何浮点或十进制算术包都不会起作用,然后指数将毫无用处。所以你也可以使用整数。
你真正需要的是一串比特。这只是一组方便的类型。我建议<stdint.h>
并简单地使用uint32_t[125000]
(或64)开始。这实际上可以很好地利用该标头中更模糊的常量,这些常量可以挑选出在给定平台上快速的位大小。
为了更具体,我们需要更多地了解您的目标。这是用特定语言练习的吗?对数论进行一些调查?如果是后者,为什么不直接使用已经支持 Bignum 的语言,比如 Ruby?
那么存储是别人的问题。但是,如果你真正想做的是实现一个大数字包,那么我可能会建议使用 bcd(4 位)字符串,甚至是带有可打印数字的普通 ascii 8 位字符串,因为事情会更容易编写和调试最大的空间和时间效率可能并不重要。
【讨论】:
优点。这是对cs理论的调查。我使用 C 作为语言,因为它是我最熟悉的。我正在使用 PI 算法,因为它的算法是众所周知的,精确数字高达数千万位数,所以我可以测试我的算法,看看它是否有效。效率将一如既往地在内存和时间之间进行权衡。谢谢! 感谢你给了我一个真正喜欢 Ruby的理由。【参考方案2】:我建议将它存储为一个短整数数组,每个数字一个,然后仔细编写实用程序类来添加和减去部分数字。你最终会从这个整数数组移动到浮点数并返回,但你需要一种“完美”的存储数字的方式 - 所以使用它的精确表示。就空间而言,这不是最有效的方法,但一百万个整数并不是很大。
这完全取决于您使用表示的方式。决定你将如何“使用”这个数字,并编写一些好的实用函数。
【讨论】:
嗨,感谢您的回复。使用已知的算法,我可以快速生成比我知道如何处理更多的数字。做任何类型的浮点数学都会出现问题,我不确定如何判断结果是否准确,或者它是否受到 IEEE 754 浮点数的细微差别的影响。我可以一次计算一个数字,并将它们全部存储为一个巨大的 C 短裤数组......但这似乎是蛮力【参考方案3】:如果您愿意以十六进制而不是十进制计算 pi,则有一个 very cute algorithm 允许您在不知道前面的数字的情况下计算给定的十六进制数字。这意味着,通过扩展,您不需要存储(或能够进行计算)百万位数。
当然,如果您想获得第 n 个 十进制 数字,您需要知道所有达到该精度的十六进制数字才能进行基本转换,因此取决于您的需要,这最终可能不会为您节省太多(如果有的话)。
【讨论】:
使用十六进制而不是十进制是一个好主意,并且可以让您以某种方式存储更多数字。并且会占用更少的空间,可以很好地处理二进制数学等......但是必须连续计算每个数字而不存储结果将是一个杀手。简洁的算法。谢谢【参考方案4】:除非您只是为了娱乐和/或学习而编写此代码,否则我建议您使用 GNU Multiprecision 之类的库。查看mpf_t
数据类型及其相关函数以存储任意精度浮点数。
如果您只是为了娱乐/学习而这样做,则将数字表示为 chars
的数组,每个数组元素存储一个十进制数字。您必须实现长加法、长乘法等。
【讨论】:
将字符转换为数字并为每个元素返回会不会产生大量开销? 如果您将它们视为原始字节而不是 ASCII 字符,则不会。如果你使用'0'
到'9'
,你会有一点额外的开销,但如果你只是使用(char)0
到(char)9
,则不会。【参考方案5】:
试试PARI/GP,见wikipedia。
【讨论】:
【参考方案6】:您可以将其小数位作为文本存储在文件中并将其映射到数组。
【讨论】:
【参考方案7】:我曾经开发过一个使用非常大的数字(但不需要很好的精度)的应用程序。我们所做的是将数字存储为对数,因为您可以将一个相当大的数字存储为 int 中的 log10。
在使用位填充或一些复杂的位表示之前,请先考虑这一点。
我不太擅长复杂的数学运算,但我认为在存储数百万位精度的数字时,有些解决方案很优雅。
【讨论】:
数字作为日志,有趣的想法。但我想这就是只需要良好精度的地方。 log10 是一个巨大的数字,并且转换回来并不总是等于相同的数字。【参考方案8】:IMO,任意精度算术的任何程序员都需要了解基本转换。无论如何,这解决了两个问题:能够以十六进制数字计算 pi 并将这些东西转换为十进制表示,以及找到最佳容器。
主要约束是乘法指令中正确位数。 在 javascript 中,精度始终为 53 位,这意味着可以本地处理具有最大 26 位数字的 Uint32Array。 (每个字浪费 6 位)。
在使用 C/C++ 的 32 位架构中,可以很容易地得到 A*B mod 2^32,暗示 16 位的基本元素。 (这些可以在从 MMX 开始的许多 SIMD 架构中并行化)。此外,每个 16 位结果每个字可以包含 4 位十进制数(浪费大约 2.5 位)。
【讨论】:
以上是关于在 C 中存储和使用具有 1,000,000 位有效数字的浮点数的最有效方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
由于以下错误,检索具有 CLSID 00020906-0000-0000-C000-000000000046 的组件的 COM 类工厂失败:80070005
如何将 8 位无符号 wav 文件转换为 8 位有符号 wav 文件?
具有 1,000 行和 5,000 个输入的 Angular 表的缓慢渲染