Golf ini membutuhkan perhitungan faktorial untuk dibagi di antara beberapa utas atau proses.
Beberapa bahasa membuat ini lebih mudah untuk dikoordinasikan daripada yang lain, jadi itu adalah bahasa agnostik. Kode contoh tidak disediakan disediakan, tetapi Anda harus mengembangkan algoritma Anda sendiri.
Tujuan dari kontes ini adalah untuk melihat siapa yang dapat menghasilkan algoritma faktorial multicore terpendek (dalam byte, bukan detik) untuk menghitung N! yang diukur dengan suara ketika kontes ditutup. Seharusnya ada keuntungan multicore, jadi kami akan mengharuskan itu harus bekerja untuk N ~ 10.000. Pemilih harus memilih jika penulis gagal memberikan penjelasan yang valid tentang bagaimana ia menyebar pekerjaan di antara prosesor / core dan memilih berdasarkan pada keringkasan golf.
Untuk rasa ingin tahu, silakan kirim beberapa angka kinerja. Mungkin ada tradeoff kinerja vs golf di beberapa titik, pergi dengan golf selama memenuhi persyaratan. Saya ingin tahu ketika ini terjadi.
Anda dapat menggunakan perpustakaan integer tunggal inti tunggal yang tersedia secara normal. Misalnya, perl biasanya dipasang dengan bigint. Namun, perhatikan bahwa hanya memanggil sistem yang disediakan fungsi faktorial biasanya tidak akan membagi pekerjaan menjadi beberapa core.
Anda harus menerima dari STDIN atau ARGV input N dan output untuk STDOUT nilai N !. Anda secara opsional dapat menggunakan parameter input ke-2 untuk juga menyediakan jumlah prosesor / inti untuk program sehingga tidak melakukan apa yang akan Anda lihat di bawah :-) Atau Anda dapat mendesain secara eksplisit untuk 2, 4, apa pun yang Anda miliki.
Saya akan memposting contoh perl aneh saya sendiri di bawah ini, yang sebelumnya dikirimkan pada Stack Overflow di bawah Algoritma Faktorial dalam Berbagai Bahasa . Ini bukan golf. Banyak contoh lain diajukan, banyak dari mereka golf tetapi banyak yang tidak. Karena perizinan yang serupa, jangan ragu untuk menggunakan kode dalam contoh apa pun di tautan di atas sebagai titik awal.
Kinerja dalam contoh saya kurang bagus karena sejumlah alasan: ia menggunakan terlalu banyak proses, terlalu banyak konversi string / bigint. Seperti yang saya katakan itu adalah contoh yang sengaja aneh. Ini akan menghitung 5.000! di bawah 10 detik pada mesin 4 inti di sini. Namun, dua liner yang lebih jelas untuk / loop berikutnya dapat melakukan 5000! pada salah satu dari empat prosesor dalam 3.6s.
Anda pasti harus melakukan yang lebih baik dari ini:
#!/usr/bin/perl -w
use strict;
use bigint;
die "usage: f.perl N (outputs N!)" unless ($ARGV[0] > 1);
print STDOUT &main::rangeProduct(1,$ARGV[0])."\n";
sub main::rangeProduct {
my($l, $h) = @_;
return $l if ($l==$h);
return $l*$h if ($l==($h-1));
# arghhh - multiplying more than 2 numbers at a time is too much work
# find the midpoint and split the work up :-)
my $m = int(($h+$l)/2);
my $pid = open(my $KID, "-|");
if ($pid){ # parent
my $X = &main::rangeProduct($l,$m);
my $Y = <$KID>;
chomp($Y);
close($KID);
die "kid failed" unless defined $Y;
return $X*$Y;
} else {
# kid
print STDOUT &main::rangeProduct($m+1,$h)."\n";
exit(0);
}
}
Ketertarikan saya pada ini hanyalah (1) mengurangi kebosanan; dan (2) mempelajari sesuatu yang baru. Ini bukan masalah pekerjaan rumah atau penelitian bagi saya.
Semoga berhasil!
Jawaban:
Mathematica
Fungsi paralel-mampu:
Di mana g adalah
Identity
atauParallelize
tergantung pada jenis proses yang diperlukanUntuk tes pengaturan waktu, kami akan sedikit memodifikasi fungsi, sehingga mengembalikan waktu jam nyata.
Dan kami menguji kedua mode (dari 10 ^ 5 hingga 9 * 10 ^ 5): (hanya dua kernel di sini)
Hasil:
sumber
Haskell:
209200198177 karakter176167 sumber +3310 flag kompilerSolusi ini sangat konyol. Ini berlaku produk secara paralel dengan nilai jenis
[[Integer]]
, di mana daftar bagian dalam paling banyak dua item. Setelah daftar luar turun ke paling banyak 2 daftar, kami meratakannya dan mengambil produk secara langsung. Dan ya, pemeriksa tipe membutuhkan sesuatu yang dijelaskan dengan Integer, jika tidak, ia tidak akan dikompilasi.(Jangan ragu untuk membaca bagian tengah dari
f
antaraconcat
dans
sebagai "sampai aku hati panjangnya")Hal-hal tampak seperti mereka akan menjadi cukup baik sejak parMap dari Control.Parallel.Strategies membuatnya cukup mudah untuk mengolah ini ke beberapa utas. Namun, sepertinya GHC 7 membutuhkan 33 karakter kekalahan dalam opsi baris perintah dan lingkungan vars untuk benar-benar mengaktifkan runtime berulir untuk menggunakan beberapa core (yang saya sertakan dalam total).Kecuali saya kehilangan sesuatu, yangmungkinterjadi . ( Pembaruan : runtime GHC ulir tampaknya menggunakan utas N-1, dengan N adalah jumlah inti, jadi tidak perlu mengutak-atik opsi run time.)Untuk mengkompilasi:
Runtime, bagaimanapun, cukup bagus mengingat jumlah evaluasi paralel yang dipicu dan saya tidak mengkompilasi dengan -O2. Untuk 50000! pada MacBook dual-core, saya mendapatkan:
Total waktu untuk beberapa nilai yang berbeda, kolom pertama adalah paralel golf, yang kedua adalah versi sekuensial naif:
Sebagai referensi, versi sekuensial naif adalah ini (yang dikompilasi dengan -O2):
sumber
Ruby - 111 + 56 = 167 karakter
Ini adalah skrip dua file, file utama (
fact.rb
):file tambahan (
f2.rb
):Cukup mengambil jumlah proses dan angka untuk menghitung sebagai arg dan membagi pekerjaan menjadi rentang yang setiap proses dapat menghitung secara individual. Kemudian gandakan hasilnya di akhir.
Ini benar-benar menunjukkan seberapa lambat Rubinius bagi YARV:
Rubinius:
Ruby1.9.2:
(Perhatikan ekstra
0
)sumber
inject(:+)
. Berikut contoh dari docs:(5..10).reduce(:+)
.8
mana seharusnya ada*
kalau ada yang punya masalah menjalankan ini.Java,
523 519 434 430429 karakterDua 4s di baris terakhir adalah jumlah utas yang digunakan.
50000! diuji dengan kerangka kerja berikut (versi ungolfed dari versi asli dan dengan beberapa praktik buruk lebih sedikit - meskipun masih banyak) memberikan (pada mesin Linux 4-core saya) kali
Perhatikan bahwa saya mengulangi pengujian dengan satu utas untuk keadilan karena jit mungkin telah memanas.
Java dengan bigints bukan bahasa yang tepat untuk bermain golf (lihat apa yang harus saya lakukan hanya untuk membangun hal-hal yang buruk, karena konstruktor yang memakan waktu lama bersifat pribadi), tapi hei.
Seharusnya benar-benar jelas dari kode yang tidak di-serigala bagaimana memecah pekerjaan: setiap thread mengalikan kelas kesetaraan modulo jumlah thread. Poin kuncinya adalah bahwa setiap utas melakukan kurang lebih jumlah pekerjaan yang sama.
sumber
CSharp -
206215 karakterPisahkan perhitungan dengan fungsionalitas C # Parallel.For ().
Edit; Lupa kunci
Waktu eksekusi:
sumber
Perl, 140
Diambil
N
dari input standar.Fitur:
Benchmark:
sumber
Scala (
345266244232214 karakter)Menggunakan Aktor:
Edit - dihapus referensi untuk
System.currentTimeMillis()
, faktor keluara(1).toInt
, diubah dariList.range
menjadix to y
Sunting 2 - mengubah
while
loop menjadi afor
, mengubah flip kiri ke fungsi daftar yang melakukan hal yang sama, bergantung pada konversi tipe implisit sehingga tipe 6 charBigInt
hanya muncul sekali, diubah println untuk mencetakSunting 3 - menemukan cara melakukan beberapa deklarasi di Scala
Sunting 4 - berbagai optimasi yang saya pelajari sejak pertama kali saya melakukan ini
Versi tidak disatukan:
sumber
Scala-2.9.0 170
ungolfed:
Faktorial 10 dihitung pada 4 core dengan menghasilkan 4 Daftar:
yang dikalikan secara paralel. Akan ada pendekatan yang lebih sederhana untuk mendistribusikan angka-angka:
Tetapi distribusinya tidak akan sebagus itu - angka yang lebih kecil semuanya akan berakhir di daftar yang sama, tertinggi di yang lain, yang mengarah ke perhitungan yang lebih panjang di daftar terakhir (untuk Ns tinggi, utas terakhir tidak akan hampir kosong. , tetapi setidaknya mengandung (N / core) elemen -cores.
Scala dalam versi 2.9 berisi Koleksi paralel, yang menangani pemanggilan paralel sendiri.
sumber
Erlang - 295 karakter.
Hal pertama yang pernah saya tulis di Erlang jadi saya tidak akan terkejut jika seseorang dapat dengan mudah membagi dua ini:
Menggunakan model threading yang sama dengan entri Ruby saya sebelumnya: membagi rentang menjadi sub-rentang dan mengalikan rentang bersama-sama di utas terpisah lalu mengalikan hasilnya kembali di utas utama.
Saya tidak dapat menemukan cara agar escript berfungsi jadi simpan saja
f.erl
dan buka erl dan jalankan:dengan substitusi yang tepat.
Dapatkan sekitar 8 untuk 50000 dalam 2 proses dan 10 untuk 1 proses, di MacBook Air saya (dual-core).
Catatan: Perhatikan saja macet jika Anda mencoba lebih banyak proses daripada nomor untuk memfaktorkanisasi.
sumber