Code Golf: Collatz Conjecture


86

Zainspirowany http://xkcd.com/710/ tutaj jest kod do tego golfa.

Wyzwanie

Mając dodatnią liczbę całkowitą większą niż 0, wydrukuj sekwencję gradobicia dla tej liczby.

Sekwencja gradobicia

Więcej szczegółów można znaleźć w Wikipedii .

  • Jeśli liczba jest parzysta, podziel ją przez dwa.
  • Jeśli liczba jest nieparzysta, potrój ją i dodaj jeden.

Powtarzaj to z liczbą wygenerowaną, aż osiągnie 1. (jeśli będzie kontynuowana po 1, przejdzie w nieskończoną pętlę 1 -> 4 -> 2 -> 1...)

Czasami najlepszym sposobem wyjaśnienia jest kod, więc oto fragment z Wikipedii

function collatz(n)
  show n
  if n > 1
    if n is odd
      call collatz(3n + 1)
    else
      call collatz(n / 2)

Ten kod działa, ale dodaję dodatkowe wyzwanie. Program nie może być podatny na przepełnienia stosu . Musi więc albo używać iteracji, albo rekurencji ogonowej.

Ponadto punkty bonusowe za to, czy potrafi obliczać duże liczby, a język nie ma jeszcze tego zaimplementowanego. (lub jeśli ponownie zaimplementujesz obsługę dużych liczb za pomocą liczb całkowitych o stałej długości)

Przypadek testowy

Number: 21
Results: 21 -> 64 -> 32 -> 16 -> 8 -> 4 -> 2 -> 1

Number: 3
Results: 3 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1

Ponadto kod golfowy musi zawierać pełne dane wejściowe i wyjściowe użytkownika.



20
nie może być podatny na przepełnienie stosu : nie powinieneś był go tutaj publikować! ;)
Felix Kling

51
Moi przyjaciele przestali do mnie dzwonić, czy to oznacza, że ​​rozwiązałem problem?
Martin

18
Jesteś na SO, ale miałeś kiedyś przyjaciół? ... Co to było?
Wyskakuje

5
Odpowiedź asemblera jest fajna, ale wybranie najdłuższej odpowiedzi jest trochę anty-kodowe !
John La Rooy

Odpowiedzi:


129

x86, 1337 znaków

;
; To assemble and link this program, just run:
;
; >> $ nasm -f elf collatz.asm && gcc -o collatz collatz.o
;
; You can then enjoy its output by passing a number to it on the command line:
;
; >> $ ./collatz 123
; >> 123 --> 370 --> 185 --> 556 --> 278 --> 139 --> 418 --> 209 --> 628 --> 314
; >> --> 157 --> 472 --> 236 --> 118 --> 59 --> 178 --> 89 --> 268 --> 134 --> 67
; >> --> 202 --> 101 --> 304 --> 152 --> 76 --> 38 --> 19 --> 58 --> 29 --> 88
; >> --> 44 --> 22 --> 11 --> 34 --> 17 --> 52 --> 26 --> 13 --> 40 --> 20 --> 10
; >> --> 5 --> 16 --> 8 --> 4 --> 2 --> 1
; 
; There's even some error checking involved:
; >> $ ./collatz
; >> Usage: ./collatz NUMBER
;
section .text
global main
extern printf
extern atoi

main:

  cmp dword [esp+0x04], 2
  jne .usage

  mov ebx, [esp+0x08]
  push dword [ebx+0x04]
  call atoi
  add esp, 4

  cmp eax, 0
  je .usage

  mov ebx, eax
  push eax
  push msg

.loop:
  mov [esp+0x04], ebx
  call printf

  test ebx, 0x01
  jz .even

.odd:
  lea ebx, [1+ebx*2+ebx]
  jmp .loop

.even:

  shr ebx, 1
  cmp ebx, 1
  jne .loop

  push ebx
  push end
  call printf

  add esp, 16
  xor eax, eax
  ret

.usage:
  mov ebx, [esp+0x08]
  push dword [ebx+0x00]
  push usage
  call printf
  add esp, 8
  mov eax, 1
  ret

msg db "%d --> ", 0
end db "%d", 10, 0
usage db "Usage: %s NUMBER", 10, 0

27
x86 asm i 1337 znaków. Płaczę z radości.
ZoogieZork

10
Podoba mi się (ab) użycie lea przez 3n + 1.
najwspanialszy

Dziękuję, że nie używasz int 23h.
Mike D.

Jak mogę się zgodzić w Linuksie nie mogę się doczekać, aby go wypróbować
hidroto

64

Befunge

&>:.:1-|
  >3*^ @
  |%2: <
 v>2/>+

2
Powinieneś przeczytać to w 2D. <> ^ v to strzałki, które zmieniają kierunek wędrówki "licznika programu". | i _ są warunkami, które idą w górę / w dół lub w lewo / w prawo w zależności od tego, czy wartość na stosie jest prawdą czy fałszem. Cała „arena kodu” zawija się od góry do dołu i od lewej do prawej.
SF.

I tylko 35 znaków, w tym spacje! Tak ogólnie to nieźle!
Potatoswatter

6
Czy na pewno to nie Perl?
ijw,

