Code Golf: Collatz Varsayımı


86

Http://xkcd.com/710/ esinlenerek burada bunun için bir kod golfü var.

Meydan okuma

0'dan büyük pozitif bir tam sayı verildiğinde, bu sayı için dolu taşı dizisini yazdırın.

Hailstone Dizisi

Daha fazla ayrıntı için Wikipedia'ya bakın ..

  • Sayı çift ise, ikiye bölün.
  • Sayı tekse, üçe katlayın ve bir ekleyin.

Bunu 1'e ulaşana kadar üretilen sayı ile tekrarlayın (1'den sonra devam ederse, sonsuz bir döngü içinde gidecektir 1 -> 4 -> 2 -> 1...)

Bazen açıklamanın en iyi yolu koddur, işte Wikipedia'dan bazılarını

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

Bu kod işe yarıyor, ancak ekstra bir zorluk ekliyorum. Program yığın taşmalarına karşı savunmasız olmamalıdır . Bu yüzden ya yineleme ya da kuyruk özyineleme kullanmalıdır.

Ayrıca, büyük sayıları hesaplayabiliyorsa ve dilde zaten uygulanmamışsa bonus puanları. (veya sabit uzunluklu tam sayılar kullanarak büyük sayı desteğini yeniden uygularsanız)

Test durumu

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

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

Ayrıca, golf kodu tam kullanıcı girişi ve çıkışı içermelidir.



20
yığın taşmalarına karşı savunmasız olmamalıdır: O zaman buraya göndermemeliydiniz! ;)
Felix Kling

51
Arkadaşlarım beni aramayı bıraktı, bu sorunu çözdüğüm anlamına mı geliyor?
Martin

18
SO'dasınız ama bir zamanlar arkadaşlarınız mı vardı? ... nasıldı?
Pops

5
Birleştirici cevabı harika, ancak en uzun cevabı seçmek biraz anti-kod golfü!
John La Rooy

Yanıtlar:


129

x86 derlemesi, 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 ve 1337 karakter. Neşeyle ağlıyorum.
ZoogieZork

10
3n + 1 için lea'nın (ab) kullanımını seviyorum.
wowest

Kullanmayan için teşekkür ederiz int 23h.
Mike D.


64

Befunge

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

2
Bunu 2D olarak okumalısınız. <> ^ v, "program sayacı" nın gezinme yönünü değiştiren oklardır. | ve _, yığındaki değerin doğru veya yanlış olmasına bağlı olarak yukarı / aşağı veya sola / sağa giden koşullardır. Tüm "kod alanı", üst-alt ve sol-sağdan geçer.
SF.

Ve boşluk dahil sadece 35 karakter! Hiç de fena değil!
Potatoswatter

6
Perl olmadığına emin misin?
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'NIN YORUMLUSU . KTHXBYE!


51

Python - 95 64 51 46 karakter

Açıkça bir yığın taşması oluşturmaz.

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

4
Python 2.x'i belirtmek isteyebilirsiniz. IIRC, Python 3.x inputbir eval.
Mike D.

5
İlk sayı yazmıyor - Bu gereklilikleri yerine getirmemesi
Ben Lings

7
bu neden kabul edildi? en kısa olanı değil ve ilk sayıyı
basmıyor

1
Sanırım input () yazdığınız karakterleri yansıtıyor, bu yüzden bu ilk sayıyı yazdırıyor :)
Danko Durbić

17
İlk sayıyı yalnızca 2 baytlık bir maliyetle yazdırabilirsinizn=input()*2
John La Rooy

23

Perl

Biraz rekabete aykırı olmaya karar verdim ve bu tür bir sorunu Perl'de normalde nasıl kodlayacağınızı gösterdim.
Ayrıca sonunda 46 (toplam) karakter kodu-golf girişi vardır.

Bu ilk üç örneğin tümü bu başlık ile başlar.

