Code Golf: Collatz Conjecture


86

Terinspirasi oleh http://xkcd.com/710/ berikut ini adalah kode golf untuk itu.

Tantangan

Diberikan bilangan bulat positif yang lebih besar dari 0, cetak urutan batu es untuk nomor itu.

Urutan Hailstone

Lihat Wikipedia untuk detail lebih lanjut ..

  • Jika angkanya genap, bagi dengan dua.
  • Jika angkanya ganjil, tiga kali lipat dan tambahkan satu.

Ulangi ini dengan angka yang dihasilkan hingga mencapai 1. (jika berlanjut setelah 1, itu akan masuk dalam putaran tak terbatas 1 -> 4 -> 2 -> 1...)

Terkadang kode adalah cara terbaik untuk menjelaskan, jadi ini beberapa dari Wikipedia

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

Kode ini berfungsi, tetapi saya menambahkan tantangan tambahan. Program tidak boleh rentan terhadap luapan tumpukan . Jadi itu harus menggunakan iterasi atau rekursi ekor.

Juga, poin bonus jika dapat menghitung angka besar dan bahasanya belum diterapkan. (atau jika Anda menerapkan kembali dukungan angka besar menggunakan bilangan bulat panjang tetap)

Kasus cobaan

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

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

Juga, kode golf harus menyertakan input dan output pengguna secara penuh.



20
tidak boleh rentan terhadap luapan tumpukan : Anda seharusnya tidak mempostingnya di sini! ;)
Felix Kling

51
Teman-teman saya berhenti menelepon saya, apakah itu berarti saya menyelesaikan masalah?
Martin

18
Anda menggunakan SO, tetapi pernah punya teman? ... seperti apa itu?
Muncul

5
Jawaban assembler keren, tapi agak anti-code-golf untuk memilih jawaban terpanjang !
John La Rooy

Jawaban:


129

perakitan x86, 1337 karakter

;
; 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 dan 1337 karakter. Saya menangis dengan gembira.
ZoogieZork

10
Saya suka penggunaan lea (ab) untuk 3n + 1.
wowest

Terima kasih telah tidak menggunakan int 23h.
Mike D.

bagaimana cara saya patuh di linux tidak sabar untuk mencobanya
hidroto

64

Befunge

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

2
Anda harus membaca ini dalam 2D. <> ^ v adalah panah yang mengubah arah pengembaraan "penghitung program". | dan _ adalah kondisional yang naik / turun atau kiri / kanan tergantung pada apakah nilai pada stack benar atau salah. Seluruh "arena kode" membungkus melalui atas-bawah dan kiri-kanan.
SF.

Dan hanya 35 karakter termasuk spasi! Tidak buruk sama sekali!
Potatoswatter

6
Apakah Anda yakin itu bukan 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 INTERPRETR JUSTIN J. MEZA . KTHXBYE!


51

Python - 95 64 51 46 karakter

Jelas tidak menghasilkan stack overflow.

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

4
Anda mungkin ingin menentukan Python 2.x. IIRC, Python 3.x inputtidak melakukan eval.
Mike D.

5
Ini tidak memenuhi persyaratan - tidak mencetak nomor pertama
Ben Lings

7
mengapa ini diterima? ini bukan yang terpendek dan tidak mencetak nomor pertama
Claudiu

1
Saya kira input () menggemakan karakter yang Anda ketik, jadi ini mencetak angka pertama :)
Danko Durbić

17
Anda dapat mencetak nomor pertama dengan biaya hanya 2 byte dengan menggunakann=input()*2
John La Rooy

23

Perl

Saya memutuskan untuk menjadi sedikit anti persaingan, dan menunjukkan bagaimana Anda biasanya mengkodekan masalah seperti itu di Perl.
Ada juga entri golf kode karakter 46 (total) di akhir.

Tiga contoh pertama ini semuanya dimulai dengan tajuk ini.

