Code Golf: Collatz Conjecture


86

แรงบันดาลใจจากhttp://xkcd.com/710/นี่คือโค้ดกอล์ฟสำหรับมัน

ความท้าทาย

กำหนดจำนวนเต็มบวกที่มากกว่า 0 ให้พิมพ์ลำดับลูกเห็บสำหรับจำนวนนั้น

ลำดับ Hailstone

ดูวิกิพีเดียสำหรับรายละเอียดเพิ่มเติม ..

  • ถ้าจำนวนเท่ากันให้หารด้วยสอง
  • ถ้าตัวเลขเป็นเลขคี่ให้คูณสามแล้วบวกหนึ่ง

ทำซ้ำกับหมายเลขที่เกิดขึ้นจนกว่าจะถึง 1 (ถ้ายังคงอยู่หลังจาก 1 มันจะวนซ้ำไม่สิ้นสุด1 -> 4 -> 2 -> 1...)

บางครั้งโค้ดเป็นวิธีที่ดีที่สุดในการอธิบายดังนั้นนี่คือบางส่วนจาก Wikipedia

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

รหัสนี้ใช้ได้ แต่ฉันกำลังเพิ่มความท้าทายพิเศษ โปรแกรมจะต้องไม่เสี่ยงที่จะล้นสแต็ค ดังนั้นจึงต้องใช้การวนซ้ำหรือการเรียกซ้ำหาง

นอกจากนี้คะแนนโบนัสสำหรับหากสามารถคำนวณตัวเลขจำนวนมากได้และภาษายังไม่มีการใช้งาน (หรือหากคุณใช้การสนับสนุนจำนวนมากอีกครั้งโดยใช้จำนวนเต็มที่มีความยาวคงที่)

กรณีทดสอบ

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

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

นอกจากนี้โค้ดกอล์ฟจะต้องมีอินพุตและเอาต์พุตของผู้ใช้แบบเต็ม



20
ต้องไม่เสี่ยงต่อการเกิดสแต็คล้น : คุณไม่ควรโพสต์ไว้ที่นี่แล้ว! ;)
Felix Kling

51
เพื่อนของฉันหยุดโทรหาฉันหมายความว่าฉันแก้ปัญหาได้หรือไม่?
Martin

18
คุณใช้ SO แต่เคยมีเพื่อน? ... อะไรแบบนั้น?
ปรากฏ

5
คำตอบของแอสเซมเบลอร์นั้นยอดเยี่ยม แต่การต่อต้านโค้ด - กอล์ฟเล็กน้อยเพื่อเลือกคำตอบที่ยาวที่สุด !
John La Rooy

คำตอบ:


129

x86 ประกอบ 1337 ตัวอักษร

;
; 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 และ 1337 ตัวอักษร ฉันร้องไห้ด้วยความสุข
ZoogieZork

10
ฉันชอบการใช้ (ab) ของ lea สำหรับ 3n + 1
ว้าวที่สุด

ขอบคุณที่ไม่ใช้int 23h.
Mike D.

ฉันจะปฏิบัติตามใน linux ไม่สามารถรอที่จะลองได้อย่างไร
hidroto

64

Befunge

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

2
คุณควรอ่านสิ่งนี้ในแบบ 2 มิติ <> ^ v คือลูกศรที่เปลี่ยนทิศทางของไม้เท้า "ตัวนับโปรแกรม" | และ _ เป็นเงื่อนไขที่ขึ้น / ลงหรือซ้าย / ขวาขึ้นอยู่กับว่าค่าบนสแต็กเป็นจริงหรือเท็จ "เวทีรหัส" ทั้งหมดล้อมรอบด้านบน - ล่างและซ้าย - ขวา
SF.

และมีเพียง 35 ตัวอักษรรวมถึงช่องว่าง! ไม่เลวเลย!
Potatoswatter

6
แน่ใจเหรอว่าไม่ใช่ 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 เจ Meza'S INTERPRETR KTHXBYE!


51

Python - 95 64 51 46 ถ่าน

เห็นได้ชัดว่าไม่ก่อให้เกิดสแตกล้น

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

4
คุณอาจต้องการระบุ Python 2.x. IIRC, Python 3.x inputไม่ทำevalไฟล์.
Mike D.

5
สิ่งนี้ไม่เป็นไปตามข้อกำหนด - ไม่พิมพ์หมายเลขแรก
Ben Lings

7
ทำไมถึงได้รับการยอมรับ ไม่ใช่เลขที่สั้นที่สุดและไม่ได้พิมพ์ตัวเลขตัวแรก
Claudiu