#! /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( $_ );
}
  • Basit özyinelemeli sürüm

    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 );
        }
      }
    }
    
  • Basit yinelemeli sürüm

    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;
      }
    }
    
  • Optimize edilmiş yinelemeli sürüm

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

Şimdi bu son örneği Perl'in v5.10.0'dan önceki bir sürümüyle nasıl yapacağınızı göstereceğim.

#! /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];
  }
}

Kıyaslama

İlk olarak IO her zaman yavaş olan kısım olacak. Dolayısıyla, onları olduğu gibi değerlendirdiyseniz, her birinden yaklaşık aynı hızı almalısınız.

Daha sonra bunları test etmek için, /dev/null( $null) için bir dosya tanıtıcısı açtım ve say $nbunun yerine okumak için her şeyi düzenledim say {$null} $n. Bu, IO'ya olan bağımlılığı azaltmak içindir.

#! /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;
  ...
}

10 kez çalıştırdıktan sonra, işte temsili bir örnek çıktı:

            Yinelemeli Yinelemeli Optimize Edilmiş Oranı
Yinelemeli 1715 / sn - -% 27 -% 46
Yinelemeli 2336 / sn% 36 - -% 27
Optimize edilmiş 3187 / s 86% 36% -

Son olarak, gerçek bir kod-golf girişi:

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

Toplam 46 karakter

Başlangıç ​​değerini yazdırmanız gerekmiyorsa, 5 karakter daha kaldırabilirsiniz.

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

Gerçek kod bölümü için 41 karakter toplam
31 karakter, ancak kod -nanahtar olmadan çalışmayacaktır . Bu yüzden sayıma tüm örneği dahil ediyorum.


Optimize edilmiş versiyonunuz değil.
Motti

@Motti Bu örnekler çok IO'ya bağlıdır. Bunları birden çok kez test ettikten sonra, optimize edilmiş sürüm her zaman önemli bir liderlik sağlar.
Brad Gilbert

@Brad, Collatz'ı bir numara üzerinde çalıştırdığınızda, optimizasyon bir karamsarlıktır, çünkü hiçbir sayı birden fazla görünmemelidir (varsayım yanlış değilse). Eğer bir iyileşme görüyoruz nedeni (Euler sorun olduğu gibi) birçok sayılar yayınladığınıza göre, aslında Geçenlerde bu konuda bir blog yazısı yazdı lanzkron.wordpress.com/2010/01/18/...
Motti

2
@Motti, bahsettiğim optimizasyon. Ayrıca Perl'de $i + 1her zaman bir toplama vardır (blog girişine yanıt). Ayrıca kullanmak Sub::Call::Recurda bir optimizasyondur. Aksi takdirde kullanırdım @_=$n;goto &Collatz. (Bu 10-20% değiştirmek eğer yavaş state @nextiçinmy @next
Brad Gilbert

3
Perl golf vuruş sayma standartlarının tercümanı çağırmak için zorunlu vuruşları veya alıntıları saymadığına inanıyorum, ancak E'nin yanındaki her bayrak için bir tane saydığına inanıyorum.
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

Kullanıcı girişi, basılı çıktı, sabit bellek ve yığın kullanır, keyfi olarak büyük tamsayılarla çalışır.

Giriş olarak tüm '1'lerin (!) 80 basamaklı bir numarası verilen bu kodun örnek bir çalıştırmasına bakmak oldukça eğlencelidir.


Orijinal, yalnızca işlevsel sürüm:

Haskell 51 karakter

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

@ & ^ # Koşullu ifadelere kimin ihtiyacı var ki?

