Produk kombinasi bilangan prima yang unik

21

Pernyataan masalah

Diberikan satu set bilangan prima unik dan berurutan (tidak harus termasuk 2), hasilkan semua kombinasi kekuatan pertama bilangan prima ini - mis., Tidak ada pengulangan - dan juga 1. Sebagai contoh, diberikan himpunan {2, 3, 5, 7}, Anda menghasilkan {1, 2, 3, 5, 6, 7, 10, 14, 15, 21, 30, 35, 42, 70, 105, 210} karena:

  1  =  1
  2  =  2
  3  =  3
  5  =  5
  6  =  2 x 3
  7  =  7
 10  =  2 x 5
 14  =  2 x 7
 15  =  3 x 5
 21  =  3 x 7
 30  =  2 x 3 x 5
 35  =  5 x 7
 42  =  2 x 3 x 7
 70  =  2 x 5 x 7
105  =  3 x 5 x 7
210  =  2 x 3 x 5 x 7

Perhatikan bahwa jika kardinalitas set input Anda adalah k, ini akan memberi Anda 2 ^ k anggota dalam set output Anda.

Aturan / Ketentuan

  1. Anda dapat menggunakan bahasa apa pun. Bertujuan untuk penghitungan karakter terkecil dari kode sumber.
  2. Solusi Anda harus berupa program lengkap atau fungsi lengkap. Fungsi ini bisa anonim (jika bahasa Anda mendukung fungsi anonim).
  3. Solusi Anda harus dapat mendukung produk hingga setidaknya 2 ^ 31. Jangan khawatir tentang mendeteksi atau menangani bilangan bulat bilangan bulat jika Anda melewati angka yang produknya terlalu bagus untuk diwakili. Namun, sebutkan batas perhitungan Anda.
  4. Anda dapat menerima daftar atau set dan menghasilkan daftar atau set. Anda dapat mengasumsikan input diurutkan tetapi Anda tidak diharuskan untuk menghasilkan output yang diurutkan.

Latar Belakang

Kapan atau mengapa ini bermanfaat? Satu tempat yang sangat berguna adalah membuat tabel pengali untuk berpacu secara paralel dalam algoritma bilangan bulat yang dikenal sebagai Faktor Bentuk Square.. Di sana, setiap pengganda ganjil yang Anda coba mengurangi kemungkinan gagal algoritma (untuk menemukan faktor) sekitar 50% pada semiprimes keras. Jadi dengan himpunan bilangan prima {3, 5, 7, 11}, yang menghasilkan satu set pengganda uji coba 16 untuk berpacu secara paralel, algoritma gagal sekitar 2 ^ –16 waktu pada hard semiprimes. Menambahkan 13 ke daftar bilangan prima menghasilkan satu set 32 ​​pengganda percobaan, mengurangi kemungkinan kegagalan menjadi sekitar 2 ^ –32, memberikan peningkatan hasil yang drastis tanpa biaya komputasi tambahan (karena bahkan dengan pengganda dua kali lebih banyak yang berpacu secara paralel, di rata-rata masih menemukan jawaban dalam jumlah langkah yang sama).

Todd Lehman
sumber

Jawaban:

18

Bash Murni, 32 byte

