Code Golf: Collatz Conjecture


86

Lấy cảm hứng từ http://xkcd.com/710/ đây là một sân gôn mã dành cho nó.

Các thách thức

Cho một số nguyên dương lớn hơn 0, hãy in ra dãy hailstone cho số đó.

Trình tự Hailstone

Xem Wikipedia để biết thêm chi tiết ..

  • Nếu là số chẵn, hãy chia nó cho hai.
  • Nếu số lẻ, hãy nhân ba số đó và thêm một số.

Lặp lại điều này với số được tạo cho đến khi nó đạt đến 1. (nếu nó tiếp tục sau 1, nó sẽ đi theo vòng lặp vô hạn của 1 -> 4 -> 2 -> 1...)

Đôi khi mã là cách tốt nhất để giải thích, vì vậy đây là một số từ Wikipedia

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

Mã này hoạt động, nhưng tôi đang thêm vào một thách thức bổ sung. Chương trình không được dễ bị tràn ngăn xếp . Vì vậy, nó phải sử dụng phép lặp hoặc đệ quy đuôi.

Ngoài ra, điểm thưởng nếu nó có thể tính toán các số lớn và ngôn ngữ chưa có nó. (hoặc nếu bạn thực hiện lại hỗ trợ số lớn bằng cách sử dụng các số nguyên có độ dài cố định)

Trường hợp thử nghiệm

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

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

Ngoài ra, mã gôn phải bao gồm đầu vào và đầu ra đầy đủ của người dùng.



20
không được dễ bị tràn ngăn xếp : Khi đó bạn không nên đăng nó ở đây! ;)
Felix Kling

51
Bạn bè của tôi đã ngừng gọi cho tôi, điều đó có nghĩa là tôi đã giải quyết được vấn đề?
Martin

18
Bạn đang ở trên SO, nhưng đã từng có bạn bè? ... nó như thế nào?
Pops

5
Câu trả lời của người lắp ráp rất tuyệt, nhưng hơi phản mã khi chọn câu trả lời dài nhất !
John La Rooy

Câu trả lời:


129

lắp ráp x86, 1337 ký tự

;
; 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 ký tự. Tôi khóc vì vui mừng.
ZoogieZork

10
Tôi thích việc sử dụng (ab) của lea cho 3n + 1.
tuyệt vời nhất

Cảm ơn bạn đã không sử dụng int 23h.
Mike D.

làm thế nào để tôi complie trong linux không thể chờ đợi để thử nó
hidroto

64

Befunge

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

2
Bạn nên đọc nó ở dạng 2D. <> ^ v là các mũi tên thay đổi hướng "bộ đếm chương trình" đi qua. | và _ là các điều kiện đi lên / xuống hoặc trái / phải tùy thuộc vào việc giá trị trên ngăn xếp là đúng hay sai. Toàn bộ "đấu trường mã" bao quanh từ trên xuống dưới và trái-phải.
SF.

Và chỉ có 35 ký tự bao gồm khoảng trắng! Không xấu cả!
Potatoswatter

6
Bạn có chắc đó không phải là 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. DIỄN GIẢI CỦA MEZA . KTHXBYE!


51

Python - 95 64 51 46 ký tự

Rõ ràng là không tạo ra tràn ngăn xếp.

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

4
Bạn có thể muốn chỉ định Python 2.x. IIRC, Python 3.x inputkhông thực hiện eval.
Mike D.

5
Điều này không thực hiện đầy đủ các yêu cầu - nó không in số đầu tiên
Bến Zerglings

7
tại sao điều này được chấp nhận? nó không phải là một ngắn nhất và nó không in số đầu tiên
Claudiu

1
Tôi đoán input () lặp lại các ký tự bạn nhập, vì vậy điều này sẽ in ra số đầu tiên :)
Danko Durbić Ngày

17
Bạn có thể in số đầu tiên với chi phí chỉ có 2 byte bằng cách sử dụngn=input()*2
John La Rooy

23

Perl

Tôi quyết định có một chút phản cạnh tranh và chỉ ra cách bạn thường viết mã vấn đề như vậy trong Perl.
Ngoài ra còn có một mục nhập mã chơi gôn 46 (tổng cộng) ở cuối.

Ba ví dụ đầu tiên này đều bắt đầu với tiêu đề này.