(düzenleme: "Zeki" oluyordum ve düzeltme kullanıyordum. O olmadan, kod 54 karaktere düştü. edit2: çarpanlarına ayırarak 51'e düştü f())


Miranda gönderimi yaptıktan sonra (temelde Haskell'den daha eski), en azından Miranda'da her biri yalnızca bir ünlem işareti kullanarak bunu kısaltabilirsiniz - fn = n: [[], [f (n div 2), f (3 * n + 1)]! (n mod 2)]! (1 mod n) - Çalışıyor :)
Derek H

Oh, evet, girdi ve çıktı eksik.
R. Martinho Fernandes

@Martinho: Ben de, ama tembel değerlendirme sayesinde tablolar diğer dillerden çok daha havalı .
Dario

1
Jleedev'in fikrini kullanarak: c 1=[1];c n=n:(c$div(nmod 2*(5*n+2)+n)2)- 41 karakter, bunun k * (3n + 1) + (1-k) * n / 2 olduğu gerçeğini kullanır, burada k = n mod 2
sdcvvc

2
Diğer girdimi sildim ve kodumu buraya taşıdım ve bu yorumlardan daha fazla fikir ekledim. 76 karaktere yükseltildi, ancak giriş ve çıkış yapıyor.
MtnViewMark

22

Golfscript: 20 karakter

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

Bu eşdeğerdir

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
"tam kullanıcı giriş ve çıkışını
içermelidir

2
@FX değiştirilmesi 21ile ~stdin'den numarayı kullanmak için programı neden olur
John La Rooy

@gnibbler: Golfscript.rb güncellendi mi? Ben var (eval):1:in 'initialize: tanımsız yöntemi leftparen' for nil:NilClass (NoMethodError)değiştirirken 21ile ~.
kennytm

@KennyTM, Ne yazık ki GolfScript etkileşimli olarak stdin okuyamıyor, bir şeyi stdin'e aktarmanız gerekiyor, örneğinecho 21 | ruby golfscript.rb collatz.gs
John La Rooy

19

bc 41 karakter

Sanırım bu tür sorunlar bunun bciçin icat edildi:

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

Ölçek:

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

Uygun kod:

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

bcen fazla basamaklı sayıları işlerINT_MAX

Düzenleme: Wikipedia makalesi bu varsayım kadar olan tüm değerler için kontrol edilmiştir bahseder 20X2 58 (. Aprox 5.76e18 ). Bu program:

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

test 2 20.000 + 1 (yaklaşık. 3.98e6,020 ) içinde 68 saniye, 144.404 döngü.


54 karakter için "n! = 1" i "n> 1" olarak değiştirin.
Jerry Coffin

4
İşte bu giriş için rasgele uzunlukta sayılar üretmek için bir komut satırı (bu durumda 10000 hane): cat /dev/urandom | tr -dc '0-9' | head -c 10000 | bc collatz-conjecture.bc
tek tek

3
@indiv - Test etmem gerekiyordu :), 10.000 basamaklı sayıyı işlemek 3 dakika 12 saniye sürdü. Çıktıyı bir dosyaya kaydettim, yaklaşık 1.2 gb uzunluğunda, ancak evet 1.'de doğru şekilde bitti. Puanbc
Carlos Gutiérrez

16

Perl: 31 karakter

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

Gereksiz 2 boşluğu kaldırmak için düzenlendi.

Gereksiz 1 alanı kaldırmak için düzenlendi.


Gereksiz iki boşluğu kaldırabilirsiniz (söyledikten sonra ve bir süre sonra)
sorpigal

Perl -E'yi deneyin $ _ = 10; $ _ = $ _% 2? $ _ * 3 + 1: $ _ / 2 iken $ _> 1 '
sorpigal

Kullanıcının dizinin başlangıç ​​numarasının farkında olacağını düşündüm ;-).
a'r

41
Bazen base64 kodlu metinle karşılaştığımda bazen bunu Perl kaynak koduyla karıştırıyorum.
Martin

21
@Martin: Bunu nasıl yapacağını hayal bile edemiyorum. Base64 çok daha okunabilir.
Jerry Coffin

15

MS Excel, 35 karakter

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

Doğrudan Wikipedia'dan alınmıştır :

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

