Prodotti combinatori di numeri primi unici


21

Dichiarazione del problema

Dato un insieme di numeri primi consecutivi unici (non necessariamente inclusi 2), genera i prodotti di tutte le combinazioni dei primi poteri di questi numeri primi - ad esempio, nessuna ripetizione - e anche 1. Ad esempio, dato l'insieme {2, 3, 5, 7}, produci {1, 2, 3, 5, 6, 7, 10, 14, 15, 21, 30, 35, 42, 70, 105, 210} perché:

  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

Nota che se la cardinalità del tuo set di input è k, questo ti darà 2 ^ k membri nel tuo set di output.

Regole / Condizioni

  1. Puoi usare qualsiasi lingua. Cerca il numero minimo di caratteri del codice sorgente.
  2. La soluzione deve essere un programma completo o una funzione completa. La funzione può essere anonima (se la tua lingua supporta funzioni anonime).
  3. La tua soluzione dovrebbe essere in grado di supportare prodotti fino ad almeno 2 ^ 31. Non preoccuparti di rilevare o gestire l'overflow di numeri interi se vengono passati numeri il cui prodotto è troppo grande per essere rappresentato. Tuttavia, si prega di indicare i limiti dei calcoli.
  4. È possibile accettare un elenco o un set e produrre un elenco o un set. È possibile supporre che l'input sia ordinato ma non è necessario produrre output ordinato.

sfondo

Quando o perché è utile? Un posto molto utile è la generazione di una tabella di moltiplicatori per correre in parallelo in un algoritmo di factoring intero noto come fattorizzazione delle forme quadrate. Lì, ogni moltiplicatore dispari che provi diminuisce la probabilità che l'algoritmo fallisca (per trovare un fattore) di circa il 50% sui semiprimi difficili. Quindi, con il set di generazione di numeri primi {3, 5, 7, 11}, che produce un set di 16 moltiplicatori di prova per correre in parallelo, l'algoritmo fallisce circa 2 ^ –16 del tempo su semiprime difficili. L'aggiunta di 13 all'elenco dei numeri primi produce un set di 32 moltiplicatori di prova, riducendo la possibilità di fallimento a circa 2 ^ –32, fornendo un drastico miglioramento del risultato senza spese computazionali aggiuntive (perché anche con il doppio dei moltiplicatori che corrono in parallelo, su nella media trova ancora la risposta nello stesso numero totale di passaggi).

Risposte:


18

Pure Bash, 32 byte

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

Legge l'elenco di input (spazio singolo separato) passato come arg della riga di comando.

Vengono utilizzate tre diverse espansioni della shell:

  1. ${1// /\}*{1,}è un'espansione di parametro che sostituisce spazi 2 3 5 7con }*{1,invia 2}*{1,3}*{1,5}*{1,7. \$[{1,e }]vengono aggiunti all'inizio e alla fine rispettivamente per dare \$[{1,2}*{1,3}*{1,5}*{1,7}]. Il \$[backslash è evitato per impedire i tentativi di eseguire l'espansione aritmetica in questa fase.
  2. \$[{1,2}*{1,3}*{1,5}*{1,7}]è un'espansione del tutore . Poiché l' espansione del controvento si verifica in genere prima dell'espansione dei parametri , è necessario utilizzare evalper forzare l'espansione dei parametri prima. Il risultato dell'espansione del controvento è $[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]è un elenco di espansioni aritmetiche , che vengono quindi valutate per fornire l'elenco dei numeri richiesti.

Produzione:

$ ./comboprime.sh "2 3 5 7"
1 7 5 35 3 21 15 105 2 14 10 70 6 42 30 210
$

3
Mente ... soffiato ... wow!
Todd Lehman,

Wtf ... ottengo1 0
username.ak

@ username.ak Qual è il tuo contributo? Come lo stai inserendo (argomenti della riga di comando?). Quale versione di bash stai usando? bash --version
Trauma digitale

12

CJam, 13 byte

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

Legge un array (ad es. [2 3 5 7]) Da STDIN. Provalo online.

Una funzione anonima avrebbe lo stesso numero di byte:

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

Esempio di esecuzione

$ 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]

Come funziona

1a               " Push R := [1].              ";
  q~             " Read an array A from STDIN. ";
    {     }/     " For each a ∊ A:             ";
     1$f*+       "     R += { ra : r ∊ R }     ";
            p    " Print.                      ";

4
Wow, è un modo intelligente per scorrere tutti i sottoinsiemi.
Martin Ender,

9

Haskell, 22

la soluzione è una funzione anonima:

map product.mapM(:[1])

esempio di utilizzo:

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