1
ฉันเดาว่า input () สะท้อนตัวอักษรที่คุณพิมพ์ดังนั้นนี่จึงเป็นการพิมพ์ตัวเลขตัวแรก :)
Danko Durbić

17
คุณสามารถพิมพ์ตัวเลขแรกได้ในราคาเพียง 2 ไบต์โดยใช้n=input()*2
John La Rooy

23

Perl

ฉันตัดสินใจที่จะต่อต้านการแข่งขันเล็กน้อยและแสดงให้เห็นว่าคุณจะเขียนโค้ดปัญหาดังกล่าวใน Perl ได้อย่างไร
นอกจากนี้ยังมีรายการกอล์ฟรหัส 46 (ทั้งหมด) ในตอนท้าย

สามตัวอย่างแรกนี้เริ่มต้นด้วยส่วนหัวนี้

#! /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( $_ );
}
  • เวอร์ชันเรียกซ้ำง่าย ๆ

    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 );
        }
      }
    }
    
  • รุ่นซ้ำง่าย

    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;
      }
    }
    
  • รุ่นที่ปรับปรุงซ้ำ

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

ตอนนี้ฉันจะแสดงให้เห็นว่าคุณจะทำอย่างไรกับตัวอย่างสุดท้ายด้วย Perl เวอร์ชันก่อน 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];
  }
}

เกณฑ์มาตรฐาน

อันดับแรกของ IO จะเป็นส่วนที่ช้าเสมอ ดังนั้นหากคุณเปรียบเทียบตามที่เป็นจริงคุณควรได้รับความเร็วเท่ากันจากแต่ละอัน

ในการทดสอบเหล่านี้แล้วผมเปิดมือจับไฟล์/dev/null( $null) และแก้ไขทุกแทนที่จะอ่านsay $n say {$null} $nเป็นการลดการพึ่งพา 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;
  ...
}

หลังจากรัน 10 ครั้งนี่คือผลลัพธ์ตัวอย่างที่เป็นตัวแทน:

            ปรับอัตราการวนซ้ำซ้ำ
เรียกซ้ำ 1715 / s - -27% -46%
วนซ้ำ 2336 / s 36% - -27%
เพิ่มประสิทธิภาพ 3187 / s 86% 36% -

ในที่สุดรายการกอล์ฟรหัสจริง:

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

ทั้งหมด 46 ตัวอักษร

หากคุณไม่จำเป็นต้องพิมพ์ค่าเริ่มต้นคุณสามารถลบอักขระได้อีก 5 ตัว

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

41 ตัวอักษรรวม
31 ตัวอักษรสำหรับส่วนรหัสจริง แต่รหัสจะไม่ทำงานหากไม่มี-nสวิตช์ ดังนั้นฉันจึงรวมตัวอย่างทั้งหมดไว้ในการนับของฉัน


เวอร์ชันที่เพิ่มประสิทธิภาพของคุณไม่ใช่
Motti

@Motti ตัวอย่างเหล่านี้ขึ้นอยู่กับ IO มาก หลังจากทดสอบหลายครั้งเวอร์ชันที่ปรับให้เหมาะสมแล้วจะรักษาโอกาสในการขายที่สำคัญได้เสมอ
Brad Gilbert

@Brad เมื่อคุณเรียกใช้ Collatz บนหมายเลขหนึ่งการเพิ่มประสิทธิภาพจะเป็นการมองในแง่ร้ายเนื่องจากไม่ควรมีตัวเลขปรากฏมากกว่าหนึ่งครั้ง (เว้นแต่การคาดเดาจะผิด) เหตุผลที่คุณได้เห็นการปรับปรุงคือการที่คุณกำลังใช้ตัวเลขมาก (ในขณะที่ปัญหาออยเลอร์) ในความเป็นจริงผมเขียนบล็อกโพสต์เกี่ยวกับเรื่องนี้เมื่อเร็ว ๆ นี้lanzkron.wordpress.com/2010/01/18/...
Motti