1000 başlangıç ​​sayısının sonucunu elde etmek için formülü 111 kez kopyalayıp / yapıştırmak yeterliydi.;)


16
Sanırım doldurma işleminin bunun için olduğunu belirtmem için çok geç değil mi? ehow.com/how_2284668_use-fill-handle-microsoft-excel.html :)
Jordan Running

Bu, varlığından bile haberdar olmadığım oldukça kullanışlı bir özellik. İlk hücreyi kopyaladım ve ardından diğer tüm hücreleri vurguladım ve bir kez yapıştırdım.
Lance McNearney

Dolgu tutamacını keşfettikten yaklaşık on yıl sonra alan-macunu öğrendim. rakamlar.
Jimmy

14

C: 64 karakter

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

Büyük tamsayı desteği ile: 431 (gerekli) karakter

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

Not : #include <stdlib.h>Malloc / realloc prototipini en azından prototip oluşturmadan kaldırmayın , çünkü bunu yapmak 64-bit platformlarda güvenli olmayacaktır (64-bit void * 32-bit int'e dönüştürülecektir).

Bu henüz güçlü bir şekilde test edilmedi. Biraz kısaltmak da kullanabilir.


Önceki sürümler:

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

(kimse çıktı biçimine uymadığı için 12 karakter kaldırıldı ...: |)


12

Başka bir assembler versiyonu. Bu 32 bitlik sayılarla sınırlı değildir, 10 65534'e kadar sayıları işleyebilir, ancak MS-DOS'un kullandığı ".com" biçimi 80 basamaklı sayılarla sınırlıdır. A86 assembler için yazılmıştır ve çalışması için bir Win-XP DOS kutusu gerektirir. 180 bayta kadar toplanır:

    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 bu sıralama için iyi bir araçtır:

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

Ayrıca Golfscript girişindeki formülü kullanan 24 karakter :

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

Özellikleri karşılayan 57 karakter :

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

9

Şema: 72

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

Bu özyinelemeyi kullanır, ancak çağrılar kuyruk özyinelemelidir, bu yüzden yinelemeye göre optimize edileceklerini düşünüyorum. Bazı hızlı testlerde, yine de yığının taştığı bir sayı bulamadım. Örnek vermek gerekirse:

(c 9876543219999999999000011234567898888777766665555444433332222 777777777777777777777777777777777798797657657651234143375987342987 539870981237498252983098374329743298523098573987

... gayet iyi çalışıyor. [hepsi tek bir sayı - ekrana sığması için kırdım.]


8

Mathematica, 45 50 karakter

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

58 karakter saydım. Ve 1 karakterden tasarruf etmek için OddQ[#]ile değiştirebilirsiniz OddQ@#.
kennytm

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

7

Ruby, 50 karakter, yığın taşması yok

Temel olarak makapuf'un Python çözümünün doğrudan kopyası :

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

Ruby, 45 karakter, taşacak

Temel olarak soruda sağlanan kodun doğrudan kopyası:

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

Bu Ruby'nin hangi sürümü? Ben n.odd??tanımlanmadım. Ayrıca, bu, çok sayıda yığın taşmasına karşı savunmasızdır.
Earlz

İlginç. 1.8.7 var. Soru işaretleri arasına boşluk eklemek bunu düzeltmelidir. Ve yığın taşması konusunda haklısın. Bunu not etmek için cevabımı düzenleyeceğim.
Jordan Koşu

3
İle dört karakter kaydedebilirsinizp 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: BigIntegers'ı yalnızca çözümün kodundaki karakter sayısını saymak için kullanmanız gereken dil.
Jared Updike

3
@Jared Java'nın ayrıntılı olduğuna tamamen katılıyorum. Sunulan çözümün a) gereksinimleri karşıladığını, b) gerçekten gerekenden çok daha uzun olduğunu ve c) java türü sistemle hoş bir şekilde
oynadığını kabul etmelisiniz

7

Python 45 Karakter

Makapuf'un cevabından bir karakter kazandım.

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

~ operatörünün çok akıllıca kullanımı. Ne yaptığını görmek için ona bakmak zorunda kaldım (Python'da ikili operatörlerden kaçınmaya çalıştım, bu yüzden onlara pek aşina değilim).
Ponkadoodle

5

TI-BASIC

En kısa değil, yeni bir yaklaşım. Büyük dizilerle önemli ölçüde yavaşlayacağı kesindir, ancak taşmamalıdır.

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)

Jkff'ın fikrini kullanma: c 1=[1];c n=n:(c$[ndiv 2,3*n+1]!!(nmod 2)), 44 karakter
sdcvvc

4

en kısa değil, zarif bir clojure çözümü

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

uzun biçimde:

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

Yeni Sürüm, komut satırı aracılığıyla sağlanan giriş olarak bir sayıyı kabul eder, giriş doğrulaması yoktur. 173 154 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);}}}