spiegazione:
(:[1]) è una funzione che ha dato un numero xrestituisce la lista [x,1].
mapM(:[1])è una funzione che fornisce un elenco di numeri che mappa la funzione (:[1])su di essi e restituisce ogni modo possibile per scegliere un elemento da ogni elenco. per esempio, mapM(:[1]) $ [3,4]prima mappa la funzione da ottenere [[3,1] , [4,1]]. quindi le possibili scelte sono [3,4](scegliendo il primo numero di entrambi) [3,1] [1,4]e [1,1]quindi ritorna [[3,4],[3,1],[1,4],[1,1]].

quindi map productmappa su tutte le scelte e restituisce i loro prodotti, che sono l'output desiderato.

questa funzione è polimorfica nel suo tipo, il che significa che può operare su tutti i tipi di numeri. è possibile inserire un elenco di Inte il risultato sarebbe un elenco di Intma potrebbe anche essere applicato a un elenco di tipoIntegere restituisce un elenco di Integer. questo significa che il comportamento di overflow non è specificato da questa funzione ma dal tipo di input (il sistema di tipi espressivi di yay Haskell :))


Bello! Ci sono limiti alla dimensione del numero?
Todd Lehman,

1
@ToddLehman no. Il tipo numerico predefinito è Integer, che è un tipo intero illimitato. C'è anche Intun numero intero a 32 bit, ma per lo più è solo una cosa legacy.
John Dvorak,

@JanDvorak in pratica sì, ma adoro il sistema dei tipi troppo per non menzionarlo :). un'altra cosa da notare è che, poiché è anonimo, importa come lo usi perché in alcuni casi può essere applicata la restrizione del monomorfismo.
orgoglioso haskeller il

8

Mathematica, 18 17 byte

1##&@@@Subsets@#&

Questa è una funzione anonima. Chiamalo come

1##&@@@Subsets@#&[{2,3,5,7}]

E Martin interviene con una risposta meravigliosamente breve!
Todd Lehman,

@ToddLehman Ora aspettiamo la risposta J che batte questa. ;)
Martin Ender,

1
Se Mathematica non fosse una fonte chiusa, qualcuno potrebbe scrivere una versione giocata a golf. ×@@@𝒫@#dovrebbe essere imbattibile.
Dennis,

@Dennis Le specifiche del linguaggio Wolfram sono disponibili indipendentemente da Mathematica e penso che ci siano una o due implementazioni (incomplete) open source. La creazione di una versione di Mathematica con alias Unicode è stata suggerita alcune volte, ma non credo che sarebbe molto ben accolta su PPCG. ^^
Martin Ender,