eval echo \$[{1,${1// /\}*{1,}}]

Membaca daftar input (dipisahkan dengan spasi tunggal) yang dilewatkan sebagai argumen baris perintah.

Tiga ekspansi shell yang berbeda digunakan:

  1. ${1// /\}*{1,}adalah ekspansi parameter yang menggantikan spasi 2 3 5 7dengan }*{1,memberi 2}*{1,3}*{1,5}*{1,7. \$[{1,dan }]ditambahkan ke awal dan akhir masing-masing untuk memberi \$[{1,2}*{1,3}*{1,5}*{1,7}]. Ini \$[adalah garis miring terbalik untuk mencegah upaya untuk melakukan ekspansi aritmatika pada tahap ini.
  2. \$[{1,2}*{1,3}*{1,5}*{1,7}]adalah ekspansi penjepit . Karena ekspansi brace biasanya terjadi sebelum ekspansi parameter , kami menggunakan harus menggunakan evaluntuk memaksa ekspansi parameter terjadi terlebih dahulu. Hasil dari ekspansi brace adalah $[1*1*1*1] $[1*1*1*7] $[1*1*5*1] ... $[2*3*5*7].
  3. $[1*1*1*1] $[1*1*1*7] $[1*1*5*1] ... $[2*3*5*7]adalah daftar ekspansi aritmatika , yang kemudian dievaluasi untuk memberikan daftar angka yang kami butuhkan.

Keluaran:

$ ./comboprime.sh "2 3 5 7"
1 7 5 35 3 21 15 105 2 14 10 70 6 42 30 210
$
Trauma Digital
sumber
3
Pikiran ... hancur ... wow!
Todd Lehman
Wtf ... saya dapat1 0
username.ak
@ username.ak Apa masukan Anda? Bagaimana Anda memasukkannya (baris perintah args?). Versi bash apa yang Anda jalankan? bash --version
Trauma Digital
12

CJam, 13 byte

1aq~{1$f*+}/p

Membaca array (mis., [2 3 5 7]) Dari STDIN. Cobalah online.

Fungsi anonim akan memiliki jumlah byte yang sama:

{1a\{1$f*+}/}

Contoh dijalankan

$ cjam <(echo '1aq~{1$f*+}/p') <<< '[]'
[1]
$ cjam <(echo '1aq~{1$f*+}/p') <<< '[2 3 5 7]'
[1 2 3 6 5 10 15 30 7 14 21 42 35 70 105 210]

Bagaimana itu bekerja

1a               " Push R := [1].              ";
  q~             " Read an array A from STDIN. ";
    {     }/     " For each a ∊ A:             ";
     1$f*+       "     R += { ra : r ∊ R }     ";
            p    " Print.                      ";
Dennis
sumber
4
Wow, itu cara cerdas untuk beralih melalui semua subset.
Martin Ender
9

Haskell, 22

solusinya adalah fungsi anonim:

map product.mapM(:[1])

contoh penggunaan:

*Main> map product.mapM(:[1]) $ [2,3,5]
[30,6,10,2,15,3,5,1]

Penjelasan:
(:[1]) adalah fungsi yang diberi nomor xmengembalikan daftar [x,1].
mapM(:[1])adalah fungsi yang diberi daftar angka memetakan fungsi (:[1])di atasnya, dan mengembalikan setiap cara yang mungkin untuk memilih elemen dari setiap daftar. misalnya, mapM(:[1]) $ [3,4]pertama memetakan fungsi untuk mendapatkan [[3,1] , [4,1]]. maka pilihan yang mungkin adalah [3,4](memilih nomor pertama dari keduanya) [3,1] [1,4]dan [1,1]mengembalikannya [[3,4],[3,1],[1,4],[1,1]].

kemudian map productmemetakan semua pilihan dan mengembalikan produk mereka, yang merupakan output yang diinginkan.

fungsi ini polimorfik dalam artinya jenisnya yang dapat beroperasi pada semua jenis angka. Anda dapat memasukkannya daftar Intdan hasilnya akan menjadi daftar Inttetapi juga dapat diterapkan pada daftar jenisIntegerdan mengembalikan daftar Integer. ini berarti bahwa perilaku overflow tidak ditentukan oleh fungsi ini tetapi oleh tipe input (sistem tipe ekspresif yay Haskell :))

haskeller bangga
sumber
Bagus! Apakah ada batasan ukuran nomor?
Todd Lehman
1
@ToddLehman tidak Tipe numerik default adalah Integer, yang merupakan tipe integer tak terbatas. Ada juga Int, integer 32-bit, tapi itu kebanyakan hanya warisan.
John Dvorak
@JanDvorak dalam prakteknya ya tapi saya suka sistem tipe terlalu banyak untuk tidak menyebutkannya :). Hal lain yang perlu diperhatikan adalah bahwa karena anonim itu penting bagaimana Anda menggunakannya karena pembatasan monomorfisme mungkin berlaku dalam beberapa kasus.
haskeller bangga
8

Mathematica, 18 17 byte

1##&@@@Subsets@#&

Itu fungsi anonim. Sebut saja seperti

1##&@@@Subsets@#&[{2,3,5,7}]
Martin Ender
sumber
Dan Martin menyapu dengan jawaban singkat yang sangat indah!
Todd Lehman
@ToddLehman Sekarang mari kita tunggu jawaban J yang mengalahkan yang satu ini. ;)
Martin Ender
1
Jika Mathematica bukan sumber tertutup, seseorang dapat menulis versi golf. ×@@@𝒫@#harus tak terkalahkan.
Dennis
@ Dennis Spesifikasi Bahasa Wolfram tersedia secara independen dari Mathematica dan saya pikir ada satu atau dua implementasi sumber terbuka (tidak lengkap). Membuat versi Mathematica alias Unicode telah disarankan beberapa kali, tapi saya tidak berpikir itu akan diterima dengan sangat baik di PPCG. ^^
Martin Ender
2
@ MartinBüttner Permintaan maaf untuk membuat Anda menunggu: (*/@#~2#:@i.@^#)16 karakter dalam J;)
algorithmshark
4

Pembaruan: C (fungsi f), 92

Bahkan sebagai fungsi, ini masih merupakan entri terpanjang di sini. Ini adalah pertama kalinya saya melewatkan array dengan panjang yang tidak diketahui sebagai argumen fungsi di C, dan tampaknya tidak ada cara bagi fungsi C untuk mengetahui panjang array yang diteruskan ke sana, karena argumen dilewatkan sebagai pointer ( terlepas dari sintaks yang digunakan). Oleh karena itu argumen kedua diperlukan untuk menunjukkan panjangnya.

Saya menyimpan output ke stdout, karena mengatur array integer dan mengembalikannya hampir pasti akan lebih lama.

Terima kasih kepada Dennis untuk tipsnya.

Lihat fungsi f(92 karakter tidak termasuk spasi yang tidak perlu) dalam program pengujian di bawah ini.

Keluaran melalui printf

j;

f(int c,int*x){
  int p=1,i;
  for(i=c<<c;i--;p=i%c?p:!!printf("%d ",p))p*=(i/c>>i%c)&1?1:x[i%c];
}

main(int d,char**v){
  d--;
  int y[d];
  for(j=d;j--;)y[j]=atoi(v[j+1]);
  f(d,y);
}

Keluaran melalui pointer array

j,q[512];

f(int c,int*x,int*p){
    for(int i=-1;++i-(c<<c);p[i/c]*=(i/c>>i%c)&1?1:x[i%c])i%c||(p[i/c]=1);
}

main(int d,char**v){
  d--;
  int y[d];
  for(j=d;j--;)y[j]=atoi(v[j+1]);
  f(d,y,q);
  for(j=1<<d;j--;)printf("%d ",q[j]);
}

C (program), 108

tidak termasuk spasi yang tidak perlu.

p=1,i;
main(int c,char**v){
  c-=1;
  for(i=c<<c;i--;i%c||(printf("%d ",p),p=1))(i/c>>i%c)&1||(p*=atoi(v[i%c+1]));
}

Input dari commandline, output ke stdout. C tidak akan menang di sini, tapi mungkin saya akan mencoba mengonversi fungsi besok.

Pada dasarnya kami mengulangi semua 1<<ckombinasi bilangan prima, dengan setiap bit i/cdikaitkan dengan ada atau tidak adanya bilangan prima tertentu dalam produk. "Loop dalam" i%cberjalan melalui bilangan prima, mengalikannya dengan nilai i/c.When i%cmencapai 0, produk adalah output, kemudian diatur ke 1 untuk iterasi "luar" berikutnya.

anehnya, printf("%d ",p,p=1)tidak bekerja (selalu mencetak 1.) Ini bukan pertama kalinya saya melihat perilaku aneh ketika suatu nilai digunakan dalam printfdan ditetapkan kemudian di braket yang sama. Dalam hal ini dimungkinkan bahwa koma kedua tidak diperlakukan sebagai pemisah argumen, melainkan sebagai operator.

Pemakaian

$ ./a 2 3 5 7
1 2 3 6 5 10 15 30 7 14 21 42 35 70 105 210
Level River St
sumber
C tidak secara ketat mendefinisikan urutan argumen dievaluasi. Secara khusus, banyak panggilan fungsi C memiliki argumen yang dievaluasi dari kanan ke kiri.
COTO
Dari bagian 6.5.2.2 dari ISO / IEC 9899: TC3 : Urutan evaluasi penunjuk fungsi, argumen aktual, dan subekspresi dalam argumen aktual tidak ditentukan [.] Jadi, tergantung pada kompiler di mana memesan fungsi argumen dievaluasi. Dengan -Wsequence-pointatau -Wall, GCC akan mengeluh.
Dennis
1. Anda dapat mengubah c-=1ke c--atau bahkan menggunakan i=--c<<cjika Anda tidak keberatan UB (tampaknya bekerja dengan GCC). 2. Kedua penggunaan ||dapat diganti dengan operator ternary: p=i%c?p:!!printf("%d ",p)danp*=(i/c>>i%c)&1?1:atoi(v[i%c+1])
Dennis
@Dennis Terima kasih atas tipsnya! Saya diposting sebelum tidur jadi saya baru saja menjalankan program. c-=1adalah golf dasar yang seharusnya saya tidak melewatkannya, tapi itu adalah perbaikan bug cepat karena saya lupa bahwa ada satu string tambahan di argv (nama program.) i=..c<<cbekerja pada GCC / cygwin, tetapi saya telah meninggalkan yang asli program apa adanya dan beralih ke suatu fungsi. Jadi saya baru saja belajar bahwa sizeoftidak berfungsi pada array yang dilewatkan sebagai argumen fungsi. Saya telah memasukkan saran Anda untuk operator ternary ke dalam fungsi. Saya terjebak dengan keluaran ke stdout karena saya tidak melihat cara singkat untuk mengembalikan array.
Level River St
Ya, array dilewatkan sebagai argumen fungsi meluruh ke pointer. - Tidak jarang di C untuk melewatkan pointer ke array yang harus berisi hasil sebagai parameter fungsi. Pertanyaannya mengatakan bahwa Anda dapat berasumsi bahwa produknya lebih kecil dari 2 ^ 31, jadi Anda bisa melewatkan array berukuran 512.
Dennis
3

Haskell, 27 byte

Ini adalah implementasi Haskell dari jawaban CJam @ sudo sebagai fungsi anonim. Ini tidak akan mengalahkan solusi Haskell yang luar biasa dari haskeller @proud, tetapi saya akan tetap menyimpannya di sini.

foldr((=<<)(++).map.(*))[1]

Penjelasan: foldr mengambil fungsi biner, nilai, dan daftar. Kemudian menggantikan setiap sel kontra dalam daftar dengan aplikasi fungsi, dan akhir daftar dengan nilai, seperti ini: foldr f v [a,b,c] == f a (f b (f c v)). Nilai kami adalah daftar satu elemen yang berisi 1, dan fungsi binernya adalah f = (=<<)(++).map.(*). Sekarang, fmengambil nomor n, membuat fungsi (n*)yang mengalikan oleh n, membuat dari itu fungsi g = map(n*)yang berlaku berfungsi untuk semua elemen daftar, dan feed yang berfungsi untuk (=<<)(++). Di sini, (++)adalah fungsi rangkuman, dan (=<<)merupakan ikatan monadik , yang dalam hal ini menerima (++)dan g, dan memberikan fungsi yang mengambil dalam daftar, berlakug untuk salinannya, dan menggabungkan keduanya.

Singkatnya: mulai dengan [1], dan untuk setiap nomor ndalam daftar input, ambil salinan daftar saat ini, gandakan semuanya dengan n, dan tambahkan ke daftar saat ini.

Zgarb
sumber
3

Python: 55 karakter

f=lambda l:l and[x*l[0]for x in f(l[1:])]+f(l[1:])or[1]

Secara rekursif menghasilkan produk dengan memilih untuk memasukkan atau mengecualikan setiap nomor secara bergantian.

Tidak
sumber
Solusi rekursif! Keren!
Todd Lehman
Saya pikir Anda dapat menghapus ruang setelah andjika Anda menulis jumlah sebaliknya?
mathmandan
@mathmandan Yup, itu berhasil, terima kasih.
xnor
3

PARI / GP , 26 byte

v->divisors(factorback(v))

Versi yang lebih panjang termasuk

v->divisors(prod(i=1,#v,v[i]))

(30 byte) dan

v->divisors(fold((x,y)->x*y,v))

(31 byte).

Perhatikan bahwa jika inputnya adalah matriks faktorisasi dan bukannya set, 18 byte dapat disimpan menggunakan divisorssendiri. Tetapi mengubah satu set ke matriks faktorisasi tampaknya membutuhkan lebih dari 18 byte. (Saya bisa melakukannya dalam 39 byte langsung sebagai v->concat(Mat(v~),Mat(vectorv(#v,i,1)))atau 24 byte dengan mengalikan dan re-factoring v->factor(factorback(v)), adakah yang bisa melakukan lebih baik?)

Charles
sumber
2

Sage - 36 34

Intinya, sama dengan solusi Martin Büttner , jika saya memahaminya dengan benar. Seperti yang saya sebutkan di komentar, saya mungkin mengirimnya sebagai jawaban.

lambda A:map(prod,Combinations(A))

Ini adalah fungsi anonim, yang misalnya bisa disebut sebagai berikut:

(lambda A:map(prod,Combinations(A)))([2,3,5,7])
Wrzlprmft
sumber
1
Anda bisa mencukur 2 byte dengan menjadikannya fungsi anonim (diizinkan oleh pertanyaan)
bangga haskeller
2

J (20)

Ini ternyata lebih lama dari yang saya harapkan atau harapkan. Masih: lebih pendek dari haskel!

*/@:^"1#:@i.@(2&^)@#

Pemakaian:

    f=:*/@:^"1#:@i.@(2&^)@#
    f 2 3 5 7
1 7 5 35 3 21 15 105 2 14 10 70 6 42 30 210

Ini berfungsi untuk semua rangkaian angka, bukan hanya bilangan prima. Juga, bilangan prima dapat berukuran tidak terbatas, selama array memiliki postfix x:2 3 5 7x

ɐɔıʇǝɥʇu
sumber
*/@#~2#:@i.@^#adalah alternatif untuk 14 byte.
mil
1

R, 56 byte

r=1;for(i in 1:length(s))r=c(r,apply(combn(s,i),2,prod))

Saya mempertimbangkan di sini bahwa s adalah himpunan (dan daftar). Saya yakin itu bisa dibuat lebih pendek. Saya akan melihat.

Masclins
sumber
1

PHP, 97 Bytes

<?for(;$i++<array_product($a=$_GET[a]);){$t=$i;foreach($a as$d)$t%$d?:$t/=$d;if($t<2)echo"$i\n";}
Jörg Hülsermann
sumber