【问题标题】:How to Code a Solution To Deal With Large Numbers? [closed]如何编写处理大数的解决方案? [关闭]
【发布时间】:2010-12-31 18:16:40
【问题描述】:

我正在做一些 Project Euler 问题,并且大多数时候,计算涉及到 int、float、double 等之外的大量数字。

首先,我知道我应该寻找更有效的计算方法以避免大数问题。 我听说过 Bignum 库。

但是,出于学术兴趣,我想知道如何编写自己的解决方案来解决这个问题。

哪位高手可以帮帮我吗? (我的语言是 C)

【问题讨论】:

  • 编写一个大数字库将非常困难且容易出错
  • 我建议你使用现有的。
  • 编写一个包含基本操作的简单 bignum 库一点也不难。如果您想要最大效率或想要包含复杂的操作,那就是另一回事了,但这似乎不是这个问题的意义所在。

标签: c types largenumber bignum


【解决方案1】:

您需要将大数字存储在计算机可以使用其本机类型轻松处理的基数中,然后将数字存储在可变长度数组中。我建议为简单起见,首先以 10 为基数存储数字,以便掌握如何执行此操作。这将使调试变得容易得多。

一旦你有了一个可以以这种形式存储数字的类,只需在这个类上实现加、减、乘等操作。每个操作都必须迭代其操作数的数字并将它们组合,小心正确携带,以便您的数字永远不会大于基数。加法和减法很简单。乘法需要更多的工作,因为朴素算法需要嵌套循环。然后,一旦你完成了这项工作,你就可以尝试以一种有效的方式(例如重复平方)来实现求幂。

如果您打算编写一个 严重 bignum 实现,base 10 不会削减它。这很浪费内存,而且会很慢。您应该选择适合计算机的基数,例如 256 或字长 (2**32)。但是,这会使简单的操作变得更加困难,因为如果您天真地添加两位数字,您会出现溢出,因此您需要非常小心地处理。

【讨论】:

  • 通常,您会选择一个为最大可表示类型一半的基数,这样就不会溢出。例如,在现代 C 中,您会选择 uint32_t 并在 uint64_t 中进行所有数字运算。并且不要忘记:将数字类型设为unsigned,这样就不会出现意外。
  • 实际上,base 10 是完全足够的。这一切都取决于你的目的。如果速度是最重要的,那么如果你有一个快速的卷积器,那么卷积是进行乘法的好方法。如果使用大基数,卷积会溢出。
  • 这是最佳答案,因为它是对所提问题的唯一真正答案。
【解决方案2】:

C 不是 Project Euler 的好选择。 C 的好处是原始速度、机器可移植性(在某种程度上,与标准 C)、语言互操作性(如果某种语言与另一种语言进行通信,C 是流行的首选)、紧贴特定库或平台的 API(因为 C是常见的,例如 OS API),以及稳定的语言和标准库。 这些好处都不适用于解决 Project Euler 问题。 甚至没有原始速度,因为大多数问题与原始计算无关,而是了解所需的算法,您可以整天坐在那里等待在提交之前。

如果您正在尝试 Project Euler 问题来扩展您对 C 的体验,那很好,只需意识到这种体验不一定适用于您可能从事的长期和现实世界的 C 项目开。

对于这种短暂的、一次性的问题,通常被称为“脚本语言”的那些语言会更好、更快(在开发时)和更容易地工作。试试 Python,它在很多方面都接近 C,包括 C API,并且在各种流行的“脚本语言”中,您可能会发现与 C 项目结合使用最多的一种。

这可能会成为一个不受欢迎的答案,但它不是一个咆哮——而且我真的很喜欢 C 并且经常使用 C/C++——这里有一个明确的答案来解决你的问题:“不要使用 C”,与您最终的大量解决方案取决于您选择的替代方案。再次选择 Python,整数没有上限(请注意下面),我使用它来自然地编写 Project Euler 问题的答案,在其他语言中,我必须使用痛苦的比较替代数字库。

(Python整数: 2.x中有'int'和'long'两种整数类型(在3.x中已经完全统一了)。它们之间的转换实际上是无缝的, 而 'long' 允许任意大的值,而不是像 C 的 long 那样只是一个更大的 'int' 类型。)

【讨论】:

  • 我不同意你所说的,但 OP 想学习如何实现 bigint。
  • 我并不是说他不应该(在某些时候)学习它们是如何实现的(加上其他答案涵盖了他,没有意义重复它)。但是,在问题的上下文中,编写自己的 bigint 库甚至不是一个合适的解决方案,更不用说一个好的解决方案了。
  • 这是一篇较旧的帖子,但值得-1。这就像回答“我有一辆自行车,想给它加一个闪光灯,你能帮忙吗?”这个问题。 “一辆自行车?!?你知道汽车的效率有多高吗!它甚至还内置了闪光灯支持。显然你不了解交通。”有时只值得用适合该问题的答案来回答特定问题。
  • 这不应该是第一个答案,它根本没有回答问题。
  • 因为没有回答问题而只是分享一个人的观点而减 1。
【解决方案3】:

一个流行的用于 C/C++ 的 bignum 库是 GNU MP Bignum Library。我已经将它用于几个 Project Euler 问题,但事实仍然是 C 不是一种非常适合 Euler 问题的语言。如果性能更重要,C 会提供更多,但现在最好使用内置 bignum 支持的语言,例如 Ruby(还有很多其他语言)。

【讨论】:

  • 在 Project Euler 中重要的是您选择让什么变得重要。我在学习 C++ 的时候做了一堆问题,我的目标不是在 2 分钟内解决每个问题,而是在 2 分钟内解决 我做过的所有问题 ;-)
【解决方案4】:

一种简单的方法是将数字视为其以 b 为底的字符串表示形式。假设 b=10,可以使用与笔和纸相加时使用的相同方法来完成简单的算术运算,例如对两个这样的字符串进行加法运算。其他简单的操作也是如此。为了获得更好的结果,您可以选择更大的基数。

像这样的简单 bignum 实现应该足以解决大多数 Project Euler 问题(可能是所有问题,但我在 Euler 上解决的问题不多,所以不能确定),但有一些方法可以使用更快的算法进行运算,例如作为乘法和除法/mod。

虽然我建议您编写自己的 bignum 进行练习,但如果您真的遇到困难,您可以从已经实现的 bigint 库的代码中汲取灵感。对于一个严肃的实现,像 gmp 这样的东西是显而易见的选择。但是你也可以在网上解决类似的练习题时找到其他人编码的小 bigints(例如 Abednego 的bigint.cpp)。

【讨论】:

    【解决方案5】:

    Here's 一个漂亮而简单的 C 语言 bignum 模块。您可以从中学习灵感。 C 代码不是最高质量的,但算法实现得很好并且很常见。

    有关更高级的内容,请查阅 GMP。

    【讨论】:

      【解决方案6】:

      如果你想要一个漂亮的 C++ 版本(我知道,你说的是 C,但这确实是一段有趣的代码),看看 CGAL 的内部结构:http://www.cgal.org/

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2011-03-05
        • 2015-10-13
        • 2023-03-28
        • 2013-12-05
        • 2019-12-19
        • 1970-01-01
        • 2014-09-04
        相关资源
        最近更新 更多