2
@ MartinBüttner Chiedo scusa per averti fatto aspettare: (*/@#~2#:@i.@^#)16 caratteri in J;)
algoritmo

4

Aggiornamento: C (funzione f), 92

Anche come funzione, questa è ancora la voce più lunga qui. È la prima volta che ho passato un array di lunghezza sconosciuta come argomento di funzione in C, e apparentemente non c'è modo per una funzione C di conoscere la lunghezza di un array passato ad esso, poiché l'argomento viene passato come puntatore ( indipendentemente dalla sintassi utilizzata). Quindi è necessario un secondo argomento per indicare la lunghezza.

Ho mantenuto l'output su stdout, perché impostare un array intero e restituirlo sarebbe quasi sicuramente più lungo.

Grazie a Dennis per i suggerimenti.

Vedere la funzione f(92 caratteri esclusi gli spazi bianchi non necessari) nei seguenti programmi di test.

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

Uscita tramite puntatore a matrice

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 (programma), 108

escluso spazi bianchi non necessari.

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 da riga di comando, output su stdout. C non vincerà qui, ma forse proverò a convertirlo in una funzione domani.

Fondamentalmente ripetiamo tutte le 1<<ccombinazioni di numeri primi, con ogni bit i/cassociato alla presenza o all'assenza di un particolare primo nel prodotto. Il "loop interno" i%cscorre tra i numeri primi, moltiplicandoli in base al valore di i/c.When i%craggiungendo 0, il prodotto viene emesso, quindi impostato su 1 per la successiva iterazione "esterna".

curiosamente, printf("%d ",p,p=1)non funziona (stampa sempre un 1.) Questa non è la prima volta che vedo comportamenti strani quando un valore viene usato in un printfe assegnato successivamente nella stessa parentesi. In questo caso è possibile che la seconda virgola non sia trattata come un separatore di argomenti, ma piuttosto come un operatore.

uso

$ ./a 2 3 5 7
1 2 3 6 5 10 15 30 7 14 21 42 35 70 105 210

C non definisce rigorosamente l'ordine in cui vengono valutati gli argomenti. In particolare, molte chiamate di funzioni C hanno argomenti valutati da destra a sinistra.
COTO

Dalla sezione 6.5.2.2 di ISO / IEC 9899: TC3 : L'ordine di valutazione del designatore della funzione, gli argomenti effettivi e le sottoespressioni all'interno degli argomenti reali non è specificato [.] Quindi, spetta al compilatore in quale ordine di una funzione gli argomenti vengono valutati. Con -Wsequence-pointo -Wall, GCC si lamenterà.
Dennis,

1. È possibile modificare c-=1a c--o anche utilizzare i=--c<<cse non ti dispiace UB (sembra funzionare con GCC). 2. Entrambi gli usi di ||possono essere sostituiti con operatori ternari: p=i%c?p:!!printf("%d ",p)ep*=(i/c>>i%c)&1?1:atoi(v[i%c+1])
Dennis

@Dennis Grazie per i suggerimenti! Ho postato poco prima di andare a letto, quindi ho appena avviato il programma. c-=1è un golf così semplice che non avrei dovuto perderlo, ma è stata una rapida correzione di bug perché avevo dimenticato che c'è una stringa aggiuntiva in argv (il nome del programma.) i=..c<<cfunziona su GCC / cygwin, ma ho lasciato il mio originale programma così com'è e passa a una funzione. Quindi ho appena imparato che sizeofnon funziona su array passati come argomenti di funzione. Ho incorporato i tuoi suggerimenti per gli operatori ternari nella funzione. Ho bloccato l'output su stdout poiché non vedo alcun modo per restituire un array.
Level River St,

Sì, le matrici passate quando gli argomenti della funzione decadono ai puntatori. - Non è insolito in C passare un puntatore all'array che dovrebbe contenere i risultati come parametro di funzione. La domanda dice che puoi supporre che i prodotti siano più piccoli di 2 ^ 31, quindi puoi semplicemente passare un array di dimensioni 512.
Dennis

3

Haskell, 27 byte

Questa è un'implementazione Haskell della risposta CJam di @ sudo come funzione anonima. Non batterà la fantastica soluzione Haskell di @proud haskeller, ma la lascerò comunque qui.

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

Spiegazione: foldr accetta una funzione binaria, un valore e un elenco. Quindi sostituisce ogni cella cons nell'elenco da un'applicazione della funzione, e la fine della lista per il valore, in questo modo: foldr f v [a,b,c] == f a (f b (f c v)). Il nostro valore è un elenco di un elemento contenente 1e la funzione binaria è f = (=<<)(++).map.(*). Ora, fprende un numero n, fa una funzione (n*)che moltiplica per n, rende da esso una funzione g = map(n*)che si applica questa funzione a tutti gli elementi di una lista, e feed che funzione (=<<)(++). Qui (++)è la funzione di concatenazione, ed (=<<)è il legame monadico , che in questo caso accetta (++)e g, e fornisce una funzione che accetta in un elenco, si applicag a una copia di esso, e concatena i due.

In breve: iniziare con [1], e per ogni numero nnell'elenco di input, prendere una copia dell'elenco corrente, moltiplicare tutto per ne aggiungerlo all'elenco corrente.


3

Python: 55 caratteri

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

Genera in modo ricorsivo i prodotti scegliendo di includere o escludere ogni numero a turno.


Soluzione ricorsiva! Freddo!
Todd Lehman,

Penso che puoi lasciare spazio dopo andaver scritto la somma al contrario?
Mathmandan,

@mathmandan Yup, funziona, grazie.
xnor

3

PARI / GP , 26 byte

v->divisors(factorback(v))

Le versioni più lunghe includono

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

(30 byte) e

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

(31 byte).

Si noti che se l'input fosse una matrice di fattorizzazione anziché un set, è possibile salvare 18 byte usando divisorssolo. Ma convertire un set in una matrice di fattorizzazione sembra richiedere più di 18 byte. (Posso farlo in 39 byte direttamente come v->concat(Mat(v~),Mat(vectorv(#v,i,1)))o 24 byte moltiplicando e ri-factoring v->factor(factorback(v)), qualcuno può fare di meglio?)


2

Salvia - 36 34

In sostanza, lo stesso della soluzione di Martin Büttner , se la capisco correttamente. Come ho già detto in un commento, potrei anche pubblicarlo come risposta.

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

Questa è una funzione anonima, che può ad esempio essere chiamata come segue:

(lambda A:map(prod,Combinations(A)))([2,3,5,7])

1
Potresti radere 2 byte rendendola una funzione anonima (è consentita dalla domanda)
orgoglioso haskeller il

2

J (20)

Questo è risultato più lungo di quanto sperassi o mi aspettassi. Ancora: più corto di haskel!

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

Uso:

    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

Questo funziona per qualsiasi set di numeri, non solo per i numeri primi. Inoltre, i numeri primi possono avere dimensioni illimitate, purché l'array abbia il postfix x:2 3 5 7x


*/@#~2#:@i.@^#è un'alternativa per 14 byte.
miglia


1

R, 56 byte

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

Sto considerando che s è il set (e un elenco). Sono sicuro che può essere reso ancora più breve. Vedrò.


1

PHP, 97 byte

<?for(;$i++<array_product($a=$_GET[a]);){$t=$i;foreach($a as$d)$t%$d?:$t/=$d;if($t<2)echo"$i\n";}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.