#! /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( $_ );
}
  • Phiên bản đệ quy đơn giản

    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 );
        }
      }
    }
    
  • Phiên bản lặp lại đơn giả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;
      say $n;
      while( $n > 1 ){
        if( $n % 2 ){ # odd
          $n = 3 * $n + 1;
        } else { #even
          $n = $n / 2;
        }
        say $n;
      }
    }
    
  • Phiên bản lặp lại được tối ưu hóa

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

Bây giờ tôi sẽ chỉ cho bạn cách bạn thực hiện ví dụ cuối cùng đó với phiên bản Perl trước 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];
  }
}

Điểm chuẩn

Trước hết IO luôn là phần chậm. Vì vậy, nếu bạn thực sự đánh giá chúng như hiện tại, bạn sẽ nhận được tốc độ tương tự của mỗi cái.

Để kiểm tra những điều này sau đó, tôi đã mở một tệp điều khiển thành /dev/null( $null) và chỉnh sửa mọi thứ say $nđể thay vào đó đọc say {$null} $n. Điều này là để giảm sự phụ thuộc vào 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;
  ...
}

Sau khi chạy nó 10 lần, đây là đầu ra mẫu đại diện:

            Đánh giá lặp lại đệ quy được tối ưu hóa
Đệ quy 1715 / s - -27% -46%
Lặp lại 2336 / s 36% - -27%
Tối ưu hóa 3187 / s 86% 36% -

Cuối cùng, một mục nhập mã chơi gôn thực sự:

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

Tổng số 46 ký tự

Nếu bạn không cần in giá trị bắt đầu, bạn có thể xóa thêm 5 ký tự.

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

41 ký tự tổng số
31 ký tự cho phần mã thực tế, nhưng mã sẽ không hoạt động nếu không có công -ntắc. Vì vậy, tôi bao gồm toàn bộ ví dụ trong số của tôi.


Không phải là phiên bản được tối ưu hóa của bạn.
Motti

@Motti Những ví dụ này rất phụ thuộc vào IO. Sau khi thử nghiệm chúng nhiều lần, phiên bản được tối ưu hóa luôn duy trì một vị trí dẫn đầu đáng kể.
Brad Gilbert

@Brad, khi bạn chạy Collatz trên một số thì việc tối ưu hóa là một sự bi quan vì không có số nào xuất hiện nhiều hơn một lần (trừ khi phỏng đoán sai). Lý do bạn thấy sự cải thiện là bạn đang chạy nhiều con số (như trong bài toán Euler), thực tế là tôi đã viết một bài blog về điều này gần đây lanzkron.wordpress.com/2010/01/18/…
Motti

2
@Motti đó là sự tối ưu hóa mà tôi đã nói đến. Ngoài ra, trong Perl $i + 1luôn luôn bổ sung (đối phó với các blog entry). Ngoài ra sử dụng Sub::Call::Recurcũng là một tối ưu hóa. Nếu không, tôi sẽ sử dụng @_=$n;goto &Collatz. (Đó là 10-20% chậm hơn nếu bạn thay đổi state @nextđểmy @next
Brad Gilbert

3
Tôi tin rằng các tiêu chuẩn đếm cú đánh golf perl không tính các cú đánh bắt buộc để gọi thông dịch viên cũng như các dấu ngoặc kép, nhưng đếm một cho mỗi lá cờ bên cạnh E. Sử dụng các quy tắc đó, các mục nhập cuối cùng của bạn được tính lần lượt là 37 ký tự và 32 ký tự.
R. Martinho Fernandes

23

Haskell, 62 ký tự 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

Đầu vào của người dùng, đầu ra được in, sử dụng bộ nhớ và ngăn xếp không đổi, hoạt động với các số nguyên lớn tùy ý.

Một mẫu chạy mã này, với số 80 chữ số của tất cả các chữ số '1 (!) Làm đầu vào, khá thú vị khi xem xét.


Phiên bản ban đầu, chỉ chức năng:

Haskell 51 ký tự

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

Dù sao thì @ & ^ # cần điều kiện?

(chỉnh sửa: Tôi đã rất "thông minh" và sử dụng bản sửa lỗi. Nếu không có nó, mã giảm xuống còn 54 ký tự. sửa2: giảm xuống 51 bằng cách bao gồm thừa f())


Sau khi thực hiện bài đăng Miranda của tôi (về cơ bản chỉ là Haskell cũ hơn), ít nhất ở Miranda, bạn có thể cắt giảm điều đó bằng cách chỉ sử dụng một dấu chấm than mỗi - fn = n: [[], [f (n div 2), f (3 * n + 1)]! (n mod 2)]! (1 mod n) - Hoạt động :)
Derek H