52

LOLCODE: 406 CHARAKTERZ

HAI
BTW COLLATZ SOUNDZ JUS LULZ

CAN HAS STDIO?

I HAS A NUMBAR
BTW, I WANTS UR NUMBAR
GIMMEH NUMBAR

VISIBLE NUMBAR

IM IN YR SEQUENZ
  MOD OF NUMBAR AN 2
  BOTH SAEM IT AN 0, O RLY?
    YA RLY, NUMBAR R QUOSHUNT OF NUMBAR AN 2
    NO WAI, NUMBAR R SUM OF PRODUKT OF NUMBAR AN 3 AN 1
  OIC
  VISIBLE NUMBAR
  DIFFRINT 2 AN SMALLR OF 2 AN NUMBAR, O RLY?
    YA RLY, GTFO
  OIC
IM OUTTA YR SEQUENZ

KTHXBYE

TESTD UNDR JUSTIN J. MEZA'S INTERPRETR . KTHXBYE!


51

Python - 95 64 51 46 char

Oczywiście nie powoduje przepełnienia stosu.

n=input()
while n>1:n=(n/2,n*3+1)[n%2];print n

4
Możesz chcieć określić Python 2.x. IIRC, Python 3.x inputnie obsługuje pliku eval.
Mike D.

5
To nie spełnia wymagań - nie drukuje pierwszego numeru
Ben Lings

7
dlaczego jest to akceptowane? nie jest to najkrótszy i nie wypisuje pierwszego numeru
Claudiu

1
Chyba input () echa znaki typu, więc to robi wydrukować pierwszy numer :)
Danko Durbić

17
Możesz wydrukować pierwszą liczbę za jedyne 2 bajty, używającn=input()*2
John La Rooy

23

Perl

Postanowiłem być trochę antykonkurencyjnym i pokazać, jak normalnie zakodowałbyś taki problem w Perlu.
Na końcu znajduje się również 46 (łącznie) wpis do code-golfa.

Te pierwsze trzy przykłady zaczynają się od tego nagłówka.

#! /usr/bin/env perl
use Modern::Perl;
# which is the same as these three lines:
# use 5.10.0;
# use strict;
# use warnings;

while( <> ){
  chomp;
  last unless $_;
  Collatz( $_ );
}
  • Prosta wersja rekurencyjna

    use Sub::Call::Recur;
    sub Collatz{
      my( $n ) = @_;
      $n += 0; # ensure that it is numeric
      die 'invalid value' unless $n > 0;
      die 'Integer values only' unless $n == int $n;
      say $n;
      given( $n ){
        when( 1 ){}
        when( $_ % 2 != 0 ){ # odd
          recur( 3 * $n + 1 );
        }
        default{ # even
          recur( $n / 2 );
        }
      }
    }
    
  • Prosta wersja iteracyjna

    sub Collatz{
      my( $n ) = @_;
      $n += 0; # ensure that it is numeric
      die 'invalid value' unless $n > 0;
      die 'Integer values only' unless $n == int $n;
      say $n;
      while( $n > 1 ){
        if( $n % 2 ){ # odd
          $n = 3 * $n + 1;
        } else { #even
          $n = $n / 2;
        }
        say $n;
      }
    }
    
  • Zoptymalizowana wersja iteracyjna

    sub Collatz{
      my( $n ) = @_;
      $n += 0; # ensure that it is numeric
      die 'invalid value' unless $n > 0;
      die 'Integer values only' unless $n == int $n;
      #
      state @next;
      $next[1] //= 0; # sets $next[1] to 0 if it is undefined
      #
      # fill out @next until we get to a value we've already worked on
      until( defined $next[$n] ){
        say $n;
        #
        if( $n % 2 ){ # odd
          $next[$n] = 3 * $n + 1;
        } else { # even
          $next[$n] = $n / 2;
        }
        #
        $n = $next[$n];
      }
      say $n;
      # finish running until we get to 1
      say $n while $n = $next[$n];
    }
    

Teraz pokażę, jak można zrobić ten ostatni przykład z wersją Perla wcześniejszą niż 5.10.0

#! /usr/bin/env perl
use strict;
use warnings;

while( <> ){
  chomp;
  last unless $_;
  Collatz( $_ );
}
{
  my @next = (0,0); # essentially the same as a state variable
  sub Collatz{
    my( $n ) = @_;
    $n += 0; # ensure that it is numeric
    die 'invalid value' unless $n > 0;

    # fill out @next until we get to a value we've already worked on
    until( $n == 1 or defined $next[$n] ){
      print $n, "\n";

      if( $n % 2 ){ # odd
        $next[$n] = 3 * $n + 1;
      } else { # even
        $next[$n] = $n / 2;
      }
      $n = $next[$n];
    }
    print $n, "\n";

    # finish running until we get to 1
    print $n, "\n" while $n = $next[$n];
  }
}

Reper

Po pierwsze, IO zawsze będzie wolną częścią. Więc jeśli faktycznie przetestowałeś je w stanie, w jakim są, powinieneś uzyskać mniej więcej taką samą prędkość z każdego z nich.