#! /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( $_ );
}
  • Versi rekursif sederhana

    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 );
        }
      }
    }
    
  • Versi iteratif sederhana

    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;
      }
    }
    
  • Versi iteratif yang dioptimalkan

    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];
    }
    

Sekarang saya akan menunjukkan bagaimana Anda akan melakukan contoh terakhir dengan versi Perl sebelum v5.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];
  }
}

Tolok ukur

Pertama, IO akan selalu menjadi bagian yang lambat. Jadi, jika Anda benar-benar membandingkannya apa adanya, Anda harus mendapatkan kecepatan yang sama dari masing-masing.

Untuk mengujinya, saya membuka pegangan file ke /dev/null( $null), dan mengedit setiap file say $nuntuk dibaca say {$null} $n. Ini untuk mengurangi ketergantungan pada 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;
  ...
}

Setelah menjalankannya 10 kali, berikut adalah contoh keluaran yang representatif:

            Nilai Recursive Iterative Optimized
Rekursif 1715 / s - -27% -46%
Iteratif 2336 / s 36% - -27%
Dioptimalkan 3187 / s 86% 36% -

Akhirnya, entri kode-golf nyata:

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

46 total karakter

Jika Anda tidak perlu mencetak nilai awal, Anda dapat menghapus 5 karakter lagi.

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

41 karakter total
31 karakter untuk bagian kode sebenarnya, tetapi kode tidak akan berfungsi tanpa -nsakelar. Jadi saya memasukkan seluruh contoh dalam hitungan saya.


Versi Anda yang dioptimalkan, tidak.
Motti

@Motti Contoh-contoh ini sangat bergantung pada IO. Setelah mengujinya beberapa kali, versi yang dioptimalkan selalu mempertahankan keunggulan yang signifikan.
Brad Gilbert

@Brad, ketika Anda menjalankan Collatz pada satu nomor maka optimasinya adalah sebuah pesimisasi karena tidak ada nomor yang muncul lebih dari sekali (kecuali jika dugaannya salah). Alasan Anda melihat peningkatan adalah karena Anda menjalankan banyak angka (seperti dalam masalah Euler), sebenarnya saya menulis posting blog tentang ini baru-baru ini lanzkron.wordpress.com/2010/01/18/…
Motti

2
@Motti itulah pengoptimalan yang saya bicarakan. Juga, di Perl $i + 1adalah selalu Selain (respon ke entri blog). Juga menggunakan Sub::Call::Recurjuga merupakan optimasi. Kalau tidak, saya akan menggunakan @_=$n;goto &Collatz. (Ini 10-20% lebih lambat jika Anda mengubah state @nextkemy @next
Brad Gilbert

3
Saya percaya standar penghitungan pukulan golf perl tidak menghitung pukulan wajib untuk memanggil juru bahasa atau tanda kutip, tetapi menghitung satu untuk setiap bendera di samping E. Menggunakan aturan tersebut, entri terakhir Anda menghitung masing-masing 37 karakter dan 32 karakter.
R. Martinho Fernandes

23

Haskell, 62 karakter 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

Input pengguna, output tercetak, menggunakan memori dan tumpukan konstan, bekerja dengan bilangan bulat besar yang sewenang-wenang.

Contoh kode ini, diberi nomor 80 digit dari semua '1 (!) Sebagai masukan, cukup menyenangkan untuk dilihat.


Asli, versi hanya fungsi:

Haskell 51 karakter

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

Siapa @ & ^ # yang membutuhkan persyaratan?

(edit: Saya menjadi "pintar" dan menggunakan perbaikan. Tanpa itu, kode turun menjadi 54 karakter. edit2: turun menjadi 51 dengan memfaktorkan keluar f())


Setelah melakukan posting Miranda saya (yang pada dasarnya hanya Haskell yang lebih tua), setidaknya di Miranda Anda dapat memotongnya hanya dengan menggunakan satu tanda seru masing-masing - fn = n: [[], [f (n div 2), f (3 * n + 1)]! (n mod 2)]! (1 mod n) - Bekerja :)
Derek H