Ồ, có, bạn đang thiếu đầu vào và đầu ra.
R. Martinho Fernandes

@Martinho: Tôi cũng vậy, nhưng nhờ lười đánh giá, các bảng thậm chí còn mát hơn nhiều so với các ngôn ngữ khác.
Dario

1
Sử dụng jleedev của ý tưởng: c 1=[1];c n=n:(c$div(nmod 2*(5*n+2)+n)2)- 41 ký tự, sử dụng này thực tế rằng đây là k * (3n + 1) + (1-k) * n / 2 với k = n mod 2
sdcvvc

2
Tôi đã xóa mục nhập khác của mình và chuyển mã của tôi đến đây, đồng thời kết hợp thêm nhiều ý tưởng từ những nhận xét này. Đã tăng lên 76 ký tự, nhưng không nhập và xuất.
MtnViewMark

22

Golfscript: 20 ký tự

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

Điều này tương đương với

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
"phải bao gồm đầu vào và đầu ra đầy đủ của người dùng"
F'x

2
@FX, thay thế 21bằng ~sẽ làm cho chương trình để sử dụng một số từ stdin
John La Rooy

@gnibbler: Golfscript.rb có được cập nhật không? Tôi đã (eval):1:in khởi tạo ': phương thức không xác định leftparen' for nil:NilClass (NoMethodError)khi thay thế 21bằng ~.
kennytm

@KennyTM, Đáng buồn là GolfScript không thể đọc stdin một cách tương tác, bạn phải chuyển một cái gì đó vào stdin, chẳng hạn nhưecho 21 | ruby golfscript.rb collatz.gs
John La Rooy

19

bc 41 ký tự

Tôi đoán loại vấn đề này là thứ bcđược tạo ra để:

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

Kiểm tra:

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

Mã thích hợp:

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

bcxử lý các số có tối đa INT_MAXchữ số

Chỉnh sửa: Các bài viết trên Wikipedia đề cập đến giả thuyết này đã được kiểm tra đối với tất cả các giá trị lên đến 20x2 58 (aprox. 5.76e18 ). Chương trình này:

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

kiểm tra 2 20.000 +1 ( khoảng 3,98e6,020 ) trong 68 giây, 144.404 chu kỳ.