Aby to przetestować, otworzyłem uchwyt pliku do /dev/null( $null) i edytowałem wszystkie, say $naby zamiast tego czytać say {$null} $n. Ma to na celu zmniejszenie zależności od IO.

#! /usr/bin/env perl
use Modern::Perl;
use autodie;

open our $null, '>', '/dev/null';

use Benchmark qw':all';

cmpthese( -10,
{
  Recursive => sub{ Collatz_r( 31 ) },
  Iterative => sub{ Collatz_i( 31 ) },
  Optimized => sub{ Collatz_o( 31 ) },
});

sub Collatz_r{
  ...
  say {$null} $n;
  ...
}
sub Collatz_i{
  ...
  say {$null} $n;
  ...
}
sub Collatz_o{
  ...
  say {$null} $n;
  ...
}

Po uruchomieniu go 10 razy, oto reprezentatywne przykładowe wyjście:

            Oceń cyklicznie iteracyjne zoptymalizowane
Rekursywne 1715 / s - -27% -46%
Iteracyjne 2336 / s 36% - -27%
Zoptymalizowany 3187 / s 86% 36% -

Na koniec prawdziwy wpis dotyczący golfa w kodowaniu:

perl -nlE'say;say$_=$_%2?3*$_+1:$_/2while$_>1'

Łącznie 46 znaków

Jeśli nie musisz drukować wartości początkowej, możesz usunąć 5 dodatkowych znaków.

perl -nE'say$_=$_%2?3*$_+1:$_/2while$_>1'

41 znaków łącznie
31 znaków dla rzeczywistej części kodu, ale kod nie będzie działał bez -nprzełącznika. Więc uwzględniam cały przykład w mojej liczbie.


Twoja zoptymalizowana wersja nie jest.
Motti

@Motti Te przykłady są bardzo zależne od IO. Po wielokrotnym przetestowaniu ich zoptymalizowana wersja zawsze utrzymuje znaczącą przewagę.
Brad Gilbert

@Brad, kiedy uruchamiasz Collatz na jednym numerze, to optymalizacja jest pesymizacją, ponieważ żadna liczba nie powinna pojawić się więcej niż raz (chyba że przypuszczenie jest błędne). Powodem, dla którego widzisz poprawę, jest to, że korzystasz z wielu liczb (jak w przypadku problemu Eulera), w rzeczywistości napisałem wpis na blogu o tym niedawno lanzkron.wordpress.com/2010/01/18/ ...
Motti

2
@Motti to optymalizacja, o której mówiłem. Ponadto w Perlu $i + 1jest zawsze dodatek (odpowiedź na wpis na blogu). Używanie Sub::Call::Recurjest również optymalizacją. W przeciwnym razie użyłbym @_=$n;goto &Collatz. (Jest 10-20% wolniej, jeśli zmienisz state @nextnamy @next
Brad Gilbert,

3
Uważam, że standardy zliczania uderzeń perl golf nie liczą obowiązkowych uderzeń przy wywoływaniu tłumacza ani cudzysłowów, ale liczą po jednym dla każdej flagi obok E. Stosując te reguły, ostatnie wpisy liczą odpowiednio 37 znaków i 32 znaki.
R. Martinho Fernandes

23

Haskell, 62 znaki 63 76 83 , 86 , 97 , 137

c 1=[1]
c n=n:c(div(n`mod`2*(5*n+2)+n)2)
main=readLn>>=print.c

Dane wejściowe użytkownika, wydrukowane dane wyjściowe, używają stałej pamięci i stosu, działają z dowolnie dużymi liczbami całkowitymi.

Przykładowy przebieg tego kodu z 80-cyfrową liczbą wszystkich „jedynek” (!) Jako danych wejściowych jest całkiem fajny.


Oryginalna, tylko funkcjonalna wersja:

Haskell 51 znaków

f n=n:[[],f([n`div`2,3*n+1]!!(n`mod`2))]!!(1`mod`n)

Kto @ & ^ # potrzebuje warunków warunkowych?

(edit: byłem "sprytny" i użyłem poprawki. Bez tego kod spadł do 54 znaków. edit2: spadł do 51 przez wyodrębnienie f())


Po napisaniu mojego posta w Mirandzie (który jest w zasadzie tylko starszym Haskellem), przynajmniej w Mirandzie możesz to skrócić, używając tylko jednego wykrzyknika w każdym - fn = n: [[], [f (n dział 2), f (3 * n + 1)]! (n mod 2)]! (1 mod n) - Działa :)
Derek H

Och, tak, brakuje ci danych wejściowych i wyjściowych.
R. Martinho Fernandes

@Martinho: Ja też, ale dzięki leniwej ocenie tabele są nawet dużo fajniejsze niż w innych językach.
Dario

1
Korzystając z pomysłu jleedeva: c 1=[1];c n=n:(c$div(nmod 2*(5*n+2)+n)2)- 41 znaków, wykorzystuje to fakt, że jest to k * (3n + 1) + (1-k) * n / 2, gdzie k = n mod 2
sdcvc

2
Usunąłem mój drugi wpis i przeniosłem swój kod tutaj i włączyłem jeszcze więcej pomysłów z tych komentarzy. Zwiększono do 76 znaków, ale obsługuje dane wejściowe i wyjściowe.
MtnViewMark