Oh ya, Anda melewatkan masukan dan keluaran.
R. Martinho Fernandes

@Martinho: Saya juga, tetapi berkat evaluasi malas, tabel bahkan jauh lebih keren daripada dalam bahasa lain.
Dario

1
Menggunakan ide jleedev: c 1=[1];c n=n:(c$div(nmod 2*(5*n+2)+n)2)- 41 karakter, ini menggunakan fakta bahwa ini adalah k * (3n + 1) + (1-k) * n / 2 di mana k = n mod 2
sdcvvc

2
Saya menghapus entri saya yang lain, dan memindahkan kode saya ke sini, dan memasukkan lebih banyak lagi ide dari komentar ini. Meningkat menjadi 76 karakter, tetapi melakukan input dan output.
MtnViewMark

22

Script golf: 20 karakter

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

Ini sama dengan

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
"harus menyertakan input dan output pengguna penuh"
F'x

2
@FX, mengganti 21dengan ~akan menyebabkan program menggunakan nomor dari stdin
John La Rooy

@gnibbler: Apakah Golfscript.rb diperbarui? Saya mendapat (eval):1:in inisialisasi ': metode tidak ditentukan leftparen' for nil:NilClass (NoMethodError)saat mengganti 21dengan ~.
kennytm

@KennyTM, Sayangnya GolfScript tidak dapat membaca stdin secara interaktif Anda harus memasukkan sesuatu ke dalam stdin, sepertiecho 21 | ruby golfscript.rb collatz.gs
John La Rooy

19

bc 41 karakter

Saya kira masalah seperti bcinilah yang diciptakan untuk:

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

Uji:

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

Kode yang tepat:

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

bcmenangani angka hingga INT_MAXdigit

Edit: The artikel Wikipedia menyebutkan dugaan ini telah diperiksa untuk semua nilai hingga 20X2 58 (aprox. 5.76e18 ). Program ini:

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

menguji 2 20.000 +1 (aprox. 3.98e6.020 ) dalam 68 detik, 144.404 siklus.


