在 Elixir 中,为什么我的算法在达到 33 时会变得很奇怪,我该如何解决?

In Elixir, why does my algorthm for finding prime factors go weird once it hits the number 33 and how can I fix it?

我有以下模块来查找质因数:

defmodule PrimeFactors do
  def factors_for(number)
      when number < 2,
      do: []

  def factors_for(number),
      do: factors_for(number, _next_attempt = 2, _accumulator = [])

  def factors_for(number, next_attempt, accumulator)
      when next_attempt > number,
      do:
        accumulator
        |> Enum.reverse()

  def factors_for(number, next_attempt, accumulator) do
    IO.inspect(label: "######## [next_attempt | accumulator]  #{[next_attempt | accumulator]}: ")
    if rem(number, next_attempt) === 0,
       do: factors_for(div(number, next_attempt), next_attempt, [next_attempt | accumulator]),
       else: factors_for(number, next_prime(next_attempt), accumulator)
  end

  defp next_prime(2),
       do: 3

  defp next_prime(n),
       do: n + 2
           |> IO.inspect(label: "######## NEXT ")

end

对于大多数数字,它按预期工作:

例如,PrimeFactors.factors_for(10200) 的输出以:

结尾
######## NEXT: : 17
[
  label: <<35, 35, 35, 35, 35, 35, 35, 35, 32, 91, 110, 101, 120, 116, 95, 97,
    116, 116, 101, 109, 112, 116, 32, 124, 32, 97, 99, 99, 117, 109, 117, 108,
    97, 116, 111, 114, 93, 32, 32, 17, 5, 5, 3, 2, 2, 2, 58, 32>>
]
[2, 2, 2, 3, 5, 5, 17]

但是对于一些数字,输出变得很古怪。

例如,如果我执行 PrimeFactors.factors_for(10201),我们注意到当它命中 next_attempt 33 时,输出非常意外:

######## NEXT: : 29
[
  label: <<35, 35, 35, 35, 35, 35, 35, 35, 32, 91, 110, 101, 120, 116, 95, 97,
    116, 116, 101, 109, 112, 116, 32, 124, 32, 97, 99, 99, 117, 109, 117, 108,
    97, 116, 111, 114, 93, 32, 32, 29, 58, 32>>
]
######## NEXT: : 31
[
  label: <<35, 35, 35, 35, 35, 35, 35, 35, 32, 91, 110, 101, 120, 116, 95, 97,
    116, 116, 101, 109, 112, 116, 32, 124, 32, 97, 99, 99, 117, 109, 117, 108,
    97, 116, 111, 114, 93, 32, 32, 31, 58, 32>>
]
######## NEXT: : 33
[label: "######## [next_attempt | accumulator]  !: "]
######## NEXT: : 35
[label: "######## [next_attempt | accumulator]  #: "]
...
######## NEXT: : 99
[label: "######## [next_attempt | accumulator]  c: "]
######## NEXT: : 101
[label: "######## [next_attempt | accumulator]  e: "]
[label: "######## [next_attempt | accumulator]  ee: "]
'ee'

同样,PrimeFactors.factors_for(12221) 的值会下降:

######## NEXT: : 29
[
  label: <<35, 35, 35, 35, 35, 35, 35, 35, 32, 91, 110, 101, 120, 116, 95, 97,
    116, 116, 101, 109, 112, 116, 32, 124, 32, 97, 99, 99, 117, 109, 117, 108,
    97, 116, 111, 114, 93, 32, 32, 29, 11, 11, 58, 32>>
]
######## NEXT: : 31
[
  label: <<35, 35, 35, 35, 35, 35, 35, 35, 32, 91, 110, 101, 120, 116, 95, 97,
    116, 116, 101, 109, 112, 116, 32, 124, 32, 97, 99, 99, 117, 109, 117, 108,
    97, 116, 111, 114, 93, 32, 32, 31, 11, 11, 58, 32>>
]
######## NEXT: : 33
[label: "######## [next_attempt | accumulator]  !\v\v: "]
######## NEXT: : 35
[label: "######## [next_attempt | accumulator]  #\v\v: "]
...
[label: "######## [next_attempt | accumulator]  a\v\v: "]
######## NEXT: : 99
[label: "######## [next_attempt | accumulator]  c\v\v: "]
######## NEXT: : 101
[label: "######## [next_attempt | accumulator]  e\v\v: "]
'\v\ve'

(我不知道它是否相关,但是在 exercism.com 的 Diffie Hellman 挑战中,我在尝试提升到 33 的幂时也注意到一些奇怪的行为......似乎让我的应用程序陷入无限循环...)

当您将一个整数列表插入一个字符串时,Elixir 假定该列表是一个 "IO data",因此该列表中的整数被视为字符代码。

要解决此问题,您需要替换此行

IO.inspect(label: "######## [next_attempt | accumulator]  #{[next_attempt | accumulator]}: ")

进入这一行

IO.inspect([next_attempt | accumulator], label: "######## [next_attempt | accumulator]", charlists: :as_lists)

选项 charlists: :as_lists 强制 IO.inspect 将字符列表视为整数列表。