2
@Motti นั่นคือการเพิ่มประสิทธิภาพที่ฉันกำลังพูดถึง นอกจากนี้ใน Perl $i + 1จะมีการเพิ่มเสมอ (การตอบสนองต่อรายการบล็อก) การใช้Sub::Call::Recurยังเป็นการเพิ่มประสิทธิภาพ @_=$n;goto &Collatzมิฉะนั้นผมจะใช้ (ช้ากว่า 10-20% ถ้าคุณเปลี่ยนstate @nextเป็นmy @next
Brad Gilbert

3
ฉันเชื่อว่ามาตรฐานการนับสโตรกกอล์ฟของ Perl ไม่นับจังหวะบังคับสำหรับการเรียกใช้ล่ามหรือเครื่องหมายคำพูด แต่จะนับหนึ่งสำหรับแต่ละธงข้าง E โดยใช้กฎเหล่านั้นรายการสุดท้ายของคุณจะนับ 37 ตัวอักษรและ 32 ตัวอักษรตามลำดับ
R. Martinho Fernandes

23

Haskell, 62 ตัวอักษร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

อินพุตของผู้ใช้เอาต์พุตที่พิมพ์ใช้หน่วยความจำคงที่และสแต็กทำงานร่วมกับจำนวนเต็มขนาดใหญ่โดยพลการ

ตัวอย่างการเรียกใช้รหัสนี้โดยให้ตัวเลข 80 หลักของ '1 (!) ทั้งหมดเป็นอินพุตนั้นค่อนข้างสนุกที่จะดู


เวอร์ชันดั้งเดิมฟังก์ชั่นเท่านั้น:

Haskell 51 ตัวอักษร

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

ใครที่ @ & ^ # ต้องการเงื่อนไขหรือไม่?

(แก้ไข: ฉันเป็นคน "ฉลาด" และใช้การแก้ไขหากไม่มีรหัสนี้รหัสลดลงเหลือ 54 ตัวอักษรแก้ไข 2: ลดลงเหลือ 51 โดยแยกตัวประกอบออกf())


หลังจากทำโพสต์ Miranda ของฉัน (ซึ่งโดยพื้นฐานแล้วก็คือ Haskell ที่เก่ากว่า) อย่างน้อยใน Miranda คุณสามารถลดสิ่งนั้นได้โดยใช้เครื่องหมายอัศเจรีย์เพียงอันเดียว - fn = n: [[], [f (n div 2), f (3 * n + 1)]! (n mod 2)]! (1 mod n) - ใช้งานได้ :)
Derek H

โอ้ใช่คุณไม่มีอินพุตและเอาต์พุต
R.Martinho Fernandes

@Martinho: ฉันก็เช่นกัน แต่ด้วยการประเมินที่ขี้เกียจตารางจึงเจ๋งกว่าในภาษาอื่น ๆ
Dario

1
การใช้ความคิดของ jleedev: c 1=[1];c n=n:(c$div(nmod 2*(5*n+2)+n)2)- 41 ตัวอักษรสิ่งนี้ใช้ข้อเท็จจริงที่ว่านี่คือ k * (3n + 1) + (1-k) * n / 2 โดยที่ k = n mod 2
sdcvvc

2
ฉันลบรายการอื่นของฉันและย้ายรหัสของฉันที่นี่และรวมแนวคิดเพิ่มเติมจากความคิดเห็นเหล่านี้ เพิ่มขึ้นเป็น 76 อักขระ แต่จะใช้อินพุตและเอาต์พุต
MtnViewMark

22

Golfscript: 20 ตัวอักษร

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

ซึ่งเทียบเท่ากับ

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
"must include full user input and output"
F'x

2
@FX แทนที่21ด้วย~จะทำให้โปรแกรมใช้ตัวเลขจาก stdin
John La Rooy

@gnibbler: Golfscript.rb มีการปรับปรุงหรือไม่ ฉันได้(eval):1:in เริ่มต้น ': วิธีการที่ไม่ได้กำหนดleftparen' for nil:NilClass (NoMethodError)เมื่อแทนที่21ด้วย~.
kennytm

@Kenny ™ Sadly GolfScript ไม่สามารถอ่าน stdin แบบโต้ตอบได้คุณต้องต่อท่อบางอย่างใน stdin เช่นecho 21 | ruby golfscript.rb collatz.gs
John La Rooy

19

bc 41 ตัวอักษร

ฉันเดาว่าปัญหาประเภทนี้เกิดbcขึ้นเพื่อ:

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

ทดสอบ:

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

รหัสที่ถูกต้อง:

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

bcจัดการตัวเลขที่มีมากถึงINT_MAXหลัก

แก้ไข: วิกิพีเดียบทความกล่าวถึงการคาดเดานี้ได้รับการตรวจสอบค่าทั้งหมดขึ้นอยู่กับ20x2 58 (. aprox 5.76e18 ) โปรแกรมนี้:

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