Ubah 'n! = 1' menjadi `n> 1 'untuk 54 karakter.
Jerry Coffin

4
Berikut adalah baris perintah untuk membuat angka panjang acak acak untuk entri ini (dalam kasus ini 10.000 digit): cat /dev/urandom | tr -dc '0-9' | head -c 10000 | bc collatz-conjecture.bc
indiv

3
@ indiv - Saya harus mengujinya :), butuh 3 menit dan 12 detik untuk memproses 10.000 digit angka. Saya menyimpan output ke file, panjangnya sekitar 1.2gb, tapi ya selesai dengan benar di 1. Poin untukbc
Carlos Gutiérrez

16

Perl: 31 karakter

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

Diedit untuk menghapus 2 spasi yang tidak perlu.

Diedit untuk menghapus 1 ruang yang tidak perlu.


Anda dapat menghapus dua spasi yang tidak perlu (setelah katakan dan setelah sementara)
sorpigal

Coba perl -E 'say $ _ = 10; say $ _ = $ _% 2? $ _ * 3 + 1: $ _ / 2 sementara $ _> 1'
sorpigal

Saya pikir bahwa pengguna akan mengetahui nomor awal dari urutan ;-).
a'r

41
Kadang-kadang ketika saya menemukan teks yang dikodekan base64, saya terkadang salah mengira itu untuk kode sumber Perl.
Martin

21
@ Martin: Saya tidak bisa membayangkan bagaimana Anda akan melakukan itu. Base64 jauh lebih mudah dibaca.
Jerry Coffin

15

MS Excel, 35 karakter

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

Diambil langsung dari Wikipedia :

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

Hanya perlu menyalin / menempel rumus 111 kali untuk mendapatkan hasil untuk angka awal 1000.;)


16
Saya kira sudah terlambat bagi saya untuk menunjukkan bahwa untuk apa gagang isian itu, ya? ehow.com/how_2284668_use-fill-handle-microsoft-excel.html :)
Jordan Menjalankan

Itu adalah fitur yang sangat berguna yang saya bahkan tidak tahu ada. Saya baru saja menyalin sel pertama dan kemudian menyorot semua sel lainnya dan menempelkan sekali.
Lance McNearney

Saya belajar tentang pasta-area kira-kira sepuluh tahun setelah saya menemukan pegangan isian. angka.
Jimmy

14

C: 64 karakter

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

Dengan dukungan integer besar: 431 karakter (perlu)

#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;}}

Catatan : Jangan dilepas#include <stdlib.h> tanpa setidaknya membuat prototipe malloc / realloc, karena hal itu tidak akan aman di platform 64-bit (64-bit void * akan diubah menjadi int 32-bit).

Yang ini belum diuji dengan kuat. Ini bisa menggunakan beberapa shortening juga.


Versi sebelumnya:

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

(menghapus 12 karakter karena tidak ada yang mengikuti format keluaran ...: |)


12

Versi assembler lain. Yang ini tidak terbatas pada angka 32 bit, ini dapat menangani angka hingga 10 65534 meskipun format ".com" yang digunakan MS-DOS terbatas pada angka 80 digit. Ditulis untuk assembler A86 dan membutuhkan kotak DOS Win-XP untuk dijalankan. Merakit hingga 180 byte:

    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 karakter 25 28

dc adalah alat yang bagus untuk urutan ini:

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

Juga 24 karakter menggunakan rumus dari entri Golfscript :

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

57 karakter untuk memenuhi spesifikasi:

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

9

Skema: 72

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

Ini menggunakan rekursi, tetapi panggilannya rekursif-ekor jadi saya pikir mereka akan dioptimalkan untuk iterasi. Dalam beberapa pengujian cepat, saya belum dapat menemukan nomor yang tumpukannya melimpah. Misalnya saja:

(c 9876543219999999999000011234567898888777766665555444433332222 777777777777777777777777777777777798797657657651234143375987342987 539870981237498252983098374329743298523099880983743297432985230938857398787308523852309387539878530853375987342987 539870981237498252983098374329743298523093885739878785238523093875398785

... berjalan dengan baik. [Itu semua adalah satu angka - Saya baru saja memecahkannya agar muat di layar.]


8

Mathematica, 45 50 karakter

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

Saya menghitung 58 karakter. Dan Anda bisa menggantinya OddQ[#]dengan OddQ@#menghemat 1 karakter.
kennytm

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

7

Ruby, 50 karakter, tidak ada stack overflow

Pada dasarnya rip langsung dari solusi Python makapuf :

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

Ruby, 45 karakter, akan meluap

Pada dasarnya rip langsung dari kode yang diberikan dalam pertanyaan:

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

Versi Ruby apa itu? Saya n.odd??tidak didefinisikan. Juga, itu rentan terhadap tumpukan overflows dengan jumlah yang besar.
Earlz

Itu menarik. Saya memiliki 1.8.7. Menambahkan spasi di antara tanda tanya harus memperbaikinya. Dan Anda benar tentang stack overflow. Saya akan mengedit jawaban saya untuk mencatatnya.
Jordan Tayang

3
Anda dapat menyimpan empat karakter denganp 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: bahasa di mana Anda harus menggunakan BigIntegers hanya untuk menghitung jumlah karakter dalam kode solusi.
Jared Updike

3
@ Jared Saya sangat setuju bahwa Java itu bertele-tele. Anda harus mengakui bahwa solusi yang disajikan a) memenuhi persyaratan b) jauh lebih lama dari yang sebenarnya diperlukan dan c) bermain dengan sistem tipe java dengan cara yang menyenangkan
wowest

7

Python 45 Char

Mencukur sedikit pun dari jawaban makapuf.

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

penggunaan ~ operator yang sangat pintar. Saya harus mencarinya untuk melihat apa yang dilakukannya (saya mencoba menghindari operator biner dengan Python, jadi saya ', tidak terlalu akrab dengan mereka).
Ponkadoodle

5

TI-BASIC

Bukan yang terpendek, tapi pendekatan baru. Dipastikan akan sangat melambat dengan urutan yang besar, tetapi seharusnya tidak meluap.

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)

Menggunakan ide jkff: c 1=[1];c n=n:(c$[ndiv 2,3*n+1]!!(nmod 2)), 44 chars
sdcvvc

4

bukan yang terpendek, tapi solusi clojure yang elegan

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

4

C #: 216 Karakter

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);}}}

dalam bentuk panjang:

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);
        }
    }
}

Versi Baru, menerima satu nomor sebagai masukan yang diberikan melalui baris perintah, tanpa validasi masukan. 173154 karakter.

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);}}}

dalam bentuk panjang:

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);
        }
    }
}

Saya dapat mencukur beberapa karakter dengan merobek ide dalam jawaban ini untuk menggunakan for loop daripada sementara. 150 karakter.

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);}}

Anda harus menyebutkan kode Anda menerima lebih dari satu masukan. Atau ambil itu dan kurangi beberapa karakter.
R. Martinho Fernandes

Anda dapat mempersingkat Action <object> dan mungkin lebih dinamis di C # 4.
Dykam

@Dykam: Baru saja dicentang: gagal dengan "kesalahan CS0428: Tidak dapat mengubah grup metode 'Tulis' ke jenis non-delegasi 'dinamis'. Apakah Anda bermaksud untuk memanggil metode ini?".
R. Martinho Fernandes

Oh, tentu saja ... perubahan implisit menjadi delegasi ... membutuhkan penandaan nama delegasi.
Sial

4

Ruby, 43 karakter

bignum didukung, dengan kerentanan stack overflow:

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

... dan 50 karakter, didukung bignum, tanpa stack overflow:

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

Kudos to Jordan. Saya tidak tahu tentang 'p' sebagai pengganti put.


4

nroff 1

Jalankan dengan 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. versi groff


2
Mengerikan! Namun, setidaknya keluarannya harus diformat dengan baik.
Jonathan Leffler

3
Hei, jalankan sebagai groff -U hail.gdan Anda mendapatkan 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

Dan beraksi:

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.0

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

Ini juga termasuk trailing 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)

Dengan implisit berikut

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

ini dapat disingkat menjadi

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

Edit - 58 karakter (termasuk input dan output, tetapi tidak termasuk nomor awal)

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

Bisa dikurangi 2 jika Anda tidak membutuhkan baris baru ...


3

F #, 90 karakter

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; ...]

Atau jika Anda tidak menggunakan F # interaktif untuk menampilkan hasilnya, 102 karakter:

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

Lisp umum, 141 karakter:

(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~%"))

Uji coba:

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 

Hampir. Tidak ada tajuk untuk baris ke-2. Saya bisa saja memangkas 3 karakter dengan mengabaikan panah, 3-4 lainnya menghilangkan spasi yang tidak perlu, tapi saya senang dengan kelipatan 3.
Vatine

3

Program dari Jerry Coffin memiliki integer over flow, coba yang ini:

#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";
}

diuji dengan

Jumlahnya kurang dari 100 juta dengan total waktu henti terlama 63.728.127 dengan 949 anak tangga.

Jumlahnya kurang dari 1 Milyar dengan total waktu henti terpanjang 670.617.279 anak tangga dengan 986 anak tangga.


Setiap tipe integer terbatas tidak dapat mencegah overflow integer. Bahkan tidak unsigned long long.
kennytm

3

ruby, 43, mungkin memenuhi persyaratan I / O


Jalankan dengan ruby -n hail

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

3

C #: 659 karakter dengan dukungan 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);
        }
    }
}
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.