uzun biçimde:

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

Bir süre yerine for döngüsü kullanmak için bu cevaptaki fikri kopararak birkaç karakteri tıraş edebiliyorum . 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);}}

Kodunuzun birden fazla girişi kabul ettiğini belirtmelisiniz. Veya onu alın ve birkaç karakter tıraş edin.
R. Martinho Fernandes

<object> Eylemini kısaltabilir ve C # 4'te muhtemelen daha dinamik hale getirebilirsiniz.
Dykam

@Dykam: Kontrol ettim: "CS0428 hatasıyla başarısız oldu: 'Yazma' yöntem grubu temsilci olmayan 'dinamik' türüne dönüştürülemiyor. Yöntemi çağırmayı mı düşündünüz?".
R. Martinho Fernandes

Tabii ki ... delegeye üstü kapalı olarak dönüştürmek ... temsilcinin belirtilmesini gerektirir. Bummer ...
Dykam

4

Ruby, 43 karakter

bignum destekli, yığın taşması duyarlılığı ile:

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

... ve 50 karakter, bignum destekli, yığın taşması olmadan:

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

Ürdün'e şeref. Putların yerine "p" yi bilmiyordum.


4

nroff 1

İle çalıştırın 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. groff versiyonu


2
Korkunç! Yine de, en azından çıktı güzel bir şekilde biçimlendirilmelidir.
Jonathan Leffler

3
Hey, olarak çalıştırın groff -U hail.gve PostScript alın! :-)
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

Ve eylemde:

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

Bu aynı zamanda sondaki 1'i de içerir.

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)

Aşağıdaki örtük

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

bu kısaltılabilir

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

Düzenleme - 58 karakter (giriş ve çıkış dahil, ancak başlangıç ​​numarası hariç)

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

Yeni satırlara ihtiyacınız yoksa 2 azaltılabilir ...


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

Veya sonucu görüntülemek için F # etkileşimli kullanmıyorsanız, 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

Common Lisp, 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~%"))

Test sürüşü:

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 

Neredeyse. 2. satır için başlık yok. Oku görmezden gelerek 3 karakter tıraş edebilirdim, başka 3-4 gereksiz boşlukları atlatabilirdim, ancak 3'ün katları ile mutluyum.
Vatine

3

Jerry Coffin'den frm programı tam sayıya sahiptir, bunu deneyin:

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

ile test edildi

En uzun toplam durma süresine sahip 100 milyonun altındaki rakam 949 adımla 63.728.127'dir.

Toplam durma süresi en uzun olan 1 milyardan az sayı 986 adımla 670.617.279'dur.


Sonlu tam sayı türleri, tam sayı taşmasını önleyemez. Hatta değil unsigned long long.
kennytm

3

Ruby, 43, muhtemelen I / O gereksinimini karşılıyor


İle çalıştırın ruby -n hail

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

3

C #: BigInteger destekli 659 karakter

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

Golfsüz

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);
        }
    }
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.