22

Golfscript: 20 znaków

  ~{(}{3*).1&5*)/}/1+`
# 
# Usage: echo 21 | ruby golfscript.rb collatz.gs

Jest to równoważne z

stack<int> s;
s.push(21);
while (s.top() - 1) {
  int x = s.top();
  int numerator = x*3+1;
  int denominator = (numerator&1) * 5 + 1;
  s.push(numerator/denominator);
}
s.push(1);
return s;

2
„musi zawierać pełne dane wejściowe i wyjściowe użytkownika”
F'x

2
@FX, zastępując 21z ~spowoduje, że program użyć numeru z stdin
John La Rooy

@gnibbler: Czy Golfscript.rb jest aktualizowany? Mam (eval):1:in initialize ": metody niezdefiniowanej leftparen' for nil:NilClass (NoMethodError)przy wymianie 21z ~.
kennytm

@KennyTM, Niestety, GolfScript nie może czytać stdin interaktywnie, musisz podłączyć coś do stdin, na przykładecho 21 | ruby golfscript.rb collatz.gs
John La Rooy

19

pne 41 znaków

Myślę, że tego rodzaju problemy bczostały wymyślone dla:

for(n=read();n>1;){if(n%2)n=n*6+2;n/=2;n}

Test:

bc1 -q collatz.bc
21
64
32
16
8
4
2
1

Właściwy kod:

for(n=read();n>1;){if(n%2)n=n*3+1else n/=2;print n,"\n"}

bcobsługuje liczby do INT_MAXcyfr

Edit: artykuł Wikipedia wspomina to hipoteza została sprawdzona dla wszystkich wartości do 20x2 58 (ok. 5.76e18 ). Ten program:

c=0;for(n=2^20000+1;n>1;){if(n%2)n=n*6+2;n/=2;c+=1};n;c

testy 2 20 000 +1 (ok. 3,98e6 020 ) w 68 sekund, 144 404 cykli.


Zmień 'n! = 1' na `n> 1 'dla 54 znaków.
Jerry Coffin

4
Oto wiersz poleceń do generowania losowych liczb o dowolnej długości dla tego wpisu (w tym przypadku 10000 cyfr): cat /dev/urandom | tr -dc '0-9' | head -c 10000 | bc collatz-conjecture.bc
indyw

3
@indiv - musiałem to przetestować :), przetworzenie liczby 10000 cyfr zajęło 3 minuty i 12 sekund. Zapisałem wyjście do pliku, ma około 1,2 GB długości, ale tak, zakończyło się poprawnie w 1. Punkt zabc
Carlos Gutiérrez

16

Perl: 31 znaków

perl -nE 'say$_=$_%2?$_*3+1:$_/2while$_>1'
#         123456789 123456789 123456789 1234567

Edytowano, aby usunąć 2 niepotrzebne spacje.

Edytowano, aby usunąć 1 niepotrzebną spację.


Możesz usunąć dwie niepotrzebne spacje (po powiedzeniu i po chwili)
sorpigal

Spróbuj perl -E 'powiedz $ _ = 10; powiedz $ _ = $ _% 2? $ _ * 3 + 1: $ _ / 2 a $ _> 1'
sorpigal

Pomyślałem, że użytkownik będzie świadomy numeru początkowego sekwencji ;-).
a'r

41
Czasami, gdy napotykam tekst zakodowany w base64, czasami mylę go z kodem źródłowym Perla.
Martin

21
@Martin: Nie wyobrażam sobie, jak to zrobisz. Base64 jest znacznie bardziej czytelny.
Jerry Coffin

15

MS Excel, 35 znaków

=IF(A1/2=ROUND(A1/2,0),A1/2,A1*3+1)

Zaczerpnięte prosto z Wikipedii :

In cell A1, place the starting number.
In cell A2 enter this formula =IF(A1/2=ROUND(A1/2,0),A1/2,A1*3+1) 
Drag and copy the formula down until 4, 2, 1

Wystarczyło skopiować / wkleić formułę 111 razy, aby uzyskać wynik dla liczby początkowej 1000;)


16
Myślę, że jest już za późno, aby zwrócić uwagę, że do tego służy uchwyt napełniania, co? ehow.com/how_2284668_use-fill-handle-microsoft-excel.html :)
Jordan Bieganie

To bardzo przydatna funkcja, o której istnieniu nawet nie wiedziałem. Po prostu skopiowałem pierwszą komórkę, a następnie podświetliłem wszystkie pozostałe komórki i wkleiłem raz.
Lance McNearney

Dowiedziałem się o pasty do powierzchni mniej więcej dziesięć lat po odkryciu uchwytu wypełniania. dane liczbowe.
Jimmy

14

C: 64 znaki

main(x){for(scanf("%d",&x);x>=printf("%d,",x);x=x&1?3*x+1:x/2);}

Z obsługą dużych liczb całkowitych: 431 (konieczne) znaków

