Conjectura recursiva de Collatz

21

A conjectura de Collatz postula que, se você pegar um número inteiro positivo, repita o seguinte algoritmo várias vezes:

if number is odd, then multiply by three and add one
if number is even, then divide by two

você acabará em 1. Parece sempre funcionar, mas nunca foi provado que sempre funciona.

Você já jogou golfe calculando quanto tempo leva para chegar a 1 , então pensei em mudar um pouco as coisas.

Começando com um número inteiro positivo, calcule quanto tempo leva para chegar a 1 (seu "tempo de parada"). Em seguida, encontre o tempo de parada desse número.

Repita até chegar a 1 ou até chegar ao limite totalmente arbitrário de 100 iterações. No primeiro caso, imprima quantas iterações foram necessárias. No último caso, imprima "Fail" ou outra saída consistente de sua escolha, desde que não seja um número inteiro 1≤n≤100. Você não pode emitir uma sequência vazia para esta opção. A saída de um número inteiro fora do intervalo [1, 100], no entanto, é permitida.

Exemplos:

Input: 2
2->1
Output: 1

Input: 5
5->5->5->5->5->...
Output: Fail

Input: 10
10->6->8->3->7->16->4->2->1
Output: 8

Input: 100
100->25->23->15->17->12->9->19->20->7->16->4->2->1
Output: 13

Input: 10^100
10^100->684->126->108->113->12->9->19->20->7->16->4->2->1
Output: 13

Input: 12345678901234567890
12345678901234567890->286->104->12->9->19->20->7->16->4->2->1
Output: 11

Input: 1
--Depending on your code, one of two things may happen. Both are valid for the purposes of this question.
1
Output: 0
--Or:
1->3->7->16->4->2->1
Output: 6

Conforme calculei 10^100e 12345678901234567890usando um idioma que suporta apenas reais para esse tamanho, se o seu idioma for mais preciso, você poderá obter resultados diferentes para eles.

Pontuação

Como esse é o , a resposta com a menor quantidade de bytes vence.

DonielF
fonte

Respostas:

9

Python 2 , 70 bytes

f=lambda n,k=0,j=0:n-1and-~f(k*[n/2,n*3+1][n%2]or f(j/99or n,1),k,j+1)

Retorna 199 para cem ou mais iterações.

Experimente online!

Dennis
fonte
6

Anexo , 40 bytes

`-&3@`#@PeriodicSteps[CollatzSize@Max&1]

Experimente online!

Esta é uma nova linguagem que eu criei. Eu queria dar um jeito de criar uma linguagem de infix adequada, e este é o resultado: uma imitação do mathematica. Hooray?

Explicação

Esta é uma composição de algumas funções. Essas funções são:

  • PeriodicSteps[CollatzSize@Max&1]Isso gera uma função que aplica seu argumento até que os resultados contenham um elemento duplicado. Esta função, CollatzSize@Max&1está sendo aplicada CollatzSizeà maior entrada e 1, para evitar a entrada inválida 0no CollatSize.
  • `#é um operador citado; quando aplicado monadicamente nesse sentido, obtém o tamanho de seu argumento
  • `-&3é uma função ligada, que vincula o argumento 3à função `-, que é lida como "menos 3". Isso ocorre porque o aplicativo PeriodicSteps gera 0s, que precisam ser contabilizados. (Ele também lida perfeitamente com números fora dos limites, como os 5quais são mapeados -1.)
Conor O'Brien
fonte
1
É realmente permitido usar seu próprio idioma? Você não pode simplesmente criar um idioma para cada codegolf usando apenas alguns bytes?
Tweakimp
2
@Tweakimp É claro que é permitido criar (e usar) seu próprio idioma. Mas modificá-lo para que uma tarefa seja um único comando (após o lançamento do desafio) é uma brecha padrão.
caird coinheringaahing
2
@ Tweakimp, se isso faz você se sentir melhor, eu havia projetado essa função antes de encarar esse desafio. Sou um designer de idiomas, e é isso que faço.
Conor O'Brien
Era mais uma pergunta geral se as linguagens selfmade são permitidas, não uma afirmação negativa de que você usou a sua própria.
Tweakimp
4

J , 49 45 bytes

-4 bytes graças ao código Collatz Sequence mais curto, retirado do comentário de @ randomra aqui .

(2-~[:#(>&1*-:+2&|*+:+>:@-:)^:a:)^:(<101)i.1:

Saídas 101para resultados inválidos.

Experimente online!

Explicação

Sem surpresa, essa explicação ficou rapidamente desatualizada. Vou deixá-lo em termos da antiga resposta de 49 bytes que tive, incluindo abaixo. Se você quiser uma atualização, me avise. A maneira como ele encontra o comprimento da sequência recursiva permanece a mesma, eu acabei de usar um método Collatz Sequence mais curto.

(1-~[:#%&2`(1+3&*)@.(2&|)^:(1&<)^:a:)^:(<101)i.1:

Encontrando o comprimento da sequência Collatz

Esta seção do código é a seguinte