Thay đổi 'n! = 1' thành `n> 1 'cho 54 ký tự.
Jerry Coffin

4
Dưới đây là dòng lệnh để tạo các số có độ dài tùy ý ngẫu nhiên cho mục nhập này (10000 chữ số trong trường hợp này): cat /dev/urandom | tr -dc '0-9' | head -c 10000 | bc collatz-conjecture.bc
indiv

3
@indiv - Tôi đã phải kiểm tra nó :), mất 3 phút 12 giây để xử lý số 10.000 chữ số. Tôi đã lưu đầu ra vào một tập tin, đó là khoảng 1.2 GB dài, nhưng có nó đã kết thúc một cách chính xác trong 1. Point chobc
Carlos Gutiérrez

16

Perl: 31 ký tự

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

Đã chỉnh sửa để loại bỏ 2 khoảng trắng không cần thiết.

Đã chỉnh sửa để loại bỏ 1 khoảng trống không cần thiết.


Bạn có thể xóa hai khoảng trắng không cần thiết (sau khi nói và sau đó)
sorpigal

Hãy thử perl -E 'nói $ _ = 10; nói $ _ = $ _% 2? $ _ * 3 + 1: $ _ / 2 trong khi $ _> 1'
sorpigal

Tôi hình dung rằng người dùng sẽ nhận thức được số bắt đầu của chuỗi ;-).
a'r

41
Đôi khi tôi bắt gặp văn bản được mã hóa base64, đôi khi tôi nhầm nó với mã nguồn Perl.
Martin

21
@Martin: Tôi không thể tưởng tượng làm thế nào bạn làm điều đó. Base64 là nhiều hơn có thể đọc được.
Jerry Coffin

15

MS Excel, 35 ký tự

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

Lấy trực tiếp từ 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

Chỉ cần sao chép / dán công thức 111 lần để nhận được kết quả cho số bắt đầu là 1000.;)


16
Tôi đoán đã quá muộn để tôi chỉ ra rằng đây là cái chốt điền dùng để làm gì, phải không? ehow.com/how_2284668_use-fill-handle-microsoft-excel.html :)
Jordan Running

Đó là một tính năng khá tiện dụng mà tôi thậm chí còn không biết là có tồn tại. Tôi chỉ sao chép ô đầu tiên và sau đó đánh dấu tất cả các ô khác và dán một lần.
Lance McNearney

Tôi đã học về cách dán vùng khoảng mười năm sau khi tôi phát hiện ra chốt điền. số liệu.
Jimmy

14

C: 64 ký tự

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

Với hỗ trợ số nguyên lớn: 431 ký tự (cần thiết)

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

Lưu ý : Không xóa #include <stdlib.h>mà không có ít nhất tạo mẫu malloc / realloc, vì làm như vậy sẽ không an toàn trên nền tảng 64 bit (void 64 bit * sẽ được chuyển đổi thành int 32 bit).

Cái này vẫn chưa được thử nghiệm mạnh mẽ. Nó cũng có thể sử dụng một số rút ngắn.


Những phiên bản trước:

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

(đã xóa 12 ký tự vì không có ký tự nào tuân theo định dạng đầu ra ...: |)


12

Một phiên bản lắp ráp khác. Cái này không giới hạn ở số 32 bit, nó có thể xử lý các số lên đến 10 65534 mặc dù định dạng ".com" mà MS-DOS sử dụng chỉ giới hạn ở 80 chữ số. Được viết cho trình hợp dịch A86 và yêu cầu hộp DOS Win-XP để chạy. Lắp ráp thành 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 ký tự 25 28

dc là một công cụ tốt cho trình tự này:

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

Ngoài ra 24 ký tự sử dụng công thức từ mục nhập Golfscript :

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

57 ký tự để đáp ứng các thông số kỹ thuật:

[Number: ]n?[Results: ]ndn[d5*2+d2%*+2/[ -> ]ndnd1<L]dsLx
dc -f collatz-spec.dc
Số 3
Kết quả: 3 -> 10 -> 5 -> 16 -> 8 -> 4 -> 2 -> 1

9

Sơ đồ: 72

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

Điều này sử dụng đệ quy, nhưng các cuộc gọi là đệ quy đuôi nên tôi nghĩ chúng sẽ được tối ưu hóa để lặp lại. Trong một số thử nghiệm nhanh, tôi vẫn không thể tìm thấy số mà ngăn xếp bị tràn. Chỉ ví dụ:

(c 9876543219999999999000011234567898888777766665555444433332222 777777777777777777777777777777777798797657657651234143375987342987 5398709812374982529830983743297432985230985739873098

... chạy tốt. [đó là tất cả một số - Tôi vừa bẻ nó để vừa trên màn hình.]


8

Mathematica, 45 tuổi 50 ký tự

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

Tôi đếm được 58 ký tự. Và bạn có thể thay thế OddQ[#]bằng OddQ@#để tiết kiệm 1 ký tự.
kennytm

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

7

Ruby, 50 ký tự, không tràn ngăn xếp

Về cơ bản là một bản trích xuất trực tiếp của giải pháp Python của makapuf :

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

Ruby, 45 ký tự, sẽ tràn

Về cơ bản là một đoạn mã trực tiếp được cung cấp trong câu hỏi:

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

Đó là phiên bản nào của Ruby? Tôi n.odd??không được xác định. Ngoài ra, điều đó dễ bị tràn ngăn xếp với số lượng lớn.
Earlz

Nó thật thú vị. Tôi có 1.8.7. Thêm khoảng trắng giữa các dấu hỏi sẽ khắc phục điều đó. Và bạn nói đúng về tràn ngăn xếp. Tôi sẽ chỉnh sửa câu trả lời của mình để ghi lại điều đó.
Jordan Running

3
Bạn có thể lưu bốn ký tự vớip 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: ngôn ngữ mà bạn phải sử dụng BigIntegers chỉ để đếm số ký tự trong mã của giải pháp.
Jared Updike

3
@Jared Tôi hoàn toàn đồng ý rằng Java là dài dòng. Bạn phải thừa nhận rằng giải pháp được trình bày a) đáp ứng các yêu cầu b) là cách dài hơn thực sự cần thiết và c) chơi với hệ thống kiểu java một cách dễ chịu
wowest

7

Python 45 Char

Cạo một dấu vết cho câu trả lời của makapuf.

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

sử dụng rất thông minh toán tử ~. Tôi đã phải tìm kiếm nó để xem nó đã làm gì (tôi cố gắng tránh các toán tử nhị phân trong Python, vì vậy tôi, không quen thuộc lắm với chúng).
Ponkadoodle

5

TI-BASIC

Không phải là ngắn nhất, nhưng là một cách tiếp cận mới. Chắc chắn sẽ làm chậm đáng kể với các chuỗi lớn, nhưng nó không được tràn.

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)

Sử dụng ý tưởng jkff của: c 1=[1];c n=n:(c$[ndiv 2,3*n+1]!!(nmod 2)), 44 ký tự
sdcvvc

4

không phải là ngắn nhất, nhưng là một giải pháp áo choàng thanh lịch

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

4

C #: 216 ký tự

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

ở dạng dài:

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

Phiên bản mới, chấp nhận một số làm đầu vào được cung cấp thông qua dòng lệnh, không có xác thực đầu vào. 173 154 ký tự.

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

ở dạng dà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);
        }
    }
}

Tôi có thể loại bỏ một vài ký tự bằng cách cắt bỏ ý tưởng trong câu trả lời này để sử dụng vòng lặp for thay vì một thời gian. 150 ký tự.

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

Bạn nên đề cập đến mã của bạn chấp nhận nhiều hơn một đầu vào. Hoặc lấy đi và cạo một vài ký tự.
R. Martinho Fernandes

Bạn có thể rút ngắn Action <object> và có thể nhiều hơn nữa thành dynamic trong C # 4.
Dykam

@Dykam: Chỉ cần kiểm tra nó: không thành công với "lỗi CS0428: Không thể chuyển đổi nhóm phương thức 'Viết' thành loại không được ủy quyền 'động'. Bạn có định gọi phương thức không?".
R. Martinho Fernandes

Ồ, dĩ nhiên ... chuyển đổi ngầm thành đại biểu ... yêu cầu biểu thị đại biểu. Bummer ...
Dykam

4

Ruby, 43 ký tự

bignum được hỗ trợ, với tính dễ bị tràn ngăn xếp:

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

... và 50 ký tự, hỗ trợ bignum, không bị tràn ngăn xếp:

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

Kudos đến Jordan. Tôi không biết về 'p' như một sự thay thế cho các đặt.


4

nroff 1

Chạy với 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. phiên bản Groff


2
Đáng sợ! Tuy nhiên, ít nhất đầu ra phải được định dạng đẹp.
Jonathan Leffler

3
Này, chạy nó groff -U hail.gvà bạn nhận được 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

Và trong hành động:

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

Điều này cũng bao gồm dấu 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)

Với ẩn ý sau

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

điều này có thể được rút ngắn thành

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

Chỉnh sửa - 58 ký tự (bao gồm đầu vào và đầu ra, nhưng không bao gồm số đầu tiên)

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

Có thể giảm 2 nếu bạn không cần dòng mới ...


3

F #, 90 ký tự

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

Hoặc nếu bạn không sử dụng F # tương tác để hiển thị kết quả, 102 ký tự:

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 chung, 141 ký tự:

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

Chạy thử nghiệm:

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 

Hầu hết. Không có tiêu đề cho dòng thứ 2. Tôi có thể đã cạo 3 ký tự tắt bỏ qua những mũi tên, 3-4 khác eliding không gian không cần thiết, nhưng tôi hài lòng với một bội số của 3.
Vatine

3

Chương trình frm Jerry Coffin có số nguyên trên luồng, hãy thử chương trình này:

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

thử nghiệm với

Con số dưới 100 triệu có tổng thời gian dừng lâu nhất là 63.728.127, với 949 bậc.

Con số dưới 1 tỷ có tổng thời gian dừng lâu nhất là 670.617.279, với 986 bước.


Mọi kiểu số nguyên hữu hạn đều không thể ngăn tràn số nguyên. Thậm chí không unsigned long long.
kennytm

3

ruby, 43, có thể đáp ứng yêu cầu I / O


Chạy với ruby -n hail

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

3

C #: 659 ký tự với hỗ trợ 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);}}}

Ung dung

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);
        }
    }
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.