#include <stdlib.h>
#define B (w>=m?d=realloc(d,m=m+m):0)
#define S(a,b)t=a,a=b,b=t
main(m,w,i,t){char*d=malloc(m=9);for(w=0;(i=getchar()+2)/10==5;)
B,d[w++]=i%10;for(i=0;i<w/2;i++)S(d[i],d[w-i-1]);for(;;w++){
while(w&&!d[w-1])w--;for(i=w+1;i--;)putchar(i?d[i-1]+48:10);if(
w==1&&*d==1)break;if(*d&1){for(i=w;i--;)d[i]*=3;*d+=1;}else{
for(i=w;i-->1;)d[i-1]+=d[i]%2*10,d[i]/=2;*d/=2;}B,d[w]=0;for(i=0
;i<w;i++)d[i+1]+=d[i]/10,d[i]%=10;}}

Uwaga : nie usuwaj #include <stdlib.h>bez przynajmniej prototypowania malloc / realloc, ponieważ nie będzie to bezpieczne na platformach 64-bitowych (64-bitowe void * zostanie przekonwertowane na 32-bitowe int).

Ten nie był jeszcze intensywnie testowany. Przydałoby się też trochę tłuszczu.


Poprzednie wersje:

main(x){for(scanf("%d",&x);printf("%d,",x),x-1;x=x&1?3*x+1:x/2);} // 66

(usunięto 12 znaków, ponieważ nikt nie postępuje zgodnie z formatem wyjściowym ...: |)


12

Kolejna wersja asemblera. Ten nie jest ograniczony do liczb 32-bitowych, może obsługiwać liczby do 10 65534, chociaż format „.com” używany przez MS-DOS jest ograniczony do liczb 80-cyfrowych. Napisany dla asemblera A86 i wymaga do działania boxu Win-XP DOS. Składa się do 180 bajtów:

    mov ax,cs
    mov si,82h
    add ah,10h
    mov es,ax
    mov bh,0
    mov bl,byte ptr [80h]
    cmp bl,1
    jbe ret
    dec bl
    mov cx,bx
    dec bl
    xor di,di
 p1:lodsb
    sub al,'0'
    cmp al,10
    jae ret
    stosb
    loop p1
    xor bp,bp
    push es
    pop ds
 p2:cmp byte ptr ds:[bp],0
    jne p3
    inc bp
    jmp p2
    ret
 p3:lea si,[bp-1]
    cld
 p4:inc si
    mov dl,[si]
    add dl,'0'
    mov ah,2
    int 21h
    cmp si,bx
    jne p4
    cmp bx,bp
    jne p5
    cmp byte ptr [bx],1
    je ret
 p5:mov dl,'-'
    mov ah,2
    int 21h
    mov dl,'>'
    int 21h
    test byte ptr [bx],1
    jz p10
    ;odd
    mov si,bx
    mov di,si
    mov dx,3
    dec bp
    std
 p6:lodsb
    mul dl
    add al,dh
    aam
    mov dh,ah
    stosb
    cmp si,bp
    jnz p6
    or dh,dh
    jz p7
    mov al,dh
    stosb
    dec bp
 p7:mov si,bx
    mov di,si
 p8:lodsb
    inc al
    xor ah,ah
    aaa
    stosb
    or ah,ah
    jz p9
    cmp si,bp
    jne p8
    mov al,1
    stosb
    jmp p2
 p9:inc bp
    jmp p2
    p10:mov si,bp
    mov di,bp
    xor ax,ax
p11:lodsb
    test ah,1
    jz p12
    add al,10
p12:mov ah,al
    shr al,1
    cmp di,bx
    stosb
    jne p11
    jmp p2

10

dc - 24 znaki 25 28

dc jest dobrym narzędziem dla tej sekwencji:

?[d5*2+d2%*+2/pd1<L]dsLx
dc -f collatz.dc
21
64
32
16
8
4
2
1

Również 24 znaki według wzoru z wpisu Golfscript :

?[3*1+d2%5*1+/pd1<L]dsLx

57 znaków do spełnienia specyfikacji:

[Number: ]n?[Results: ]ndn[d5*2+d2%*+2/[ -> ]ndnd1<L]dsLx
dc -f collatz-spec.dc
Numer 3
Wyniki: 3 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1

9

Schemat: 72

