为什么Elixir中有大量的电量超时?

时间:2018-06-03 21:02:31

标签: performance elixir bitcoin

我正在尝试在Elixir中重新创建比特币的一些基础知识。我知道Elixir不是完成任务的理想语言,但我这样做是为了娱乐和学习目的。当我试图从一个秘密实现公钥派生时遇到了以下问题,其中包括在有限域上非常大的数量上的非常大的功率。我自己实现了这个:math.pow / 2已经在与相对较小的数字进行斗争。但我的实施花了很长时间,功能最终耗尽。

值并调用函数:

prime = 115792089237316195423570985008687907853269984665640564039457584007908834671663
val = 65341020041517633956166170261014086368942546761318486551877808671514674964848

Util.my_fpow(val, prime - 2, prime)
Util模块中的

my_fpow / 3方法:

defmodule Util do
  def my_fpow(n, k, prime), do: my_fpow(n, k, 1, prime)
  defp my_fpow(_, 0, acc, _), do: acc
  defp my_fpow(n, k, acc, prime) do
    new_acc = n * acc
              |> rem(prime)

    my_fpow(n, k - 1, new_acc, prime)
  end
end

首先,我想更深入地了解为什么这种方法对于这些大数字需要很长时间。另外我会感兴趣的是,还有其他更高效的实现可能仍然可以在Elixir中进行这样的计算(不是大规模的,只是因此计算实际上可以在超时之前完成)。

1 个答案:

答案 0 :(得分:4)

您的功能将递归prime - 2次,因为您一次减1。即使Elixir每秒执行10亿次呼叫(它在当前硬件上获胜),它也需要超过10 ^ 60年才能执行。

更快的解决方案involves squaring the number on each iteration,可以减少对log2(x)的调用次数,这非常快。这是该算法的翻译:

defmodule A do
  # Calculates (n ^ k) % m.
  def powmod(n, k, m), do: powmod(n, k, m, 1)
  def powmod(_, 0, _, r), do: r
  def powmod(n, k, m, r) do
    r = if rem(k, 2) == 1, do: rem(r * n, m), else: r
    n = rem(n * n, m)
    k = div(k, 2)
    powmod(n, k, m, r)
  end
end

prime = 115792089237316195423570985008687907853269984665640564039457584007908834671663
val = 65341020041517633956166170261014086368942546761318486551877808671514674964848

IO.inspect A.powmod(val, prime - 2, prime)

输出:

83174505189910067536517124096019359197644205712500122884473429251812128958118