(1-~[:#%&2`(1+3&*)@.(2&|)^:(1&<)^:a:)

Aqui está a explicação:

(1 -~ [: # %&2`(1+3&*)@.(2&|) ^: (1&<) ^: a:)  Given an input n
                                       ^: a:   Apply until convergence, collecting
                                                each result in an array.
                              ^: (1&<)         If n > 1 do the following, else
                                                return n.
                        (2&|)                  Take n mod 2.
           %&2                                 If n mod 2 == 0, divide by 2.
               (1+3&*)                         If n mod 2 == 1, multiply by 3 
                                                and add 1.
         #                                     Get the length of the resulting
                                                array.
 1 -~                                          Subtract 1.

Infelizmente, o verbo apply ( ^:) quando solicitado a armazenar resultados também armazena o valor inicial, então isso significa que estamos (como sempre) afastados por um. Por isso, subtraímos 1.

Encontrando o comprimento da sequência recursiva

(1-~[:#%&2`(1+3&*)@.(2&|)^:(1&<)^:a:) ^: (< 101) i. 1:  Given an input n.
                                      ^: (< 101)        Apply 100 times,
                                                         collecting results
                                                         in an array.
(1-~[:#%&2`(1+3&*)@.(2&|)^:(1&<)^:a:)                   Collatz sequence length.
                                                 i. 1:  Index of first 1 (returns
                                                         101, the length of the
                                                         array if 1 not found).
Cole
fonte
1
Se você não se importa com a seção de cabeçalho, esta vai mostrar talvez mais precisamente a sua resposta
Conor O'Brien
@ ConorO'Brien Eu não sei nada - eu realmente não sabia como formatá-lo como tal (mas vou roubar o seu a partir de agora). Obrigado
cole
1
A n y t i m e!
Conor O'Brien
1
38 bytes com *i.~(<101)1&(#@}.a:2&(<*|{%~,*+1+])])]devem ser equivalentes
milhas
4

C (gcc) , 75 bytes

i,j;f(n){for(j=0;(i=n)&&j++<100;)for(n=0;i-1;++n)i=i&1?i*3+1:i/2;i=!i*j-1;}

Retorna -1para n>=100iterações.

Experimente online!

C (gcc) , 73 bytes

i,j;f(n){for(j=-1;(i=n)&&j++<99;)for(n=0;i-1;++n)i=i&1?i*3+1:i/2;i=!i*j;}

Retorna 0para n>=100iterações.

Experimente online!

Steadybox
fonte
3

JavaScript (ES6), 57 bytes

Retorna truequando falha. Retorna 0para 1.

f=(n,k=i=0)=>n>1?f(n&1?n*3+1:n/2,k+1):k?i>99||f(k,!++i):i

Casos de teste

Arnauld
fonte
Eu sou cético se o seu programa calcular o resultado correto além do estouro / imprecisão ou se o OP derivou seus resultados usando uma linguagem com implementações numéricas semelhantes (presumo que eles não tenham calculado todos os casos de teste manualmente).
Jonathan Frech
@JonathanFrech Indeed. Acontece que ambos os resultados eram igualmente inválidos.
Arnauld
3

APL (Dyalog Unicode) , 39 60 53 52 49 bytes

-3 bytes graças a @ngn

0∘{99<⍺:⋄1=⍵:01+(⍺+1)∇{1=⍵:01+∇⊃⍵⌽0 1+.5 3×⍵}⍵}

Experimente online!

Usa o código @ngn para Collatz, mas usava anteriormente o código de @ Uriel.

Aqui está a versão antiga que não atendeu às especificações:

{1=⍵:01+∇{1=⍵:02|⍵:1+∇1+3×⍵⋄1+∇⍵÷2}⍵}
Zacharý
fonte
2|⍵:1+∇1+3×⍵⋄1+∇⍵÷2->1+∇⊃⍵⌽0 1+.5 3×⍵
ngn
2

Perl 6 , 56 bytes

{($_,{($_,{$_%2??$_*3+1!!$_/2}...1)-1}...1).head(102)-1}

Experimente online!

Retorna 101para uma sequência sem finalização.

Sean
fonte
2

Casca , 21 bytes

←€1↑101¡ȯ←€1¡?½o→*3¦2

Experimente online! Retorna -1na falha, 0na entrada 1.

Explicação

←€1↑101¡ȯ←€1¡?½o→*3¦2  Implicit input (a number).
             ?½o→*3¦2  Collatz function:
             ?     ¦2   if divisible by 2,
              ½         then halve,
               o→*3     else multiply by 3 and increment.
        ȯ←€1¡?½o→*3¦2  Count Collatz steps:
            ¡           iterate Collatz function and collect results in infinite list,
          €1            get 1-based index of 1,
        ȯ←              decrement.
       ¡               Iterate this function on input,
   ↑101                take first 101 values (initial value and 100 iterations),
←€1                    get index of 1 and decrement.
Zgarb
fonte
2

C (gcc) , 70 73 bytes

g(x){x=x-1?g(x%2?3*x+1:x/2)+1:0;}f(x,m){for(m=0;(x=g(x))&&100>m++;);x=m;}

Experimente online!

Retorna 101quando o número de iterações excede 100.


fonte
1
Bem-vindo ao PPCG! Esta resposta não é totalmente válida, porque todos os envios de funções precisam ser reutilizáveis . Eu acho que você pode corrigir isso inserindo m=0no seu f(provavelmente até fazendo uso do forintiailizador atualmente vazio para salvar um a ;).
Martin Ender
2

Limpo , 146 ... 86 bytes

-11 bytes graças a Ørjan Johansen

import StdEnv
?f l n=hd[u\\1<-iterate f n&u<-l]

?(?(\b|isOdd b=3*b+1=b/2)[0..])[0..99]

Como uma função parcial literal.

Experimente online!

Interrompe hd of []se o número de iterações exceder 100.
Sai com Heap Fullentradas acima de ~, a 2^23menos que você especifique um tamanho de heap maior.

Furioso
fonte
1
Estou começando a entender uma sintaxe limpa (como difere de Haskell) de suas respostas ... você pode reduzi-lo com uma função auxiliar j f l n=hd[u\\1<-iterate f n&u<-l].
Ørjan Johansen
@ ØrjanJohansen Obrigado!
Οurous
Você não precisa da \a=...apeça, é caril. (Ou eta reduz.)
Ørjan Johansen
@ ØrjanJohansen oh, perdi isso, obrigado!
Οurous
1

Python 2 , 99 98 97 bytes

  • Salve um byte usando em c and t or fvez de t if c else f.
  • Salva um byte ao enviar em -1vez de fou 'f'para entradas sem interrupção.
exec"f,F="+"lambda n,i=0:n<2and i or %s"*2%("f([n/2,3*n+1][n%2],-~i),","i>99and-1or F(f(n),-~i)")

Experimente online!

Jonathan Frech
fonte
1

BiwaScheme , 151 caracteres

(define(f n i s)(if(= s 0) 'F(if(= n 0)i(f(letrec((c(lambda(m k)(if(= m 1)k(c(if(=(mod m 2)0)(/ m 2)(+(* m 3)1))(+ k 1))))))(c n 0))(+ i 1)(- s 1)))))

Você pode tentar aqui .

Andrea Ciceri
fonte
1

R , 119 107 bytes

Parcialmente usa o código collatz de Jarko Dubbeldam a partir daqui . Retorna 0para> 100 iterações (falha).

pryr::f(x,{N=n=0
while(x-1){while(x-1){x=`if`(x%%2,3*x+1,x/2);n=n+1}
x=n
n=0
N=N+1
if(N==100)return(0)}
N})

Experimente online!

rturnbull
fonte
1

NARS APL, 115 bytes, 63 caracteres

{d←0⋄{⍵=1:d⋄99<d+←1:¯1⋄∇{c←0⋄{1=⍵:c⋄c+←1⋄2∣⍵:∇1+3×⍵⋄∇⍵÷2}⍵}⍵}⍵}

Provavelmente, usando loops, seria mais claro ... Existem 4 funções, 2 aninhadas e ricorsivas, e a primeira apenas para definir e inicializar como = 0, a variável d, vista na 2ª função como um contador de variáveis ​​globais.

q←{c←0⋄{1=⍵:c⋄c+←1⋄2∣⍵:∇1+3×⍵⋄∇⍵÷2}⍵}

Esta 3ª função seria a função que retorna quantas chamadas existem para resolver a conjectura de Collatz por seu argumento

{⍵=1:d⋄99<d+←1:¯1⋄∇q⍵}

Esta é a 2ª função, se tiver seu arg = 1, interrompa sua recursão e retorne d o número de vezes que é chamado de si-1; caso contrário, se ele for chamado mais de 99 vezes, interrompa sua recursão e retornará -1 (falha); caso contrário, calcule a conjectura de Collatz para seu argumento e chama-se pelo valor do comprimento da sequência de Collatz. Para mim, mesmo que tudo isso pareça funcionar, pode ser um grande problema se for definida uma variável global e uma variável em uma função com o mesmo nome, quando o programador a vê como apenas uma variável local.

  f←{d←0⋄{⍵=1:d⋄99<d+←1:¯1⋄∇{c←0⋄{1=⍵:c⋄c+←1⋄2∣⍵:∇1+3×⍵⋄∇⍵÷2}⍵}⍵}⍵}     
  f 2
1
  f 3
5
  f 5
¯1
  f 10
8
  f 100
13
  f 12313
7
  f 1
0
RosLuP
fonte
1

(Emacs, Common, ...) Lisp, 105 bytes

Retorna t para iterações> 100

(defun f(n k c)(or(> c 100)(if(= n 1)(if(= k 0)c(f k 0(1+ c)))(f(if(oddp
n)(+ n n n 1)(/ n 2))(1+ k)c))))

Expandido:

(defun f (n k c)
  (or (> c 100)
      (if (= n 1)
          (if (= k 0) c
            (f k 0 (1+ c)))
        (f (if (oddp n) (+ n n n 1) (/ n 2))
           (1+ k) c))))
(f (read) 0 0)
user84207
fonte