I have the following module to find prime factors:
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
For most numbers, it works as expected:
For example, the output for PrimeFactors.factors_for(10200)
ends with:
######## 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]
But with some numbers, the output goes funky.
For example, if I do PrimeFactors.factors_for(10201)
, we notice when it hits next_attempt 33, the output is very unexpected:
######## 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'
Similiarly, the value goes off for 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'
(I don't know if it is relevant, but working exercism.com's Diffie Hellman challenge, I was also noticing some strange behaviour when trying to raise to the power of 33... it seemed to throw my application into an endless loop...)