【问题标题】:Write the biggest prime写出最大的素数
【发布时间】:2013-01-25 16:12:22
【问题描述】:

我正在尝试解决 C# 中的 the biggest prime 编程实践问题。 问题很简单,打印出来或者写入文件号: 257,885,161 - 1(有 17,425,170 位)

我已经设法使用惊人的GNU Multiple Precision Arithmetic LibraryEmil Stevanof .Net wrapper 解决了这个问题

var num = BigInt.Power(2, 57885161) - 1;
File.WriteAllText("biggestPrime.txt", num.ToString());

即使当前发布的所有解决方案都使用这个库,对我来说这感觉就像在作弊。有没有办法在托管代码中解决这个问题?想法?有什么建议吗?

PS:我已经尝试过使用 .Net 4.0 BigInteger,但它永远结束计算(我等了 5 分钟,但与 GMP 解决方案的 50 秒相比已经很多了)。

【问题讨论】:

  • 我只是指出5分钟不是never
  • BigInteger.ToString() 方法对于大数字非常很慢。另外我不太明白他们为什么选择将BigInteger 设为值类型,因为它的底层数组可能会占用很多兆字节。
  • @Blachshma 我知道,这就是为什么 never 是斜体的 :) 顺便说一句,我在发布后让它运行,1 个多小时后它仍在计算。
  • @JeppeStigNielsen 为什么它是一个值类型很重要?复制 BigInteger 意味着只复制 reference 到(可能是巨大的)数组,而不是复制整个数组。
  • @svick 在二进制中,它只是57885161 的序列。所以你需要做的就是找出第一个十六进制数字和后面的fs 的数量。从57885161 = 1 (mod 4)开始,第一个数字是1,后面是fs的个数是57885161 / 4 = 14471290

标签: c# algorithm numbers primes


【解决方案1】:

这更像是作弊而不是解决方案,但我使用 IntX library 解决了这个问题

IntX.Pow(2, 57885161, MultiplyMode.AutoFht) - 1;

运行了大约 6 分钟。不过,这仍然不是一个真正的答案。看到“真实”的东西会很有趣。

编辑:使用 C# 秒表我发现计算只需要 5 秒,这是 ToString 的过程需要非常长的时间。

【讨论】:

  • 考虑到库是用完全托管的代码编写的,这对我有好处。我将深入研究 IntX 代码库。谢谢
  • 数字的二进制计算相当简单。对于BigInteger,它也可以写成var prime = (((BigInteger)1) << 57885161) - 1;。所以转换成十进制是需要努力的。
  • 当然在 GMP 中也是如此。以二进制计算素数需要 GMP 0.003 秒。将其转换为十进制大约需要五秒钟。
【解决方案2】:

如果您只想使用乘法(和适当的大整数库)来计算这个数字,您可以考虑减少计算的次数。在简单的情况下,您可以在减去 1 之前重复乘以 2(57885161 次),但我们可以用更少的乘法来完成。

考虑重复平方。这给了我们 2, 22, (22)2 = 24, (2 4)2 = 28 等...在平方 25 次后,我们将计算出 2(225) = 233554432

如果我们查看 57885161 的二进制表示,我们会​​得到 11011100110100000111101001。即告诉我们我们需要 (for 257885161) 2(225) * 2(224 ) * 2(222) 等等...我们可以存储所有需要的 2 的幂来计算所需的最高幂,然后只需做最后的乘法。这就是 25 + 13 个大整数乘法。然后我们只需要为所需的值减去 1。

【讨论】:

  • 除非对大整数乘法使用高级算法,否则这仍然会非常慢。
【解决方案3】:

您要实现的目标是计算密集型的。 Visual C# 和 Visual Basic(以及一般的解释语言)不是为这样的事情而设计的。使用 GMP 是正确的做法,因为它是用纯 C 语言实现的,并且针对执行速度进行了高度优化。

如果您选择仅使用托管代码,请耐心等待:使用 .Net 4.0 BigInteger 可能需要比使用 GMP 多出100 倍的时间。要对此进行测试,您应该计算 21,000、210,000、2100,000、21,000,000 和 210,000,000 并查看使用 .Net 4.0 框架计算每个表达式所需的时间。

如果结果需要的时间太长,那么您可以尝试自己进行计算。您应该使用这个algorithm to perform the exponentiation,然后从 C++ 移植到 C# my own implementation of big integers multiplication 或您可能找到的任何其他内容。但是,无法保证您将获得明显更好的性能,因为您仍在使用托管代码。

【讨论】:

  • C# 和 VB 不是解释性语言,它们被编译为 IL,然后编译为机器代码。托管代码没有理由比 C 中的相同代码慢 100 倍。
  • 发帖人并未声明 C#/VB 本身就是解释的。除此之外,他们可能会使用解释生成的字节码(pre/ecno/normal jit)的运行时。第三,语言爱好者应该真正阅读并理解答案,并考虑与 OP 问题的相关性。
  • OP 指出,使用 GMP 计算需要 50 秒,而使用 .Net 框架时,即使超过一个小时,相同的计算也不会完成。不管是什么原因,事实是 C# 和 VB 不适合计算密集型操作,在这种情况下应该求助于其他编程语言。
  • 使用 IntX 库(用托管代码编写)需要 10 倍以上的时间,这令人印象深刻。我的问题的目的不是在 .net 中找到最好和最快的解决方案,我只是想知道一种在托管代码中处理这个问题的方法。
  • 这几乎与语言无关,与算法有关。这可能就是这个答案被否决的原因。当您将 O(N^2) 小学方法与 IntX 和 GMP 的 O(N log N log log N) 进行比较时,语言(IntX 与 GMP)的明显乘法因子 7 与N 为 5800 万时的阶数。错误的语言使它需要几分钟而不是一分钟。错误的算法将使其花费两年而不是一分钟!这个答案是在找错树。
猜你喜欢
  • 2013-02-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多