(define(c n)(if(= n 1)`(1)(cons n(if(odd? n)(c(+(* n 3)1))(c(/ n 2))))))

Używa rekurencji, ale wywołania są rekurencyjne, więc myślę, że zostaną zoptymalizowane pod kątem iteracji. W niektórych szybkich testach nie udało mi się znaleźć liczby, dla której i tak stos się przepełnia. Na przykład:

(C 9876543219999999999000011234567898888777766665555444433332222 7777777777777777777777777777777798797657657651234143375987342987 5398709812374982529830983743297432985230985739287023987532098579 058095873098753098370938753987)

... działa dobrze. [to wszystko jeden numer - właśnie złamałem go, żeby zmieścił się na ekranie.]


8

Mathematica 45 50 znaki

c=NestWhileList[If[OddQ@#,3#+1,#/2]&,#,#>1&]&

Naliczyłem 58 znaków. I można wymienić OddQ[#]z OddQ@#zaoszczędzić 1 char.
kennytm

2
50 znaków:c[n_]:=NestWhileList[If[OddQ@#,3#+1,#/2]&,n,#>1&]
Michael Pilat

7

Ruby, 50 znaków, brak przepełnienia stosu

Zasadniczo bezpośrednie ripowanie rozwiązania Python firmy Makapuf :

def c(n)while n>1;n=n.odd?? n*3+1: n/2;p n end end

Ruby, 45 znaków, przepełni się

Zasadniczo bezpośrednie ripowanie kodu podanego w pytaniu:

def c(n)p n;n.odd?? c(3*n+1):c(n/2)if n>1 end

Jaka to wersja Rubiego? Nie jestem n.odd??zdefiniowany. Jest to również podatne na przepełnienie stosu z dużymi liczbami.
Earlz

To interesujące. Mam 1.8.7. Dodanie spacji między znakami zapytania powinno to naprawić. Masz rację co do przepełnienia stosu. Zmienię odpowiedź, aby to zanotować.
Jordan Bieganie

3
Możesz uratować cztery postacie dziękip n=[n/2,n*3+1][n%2]
Wayne Conrad

7
import java.math.BigInteger;
public class SortaJava {

    static final BigInteger THREE = new BigInteger("3");
    static final BigInteger TWO = new BigInteger("2");

    interface BiFunc<R, A, B> {
      R call(A a, B b);
    }

    interface Cons<A, B> {
      <R> R apply(BiFunc<R, A, B> func);
    }

    static class Collatz implements Cons<BigInteger, Collatz> {
      BigInteger value;
      public Collatz(BigInteger value) { this.value = value; }
      public <R> R apply(BiFunc<R, BigInteger, Collatz> func) {
        if(BigInteger.ONE.equals(value))
          return func.call(value, null);
        if(value.testBit(0))
          return func.call(value, new Collatz((value.multiply(THREE)).add(BigInteger.ONE)));
        return func.call(value, new Collatz(value.divide(TWO)));
      }
    }

    static class PrintAReturnB<A, B> implements BiFunc<B, A, B> {
      boolean first = true;
      public B call(A a, B b) {
        if(first)
          first = false;
        else
          System.out.print(" -> ");
        System.out.print(a);
        return b;
      }
    }

    public static void main(String[] args) {
      BiFunc<Collatz, BigInteger, Collatz> printer = new PrintAReturnB<BigInteger, Collatz>();
      Collatz collatz = new Collatz(new BigInteger(args[0]));
      while(collatz != null)
        collatz = collatz.apply(printer);
    }
}

50
Java: język, w którym musisz używać BigIntegers tylko po to, aby policzyć liczbę znaków w kodzie rozwiązania.
Jared Updike,

3
@Jared Całkowicie zgadzam się, że Java jest gadatliwa. Trzeba przyznać, że przedstawione rozwiązanie a) spełnia wymagania b) jest znacznie dłuższe niż jest to naprawdę konieczne oraz c) przyjemnie bawi się systemem typów java
wowest

7

Python 45 Char

Zgoliłem węgiel z odpowiedzi makapufa.

n=input()
while~-n:n=(n/2,n*3+1)[n%2];print n

bardzo sprytne użycie operatora ~. Musiałem to sprawdzić, aby zobaczyć, co robi (staram się unikać operatorów binarnych w Pythonie, więc nie jestem z nimi zbyt zaznajomiony).
Ponkadoodle

5

TI-BASIC

Nie najkrótsze, ale nowatorskie podejście. Z pewnością znacznie zwolni przy dużych sekwencjach, ale nie powinno się przepełniać.

PROGRAM:COLLATZ
:ClrHome
:Input X
:Lbl 1
:While X≠1
:If X/2=int(X/2)
:Then
:Disp X/2→X
:Else
:Disp X*3+1→X
:End
:Goto 1
:End

4

Haskell: 50

c 1=[1];c n=n:(c$if odd n then 3*n+1 else n`div`2)

Korzystanie z pomysłu JKFF: c 1=[1];c n=n:(c$[nDiv 2,3*n+1]!!(nMod 2)), 44 znaki
sdcvc

4

nie najkrótsze, ale eleganckie rozwiązanie garderoby

(defn collatz [n]
 (print n "")
 (if (> n 1)
  (recur
   (if (odd? n)
    (inc (* 3 n))
    (/ n 2)))))

4

C #: 216 znaków

using C=System.Console;class P{static void Main(){var p="start:";System.Action<object> o=C.Write;o(p);ulong i;while(ulong.TryParse(C.ReadLine(),out i)){o(i);while(i > 1){i=i%2==0?i/2:i*3+1;o(" -> "+i);}o("\n"+p);}}}

w długiej formie:

using C = System.Console;
class P
{
    static void Main()
    {
        var p = "start:"; 
        System.Action<object> o = C.Write; 
        o(p); 
        ulong i; 
        while (ulong.TryParse(C.ReadLine(), out i))
        {
            o(i); 
            while (i > 1)
            {
                i = i % 2 == 0 ? i / 2 : i * 3 + 1; 
                o(" -> " + i);
            } 
            o("\n" + p);
        }
    }
}

Nowa wersja, akceptuje jeden numer jako dane wejściowe podane w wierszu poleceń, bez sprawdzania poprawności danych wejściowych. 173 154 znaków.

using System;class P{static void Main(string[]a){Action<object>o=Console.Write;var i=ulong.Parse(a[0]);o(i);while(i>1){i=i%2==0?i/2:i*3+1;o(" -> "+i);}}}

w długiej formie:

using System;
class P
{
    static void Main(string[]a)
    {
        Action<object>o=Console.Write;
        var i=ulong.Parse(a[0]);
        o(i);
        while(i>1)
        {
            i=i%2==0?i/2:i*3+1;
            o(" -> "+i);
        }
    }
}

Jestem w stanie ogolić kilka postaci, wyrywając pomysł z tej odpowiedzi, aby użyć pętli for zamiast chwili. 150 znaków.

using System;class P{static void Main(string[]a){Action<object>o=Console.Write;for(var i=ulong.Parse(a[0]);i>1;i=i%2==0?i/2:i*3+1)o(i+" -> ");o(1);}}

Należy wspomnieć, że Twój kod akceptuje więcej niż jedno wejście. Lub usuń to i zgol kilka znaków.
R. Martinho Fernandes

Możesz skrócić Action <object> i być może bardziej dynamiczny w C # 4.
Dykam

@Dykam: Właśnie to sprawdziłem: nie powiodło się i wystąpił „błąd CS0428: nie można przekonwertować grupy metod„ Zapis ”na typ„ dynamiczny ”nie będący delegatem. Czy zamierzałeś wywołać metodę?”.
R. Martinho Fernandes

Och, oczywiście ... niejawna konwersja na delegatów ... wymaga oznaczenia delegata. Bummer ...
Dykam

4

Ruby, 43 znaki

bignum obsługiwane, z podatnością na przepełnienie stosu:

def c(n)p n;n%2>0?c(3*n+1):c(n/2)if n>1 end

... i 50 znaków, obsługiwane bignum, bez przepełnienia stosu:

def d(n)while n>1 do p n;n=n%2>0?3*n+1:n/2 end end

Uznanie dla Jordanii. Nie wiedziałem o „p” jako zamienniku puts.


4

nroff 1

Biegnij z nroff -U hail.g

.warn
.pl 1
.pso (printf "Enter a number: " 1>&2); read x; echo .nr x $x
.while \nx>1 \{\
.  ie \nx%2 .nr x \nx*3+1
.  el .nr x \nx/2
\nx
.\}

1. wersja groffa


2
Straszny! Mimo to przynajmniej wyjście powinno być ładnie sformatowane.
Jonathan Leffler

3
Hej, uruchom go jako, groff -U hail.ga otrzymasz PostScript! :-)
DigitalRoss

4

Scala + Scalaz

import scalaz._
import Scalaz._
val collatz = 
   (_:Int).iterate[Stream](a=>Seq(a/2,3*a+1)(a%2)).takeWhile(1<) // This line: 61 chars

I w akcji:

scala> collatz(7).toList
res15: List[Int] = List(7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2)

Scala 2.8

val collatz = 
   Stream.iterate(_:Int)(a=>Seq(a/2,3*a+1)(a%2)).takeWhile(1<) :+ 1

Obejmuje to również końcowe 1.

scala> collatz(7)
res12: scala.collection.immutable.Stream[Int] = Stream(7, 22, 11, 34, 17, 52, 26, 13, 40, 20, 10, 5, 16, 8, 4, 2, 1)

Z następującym niejawnym

implicit def intToEven(i:Int) = new {
  def ~(even: Int=>Int, odd: Int=>Int) = { 
    if (i%2==0) { even(i) } else { odd(i) }
  }
}

można to skrócić do

val collatz = Stream.iterate(_:Int)(_~(_/2,3*_+1)).takeWhile(1<) :+ 1

Edycja - 58 znaków (w tym wejście i wyjście, ale bez numeru początkowego)

var n=readInt;while(n>1){n=Seq(n/2,n*3+1)(n%2);println(n)}

Można zmniejszyć o 2, jeśli nie potrzebujesz nowych linii ...


3

F #, 90 znaków

let c=Seq.unfold(function|n when n<=1->None|n when n%2=0->Some(n,n/2)|n->Some(n,(3*n)+1))

> c 21;;
val it : seq<int> = seq [21; 64; 32; 16; ...]

Lub jeśli nie używasz F # interaktywnego do wyświetlania wyniku, 102 znaki:

let c=Seq.unfold(function|n when n<=1->None|n when n%2=0->Some(n,n/2)|n->Some(n,(3*n)+1))>>printf"%A"

3

Common Lisp, 141 znaków:

(defun c ()
  (format t"Number: ")
  (loop for n = (read) then (if(oddp n)(+ 1 n n n)(/ n 2))
     until (= n 1)
     do (format t"~d -> "n))
  (format t"1~%"))

Testowe uruchomienie:

Number: 171
171 -> 514 -> 257 -> 772 -> 386 -> 193 -> 580 -> 290 -> 145 -> 436 ->
218 -> 109 -> 328 -> 164 -> 82 -> 41 -> 124 -> 62 -> 31 -> 94 -> 47 ->
142 -> 71 -> 214 -> 107 -> 322 -> 161 -> 484 -> 242 -> 121 -> 364 ->
182 -> 91 -> 274 -> 137 -> 412 -> 206 -> 103 -> 310 -> 155 -> 466 ->
233 -> 700 -> 350 -> 175 -> 526 -> 263 -> 790 -> 395 -> 1186 -> 593 ->
1780 -> 890 -> 445 -> 1336 -> 668 -> 334 -> 167 -> 502 -> 251 -> 754 ->
377 -> 1132 -> 566 -> 283 -> 850 -> 425 -> 1276 -> 638 -> 319 ->
958 -> 479 -> 1438 -> 719 -> 2158 -> 1079 -> 3238 -> 1619 -> 4858 ->
2429 -> 7288 -> 3644 -> 1822 -> 911 -> 2734 -> 1367 -> 4102 -> 2051 ->
6154 -> 3077 -> 9232 -> 4616 -> 2308 -> 1154 -> 577 -> 1732 -> 866 ->
433 -> 1300 -> 650 -> 325 -> 976 -> 488 -> 244 -> 122 -> 61 -> 184 ->
92 -> 46 -> 23 -> 70 -> 35 -> 106 -> 53 -> 160 -> 80 -> 40 -> 20 ->
10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1 

Prawie. Nie ma nagłówka dla drugiej linii. Mogłem zgolić 3 znaki ignorując strzałkę, kolejne 3-4 eliminując niepotrzebne spacje, ale jestem zadowolony z wielokrotności 3.
Vatine

3

Program frm Jerry Coffin ma przepełnienie liczb całkowitych, spróbuj tego:

#include <iostream>

int main(unsigned long long i)
{
    int j = 0;
    for(  std::cin>>i; i>1; i = i&1? i*3+1:i/2, ++j)
        std::cout<<i<<" -> ";

    std::cout<<"\n"<<j << " iterations\n";
}

testowane z

Liczba poniżej 100 milionów z najdłuższym łącznym czasem zatrzymania to 63728127, z 949 krokami.

Liczba poniżej 1 miliarda z najdłuższym całkowitym czasem zatrzymania to 670 617 279, z 986 krokami.


Żadne skończone typy liczb całkowitych nie mogą zapobiec przepełnieniu liczb całkowitych. Nawet nie unsigned long long.
kennytm

3

ruby, 43 lata, prawdopodobnie spełniający wymagania we / wy


Biegnij z ruby -n hail

n=$_.to_i
(n=n%2>0?n*3+1: n/2
p n)while n>1

3

C #: 659 znaków z obsługą BigInteger

using System.Linq;using C=System.Console;class Program{static void Main(){var v=C.ReadLine();C.Write(v);while(v!="1"){C.Write("->");if(v[v.Length-1]%2==0){v=v.Aggregate(new{s="",o=0},(r,c)=>new{s=r.s+(char)((c-48)/2+r.o+48),o=(c%2)*5}).s.TrimStart('0');}else{var q=v.Reverse().Aggregate(new{s="",o=0},(r, c)=>new{s=(char)((c-48)*3+r.o+(c*3+r.o>153?c*3+r.o>163?28:38:48))+r.s,o=c*3+r.o>153?c*3+r.o>163?2:1:0});var t=(q.o+q.s).TrimStart('0').Reverse();var x=t.First();q=t.Skip(1).Aggregate(new{s=x>56?(x-57).ToString():(x-47).ToString(),o=x>56?1:0},(r,c)=>new{s=(char)(c-48+r.o+(c+r.o>57?38:48))+r.s,o=c+r.o>57?1:0});v=(q.o+q.s).TrimStart('0');}C.Write(v);}}}

Ungolfed

using System.Linq;
using C = System.Console;
class Program
{
    static void Main()
    {
        var v = C.ReadLine();
        C.Write(v);
        while (v != "1")
        {
            C.Write("->");
            if (v[v.Length - 1] % 2 == 0)
            {
                v = v
                    .Aggregate(
                        new { s = "", o = 0 }, 
                        (r, c) => new { s = r.s + (char)((c - 48) / 2 + r.o + 48), o = (c % 2) * 5 })
                    .s.TrimStart('0');
            }
            else
            {
                var q = v
                    .Reverse()
                    .Aggregate(
                        new { s = "", o = 0 }, 
                        (r, c) => new { s = (char)((c - 48) * 3 + r.o + (c * 3 + r.o > 153 ? c * 3 + r.o > 163 ? 28 : 38 : 48)) + r.s, o = c * 3 + r.o > 153 ? c * 3 + r.o > 163 ? 2 : 1 : 0 });
                var t = (q.o + q.s)
                    .TrimStart('0')
                    .Reverse();
                var x = t.First();
                q = t
                    .Skip(1)
                    .Aggregate(
                        new { s = x > 56 ? (x - 57).ToString() : (x - 47).ToString(), o = x > 56 ? 1 : 0 }, 
                        (r, c) => new { s = (char)(c - 48 + r.o + (c + r.o > 57 ? 38 : 48)) + r.s, o = c + r.o > 57 ? 1 : 0 });
                v = (q.o + q.s)
                    .TrimStart('0');
            }
            C.Write(v);
        }
    }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.