ทดสอบ2 20,000 +1 (ประมาณ3.98e6,020 ) ใน68วินาที144,404รอบ


เปลี่ยน 'n! = 1' เป็น `n> 1 'สำหรับ 54 ตัวอักษร
Jerry Coffin

4
นี่คือบรรทัดคำสั่งสำหรับสร้างตัวเลขความยาวโดยพลการแบบสุ่มสำหรับรายการนี้ (ในกรณีนี้คือ 10,000 หลัก): cat /dev/urandom | tr -dc '0-9' | head -c 10000 | bc collatz-conjecture.bc
indiv

3
@indiv - ฉันต้องทดสอบ :) ใช้เวลา 3 นาที 12 วินาทีในการประมวลผลตัวเลข 10,000 หลัก ฉันบันทึกผลลัพธ์ลงในไฟล์มันยาวประมาณ 1.2gb แต่ใช่มันเสร็จสิ้นอย่างถูกต้องใน 1 จุดสำหรับbc
Carlos Gutiérrez

16

Perl: 31 ตัวอักษร

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

แก้ไขเพื่อลบช่องว่างที่ไม่จำเป็น 2 ช่อง

แก้ไขเพื่อลบ 1 ช่องว่างที่ไม่จำเป็น


คุณสามารถลบช่องว่างที่ไม่จำเป็นออกได้สองช่อง (หลังจากพูดและหลังจากนั้น)
sorpigal

ลอง perl -E 'พูด $ _ = 10; พูด $ _ = $ _% 2? $ _ * 3 + 1: $ _ / 2 ในขณะที่ $ _> 1'
sorpigal

ฉันคิดว่าผู้ใช้จะทราบถึงหมายเลขเริ่มต้นของลำดับ ;-)
อา

41
บางครั้งเมื่อฉันเจอข้อความที่เข้ารหัส base64 บางครั้งฉันก็เข้าใจผิดว่าเป็นซอร์สโค้ด Perl
Martin

21
@Martin: ฉันนึกไม่ออกว่าคุณจะทำอย่างนั้น Base64 เป็นมากเพิ่มเติมสามารถอ่านได้
Jerry Coffin

15

MS Excel, 35 ตัวอักษร

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

นำมาจาก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

ใช้เวลาเพียงคัดลอก / วางสูตร 111 ครั้งเพื่อให้ได้ผลลัพธ์สำหรับจำนวนเริ่มต้น 1,000;)


16
ฉันเดาว่ามันสายเกินไปที่ฉันจะชี้ให้เห็นว่านี่คือสิ่งที่จุดจับเติมมีไว้เพื่ออะไรเหรอ? ehow.com/how_2284668_use-fill-handle-microsoft-excel.html :)
Jordan Running

นั่นเป็นคุณสมบัติที่มีประโยชน์มากซึ่งฉันไม่รู้ด้วยซ้ำว่ามีอยู่จริง ฉันแค่คัดลอกเซลล์แรกแล้วไฮไลต์เซลล์อื่น ๆ ทั้งหมดแล้ววางครั้งเดียว
Lance McNearney

ฉันเรียนรู้เกี่ยวกับการวางพื้นที่ประมาณสิบปีหลังจากที่ฉันค้นพบที่จับเติม ตัวเลข
Jimmy

14

C: 64 ตัวอักษร

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

ด้วยการรองรับจำนวนเต็มขนาดใหญ่: 431 (จำเป็น) ตัวอักษร

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

หมายเหตุ : อย่าลบออก#include <stdlib.h>โดยไม่มีการสร้างต้นแบบ malloc / realloc เป็นอย่างน้อยเนื่องจากการทำเช่นนี้จะไม่ปลอดภัยบนแพลตฟอร์ม 64 บิต (โมฆะ 64 บิต * จะถูกแปลงเป็น 32 บิต int)

อันนี้ยังไม่ได้รับการทดสอบอย่างจริงจัง สามารถใช้การย่อบางส่วนได้เช่นกัน


รุ่นก่อนหน้า:

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

(ลบ 12 ตัวอักษรเนื่องจากไม่มีใครติดตามรูปแบบผลลัพธ์ ... : |)


12

แอสเซมเบลอร์รุ่นอื่น หมายเลขนี้ไม่ จำกัด เฉพาะตัวเลข 32 บิต แต่สามารถรองรับตัวเลขได้ถึง 10 65534แม้ว่าการใช้ MS-DOS ในรูปแบบ ".com" จะ จำกัด ไว้ที่ตัวเลข 80 หลัก เขียนขึ้นสำหรับแอสเซมเบลอร์ A86 และต้องการกล่อง Win-XP DOS เพื่อเรียกใช้ ประกอบเป็น 180 ไบต์:

    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 ตัวอักษร25 28

dc เป็นเครื่องมือที่ดีสำหรับลำดับนี้:

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

24 ตัวอักษรโดยใช้สูตรจากรายการGolfscript :

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

57 ตัวอักษรเพื่อให้ตรงตามข้อกำหนด:

[Number: ]n?[Results: ]ndn[d5*2+d2%*+2/[ -> ]ndnd1<L]dsLx
dc -f collatz-spec.dc
หมายเลข: 3
ผลลัพธ์: 3 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1

9

โครงการ: 72

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

สิ่งนี้ใช้การเรียกซ้ำ แต่การโทรเป็นแบบหางซ้ำดังนั้นฉันคิดว่าพวกเขาจะได้รับการปรับให้เหมาะสมกับการวนซ้ำ ในการทดสอบอย่างรวดเร็วบางอย่างฉันไม่พบตัวเลขที่สแต็กล้นอยู่ดี ตัวอย่างเช่น:

(c 9876543219999999999000011234567898888777766665555444433332222 777777777777777777777777777777777798797657657651234143375987342987 5398709812374982529830983743297432985275309857392870237539879832075

... ทำงานได้ดี [นั่นคือทั้งหมด - ฉันเพิ่งหักมันให้พอดีกับหน้าจอ]


8

Mathematica, 45 50 ตัวอักษร

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

ฉันนับ 58 ตัวอักษร และคุณสามารถแทนที่OddQ[#]ด้วยOddQ@#เพื่อบันทึก 1 ตัวอักษร
kennytm

2
50 ตัวอักษร:c[n_]:=NestWhileList[If[OddQ@#,3#+1,#/2]&,n,#>1&]
Michael Pilat

7

ทับทิม 50 ตัวอักษรไม่มีสแต็กล้น

โดยทั่วไปเป็นการฉีกโซลูชัน Python ของ makapufโดยตรง :

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

ทับทิม 45 ตัวจะล้น

โดยทั่วไปเป็นการฉีกรหัสโดยตรงที่ให้ไว้ในคำถาม:

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

รูบี้รุ่นอะไร ฉันn.odd??ไม่ได้กำหนด นอกจากนี้ยังมีความเสี่ยงที่จะสแต็กล้นด้วยตัวเลขจำนวนมาก
Earlz

นั่นดูน่าสนใจ. ฉันมี 1.8.7 การเพิ่มช่องว่างระหว่างเครื่องหมายคำถามควรแก้ไขได้ และคุณถูกต้องเกี่ยวกับสแต็กโอเวอร์โฟลว์ ฉันจะแก้ไขคำตอบเพื่อจดบันทึกไว้
Jordan Running

3
คุณสามารถบันทึกอักขระสี่ตัวด้วยp 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 เพื่อนับจำนวนอักขระในโค้ดของโซลูชัน
Jared Updike

3
@ Jared ฉันยอมรับโดยสิ้นเชิงว่า Java เป็นแบบ verbose คุณต้องยอมรับว่าโซลูชันที่นำเสนอ a) ตรงตามข้อกำหนด b) นานเกินความจำเป็นจริงๆและ c) เล่นกับระบบประเภท java ได้อย่างน่าพอใจ
สุดยอด

7

Python 45 Char

โกนถ่านออกจากคำตอบของ makapuf

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

การใช้ตัวดำเนินการ ~ อย่างชาญฉลาด ฉันต้องค้นหามันเพื่อดูว่ามันทำอะไรได้บ้าง (ฉันพยายามหลีกเลี่ยงตัวดำเนินการไบนารีใน Python ดังนั้นฉันจึงไม่คุ้นเคยกับพวกมันมากนัก)
Ponkadoodle

5

TI-BASIC

ไม่ใช่แนวทางที่สั้นที่สุด แต่เป็นแนวทางใหม่ แน่นอนว่าจะช้าลงอย่างมากด้วยลำดับขนาดใหญ่ แต่ก็ไม่ควรล้น

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

ฮัสเคลล์: 50

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

การใช้ความคิด jkff: c 1=[1];c n=n:(c$[ndiv 2,3*n+1]!!(nmod 2))44 ตัวอักษร
sdcvvc

4

ไม่ใช่วิธีที่สั้นที่สุด แต่เป็นโซลูชันที่หรูหรา

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

4

C #: 216 ตัวอักษร

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

ในรูปแบบยาว:

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

เวอร์ชันใหม่ยอมรับหมายเลขหนึ่งเป็นอินพุตที่ระบุผ่านบรรทัดคำสั่งไม่มีการตรวจสอบอินพุต 173 154 อักขระ

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

ในรูปแบบยาว:

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

ฉันสามารถโกนตัวละครสองสามตัวได้โดยการฉีกแนวคิดในคำตอบนี้เพื่อใช้ for loop แทนที่จะใช้สักพัก 150 อักขระ

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

คุณควรระบุว่ารหัสของคุณยอมรับการป้อนข้อมูลมากกว่าหนึ่งรายการ หรือนำสิ่งนั้นออกไปและโกนออกไม่กี่ตัว
R. Martinho Fernandes

คุณสามารถย่อ Action <object> และอาจจะมากขึ้นเป็น dynamic ใน C # 4
Dykam

@Dykam: เพิ่งตรวจสอบ: ล้มเหลวด้วย "ข้อผิดพลาด CS0428: ไม่สามารถแปลงกลุ่มเมธอด" เขียน "เป็น" ไดนามิก "แบบไม่ได้รับมอบสิทธิ์คุณตั้งใจจะเรียกใช้เมธอดหรือไม่"
R. Martinho Fernandes

โอ้แน่นอน ... โดยปริยายการเปลี่ยนเป็นผู้รับมอบสิทธิ์ ... ต้องแสดงถึงผู้รับมอบสิทธิ์ Bummer ...
Dykam

4

ทับทิม 43 อักขระ

รองรับ bignum พร้อมความไวต่อการเกิดสแตกล้น:

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

... และ 50 ตัวอักษรรองรับ bignum โดยไม่มีสแต็กล้น:

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

ความรุ่งโรจน์ถึงจอร์แดน ฉันไม่รู้เกี่ยวกับ 'p' ในการแทนที่พัต


4

nroff 1

ทำงานด้วย 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


2
สยอง! อย่างไรก็ตามอย่างน้อยผลลัพธ์ควรได้รับการจัดรูปแบบให้สวยงาม
Jonathan Leffler

3
เฮ้รันเป็นgroff -U hail.gและคุณจะได้รับ PostScript! :-)
DigitalRoss

4

สกาล่า + สกาลาซ

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

และในการดำเนินการ:

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

สกาล่า 2.8

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

ซึ่งรวมถึงการต่อท้าย 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)

โดยมีนัยดังต่อไปนี้

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

ซึ่งสามารถย่อเป็น

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

แก้ไข - 58 อักขระ (รวมอินพุตและเอาต์พุต แต่ไม่รวมหมายเลขเริ่มต้น)

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

อาจลดลง 2 หากคุณไม่ต้องการขึ้นบรรทัดใหม่ ...


3

F # 90 ตัวอักษร

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

หรือถ้าคุณไม่ได้ใช้ F # โต้ตอบเพื่อแสดงผลลัพธ์ 102 ตัวอักษร:

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 ตัวอักษร:

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

ทดสอบการทำงาน:

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 

เกือบ. ไม่มีส่วนหัวสำหรับบรรทัดที่ 2 ฉันสามารถโกน 3 ตัวโดยไม่สนใจลูกศรได้อีก 3-4 ช่องที่ไม่จำเป็น แต่ฉันมีความสุขกับการคูณ 3
Vatine

3

โปรแกรม frm Jerry Coffin มีจำนวนเต็มมากกว่าโฟลว์ลองอันนี้:

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

ทดสอบด้วย

จำนวนน้อยกว่า 100 ล้านที่มีเวลาหยุดรวมนานที่สุดคือ 63,728,127 โดยมี 949 ก้าว

จำนวนน้อยกว่า 1 พันล้านที่มีเวลาหยุดรวมนานที่สุดคือ 670,617,279 โดยมี 986 ก้าว


ประเภทจำนวนเต็ม จำกัด ใด ๆ ไม่สามารถป้องกันจำนวนเต็มล้น unsigned long longไม่ได้
kennytm

3

ทับทิมอายุ 43 ปีอาจเป็นไปตามข้อกำหนด I / O


ทำงานด้วย ruby -n hail

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

3

C #: 659 ตัวอักษรพร้อมการสนับสนุน 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);}}}

ไม่พอใจ

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);
        }
    }
}
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.