Kombinatorische Produkte einzigartiger Primzahlen


21

Erklärung des Problems

Erzeugen Sie aus einer Menge eindeutiger, aufeinanderfolgender Primzahlen (nicht notwendigerweise einschließlich 2) die Produkte aller Kombinationen der ersten Potenzen dieser Primzahlen - z. B. keine Wiederholungen - und auch 1. Wenn Sie beispielsweise die Menge {2, 3, 5, 7} erzeugen Sie {1, 2, 3, 5, 6, 7, 10, 14, 15, 21, 30, 35, 42, 70, 105, 210}, weil:

  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

Beachten Sie, dass wenn die Kardinalität Ihrer Eingabemenge k ist, dies Ihnen 2 ^ k Elemente in Ihrer Ausgabemenge gibt.

Regeln / Bedingungen

  1. Sie können eine beliebige Sprache verwenden. Streben Sie die kleinste Zeichenanzahl des Quellcodes an.
  2. Ihre Lösung muss entweder ein vollständiges Programm oder eine vollständige Funktion sein. Die Funktion kann anonym sein (wenn Ihre Sprache anonyme Funktionen unterstützt).
  3. Ihre Lösung sollte Produkte bis mindestens 2 ^ 31 unterstützen können. Machen Sie sich keine Sorgen über die Erkennung oder Behandlung von Integer-Überläufen, wenn Ihnen Zahlen übergeben werden, deren Produkt zu groß ist, um dargestellt zu werden. Bitte geben Sie jedoch die Grenzen Ihrer Berechnungen an.
  4. Sie können entweder eine Liste oder ein Set akzeptieren und entweder eine Liste oder ein Set erstellen. Sie können davon ausgehen, dass die Eingabe sortiert ist, müssen jedoch keine sortierte Ausgabe erstellen.

Hintergrund

Wann oder warum ist das sinnvoll? Ein Ort, an dem es sehr nützlich ist, eine Tabelle mit Multiplikatoren zu erstellen, die in einem Ganzzahlfaktor-Algorithmus, der als Square Forms Factorization bezeichnet wird, parallel laufen. Dort verringert jeder ungerade Multiplikator, den Sie versuchen, die Wahrscheinlichkeit, dass der Algorithmus ausfällt (um einen Faktor zu finden), auf harten Halbwerten um ungefähr 50%. Mit der Menge der generierenden Primzahlen {3, 5, 7, 11}, die eine Menge von 16 parallel laufenden Testmultiplikatoren ergibt, versagt der Algorithmus ungefähr 2 ^ –16 der Zeit auf harten Halbzeiten. Das Hinzufügen von 13 zur Liste der Primzahlen ergibt einen Satz von 32 Testmultiplikatoren, wodurch die Wahrscheinlichkeit eines Ausfalls auf ungefähr 2 ^ –32 verringert wird, was eine drastische Ergebnisverbesserung ohne zusätzlichen Rechenaufwand zur Folge hat (da selbst bei doppelt so vielen parallel laufenden Multiplikatoren weiter Durchschnittlich findet es die Antwort immer noch in der gleichen Anzahl von Schritten).

Antworten:


18

Pure Bash, 32 Bytes

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

Liest die Eingabeliste (durch einzelne Leerzeichen getrennt), die als Befehlszeilenargument übergeben wurde.

Es werden drei verschiedene Shell-Erweiterungen verwendet:

  1. ${1// /\}*{1,}ist eine Parametererweiterung , die Leerzeichen 2 3 5 7durch }*{1,zu gibende ersetzt 2}*{1,3}*{1,5}*{1,7. \$[{1,und }]werden jeweils zu Beginn und Ende addiert, um zu geben \$[{1,2}*{1,3}*{1,5}*{1,7}]. Das \$[wird mit einem Backslash versehen, um zu verhindern, dass in dieser Phase versucht wird, eine arithmetische Erweiterung durchzuführen.
  2. \$[{1,2}*{1,3}*{1,5}*{1,7}]ist eine Klammererweiterung . Da die Klammererweiterung in der Regel vor der Parametererweiterung erfolgt , müssen Sie evaldie Parametererweiterung mit erzwingen. Das Ergebnis der Klammererweiterung ist $[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]ist eine Liste von arithmetischen Erweiterungen , die ausgewertet werden, um die Liste der von uns benötigten Zahlen zu erhalten.

Ausgabe:

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

3
Geist ... geblasen ... wow!
Todd Lehman

Wtf ... ich bekomme1 0
username.ak

@ username.ak Was ist Ihre Eingabe? Wie geben Sie es ein (Befehlszeilenargumente?). Welche Version von Bash laufen Sie? bash --version
Digital Trauma

12

CJam, 13 Bytes

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

Liest ein Array (zB [2 3 5 7]) aus STDIN. Probieren Sie es online aus.

Eine anonyme Funktion hätte die gleiche Byteanzahl:

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

Beispiellauf

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

Wie es funktioniert

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, das ist eine clevere Methode, um alle Teilmengen zu durchlaufen.
Martin Ender

9

Haskell, 22

Die Lösung ist eine anonyme Funktion:

map product.mapM(:[1])

Beispielverwendung:

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

erklärung:
(:[1]) ist eine funktion, die mit einer xnummer die liste liefert [x,1].
mapM(:[1])ist eine Funktion, die eine Liste von Zahlen angibt, die die Funktion (:[1])über ihnen abbildet und alle möglichen Möglichkeiten zur Auswahl eines Elements aus jeder Liste zurückgibt. Zum Beispiel mapM(:[1]) $ [3,4]ordnet zuerst die Funktion zu, die abgerufen werden soll [[3,1] , [4,1]]. dann sind die möglichen Wahlen [3,4](die erste Zahl von beiden wählend) [3,1] [1,4]und [1,1]so gibt es zurück [[3,4],[3,1],[1,4],[1,1]].

Anschließend map productwerden alle Auswahlmöglichkeiten zugeordnet und die gewünschten Produkte zurückgegeben.

Diese Funktion ist in ihrem Typ polymorph, was bedeutet, dass sie auf alle Arten von Zahlen angewendet werden kann. Sie könnten eine Liste von eingeben Intund das Ergebnis wäre eine Liste von Int, könnte aber auch auf eine Liste vom Typ angewendet werdenIntegerund eine Liste von zurückgeben Integer. Dies bedeutet, dass das Überlaufverhalten nicht durch diese Funktion, sondern durch den Typ der Eingabe festgelegt wird (yay Haskells expressives Typensystem :)).


Nett! Gibt es Grenzen für die Anzahlgröße?
Todd Lehman

1
@ToddLehman Nein. Der standardmäßige numerische Typ Integerist ein unbegrenzter ganzzahliger Typ. Es gibt auch Inteine 32-Bit-Ganzzahl, aber das ist meistens nur eine Legacy-Sache.
John Dvorak

@JanDvorak in der Praxis ja, aber ich liebe das Typensystem zu sehr, um es nicht zu erwähnen :). Außerdem ist zu beachten, dass es von Bedeutung ist, wie Sie es verwenden, da es anonym ist, da in einigen Fällen die Monomorphismus-Beschränkung gelten kann.
stolzer Haskeller

8

Mathematica, 18 17 Bytes

1##&@@@Subsets@#&

Das ist eine anonyme Funktion. Nenne es so

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

Und Martin kommt mit einer wunderschönen kurzen Antwort herein!
Todd Lehman

@ToddLehman Warten wir nun auf die Antwort von J, die diese übertrifft. ;)
Martin Ender

1
Wenn Mathematica keine Closed-Source-Software wäre, könnte jemand eine Golfversion schreiben. ×@@@𝒫@#sollte unschlagbar sein.
Dennis

@Dennis Die Wolfram Language-Spezifikation ist unabhängig von Mathematica verfügbar, und ich glaube, es gibt eine oder zwei (unvollständige) Open Source-Implementierungen. Das Erstellen einer Unicode-Alias-Version von Mathematica wurde einige Male vorgeschlagen, aber ich denke nicht, dass es bei PPCG sehr gut ankommt. ^^
Martin Ender

2
@ MartinBüttner Entschuldigung, dass Sie warten müssen: (*/@#~2#:@i.@^#)16 Zeichen in J;)
algorithmshark

4

Update: C (Funktion f), 92

Auch als Funktion ist dies immer noch der längste Eintrag hier. Es ist das erste Mal, dass ich ein Array unbekannter Länge als Funktionsargument in C übergeben habe, und anscheinend gibt es für eine C-Funktion keine Möglichkeit, die Länge eines an sie übergebenen Arrays zu ermitteln, da das Argument als Zeiger übergeben wird ( unabhängig von der verwendeten Syntax). Daher ist ein zweites Argument erforderlich, um die Länge anzugeben.

Ich habe die Ausgabe auf stdout gehalten, da das Einrichten und Zurückgeben eines Integer-Arrays mit ziemlicher Sicherheit länger dauern würde.

Danke an Dennis für die Tipps.

Siehe die Funktion f(92 Zeichen ohne unnötige Leerzeichen) in den folgenden Testprogrammen.

Ausgabe über 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);
}

Ausgabe über Array Pointer

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

ohne unnötige Leerzeichen.

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

Eingabe von der Kommandozeile, Ausgabe nach stdout. C wird hier nicht gewinnen, aber vielleicht werde ich morgen versuchen, in eine Funktion zu konvertieren.

Grundsätzlich durchlaufen wir alle 1<<cKombinationen von Primzahlen, wobei jedes Bit i/cmit dem Vorhandensein oder Fehlen einer bestimmten Primzahl im Produkt verknüpft ist. Die "innere Schleife" i%cdurchläuft die Primzahlen und multipliziert sie mit dem Wert von i/c.Wenn i%c0 erreicht wird, wird das Produkt ausgegeben und für die nächste "äußere" Iteration auf 1 gesetzt.

Seltsamerweise printf("%d ",p,p=1)funktioniert das nicht (es gibt immer eine 1 aus). Dies ist nicht das erste Mal, dass ich ein merkwürdiges Verhalten sehe, wenn ein Wert in a verwendet printfund später in derselben Klammer zugewiesen wird. In diesem Fall wird das zweite Komma möglicherweise nicht als Argumenttrennzeichen, sondern als Operator behandelt.

Verwendung

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

C definiert die Reihenfolge, in der Argumente ausgewertet werden, nicht genau. Insbesondere werden bei vielen C-Funktionsaufrufen Argumente von rechts nach links ausgewertet.
COTO

Ab Abschnitt 6.5.2.2 von ISO / IEC 9899: TC3 : Die Reihenfolge der Auswertung des Funktionsbezeichners, der tatsächlichen Argumente und Unterausdrücke innerhalb der tatsächlichen Argumente ist nicht spezifiziert [.] Es liegt also am Compiler, in welcher Reihenfolge eine Funktion vorliegt Argumente werden ausgewertet. Mit -Wsequence-pointoder -Wallbeschwert sich GCC.
Dennis

1. Sie können ändern c-=1zu c--oder sogar verwenden , i=--c<<cwenn Sie UB nichts dagegen (mit GCC zu arbeiten scheint). 2. Beide Verwendungen von ||können durch ternäre Operatoren ersetzt werden: p=i%c?p:!!printf("%d ",p)undp*=(i/c>>i%c)&1?1:atoi(v[i%c+1])
Dennis

@Dennis Danke für die Tipps! Ich habe kurz vor dem Schlafengehen gepostet, damit ich gerade das Programm gestartet habe. c-=1Ich hätte es nicht verpassen sollen, aber es war eine schnelle Fehlerbehebung, weil ich vergessen hatte, dass argv (der Programmname) eine zusätzliche Zeichenfolge i=..c<<centhält, die auf GCC / cygwin funktioniert, aber ich habe mein Original verlassen programmieren wie es ist und zu einer Funktion übergehen. Ich habe gerade erfahren, dass sizeofdies bei Arrays, die als Funktionsargumente übergeben wurden , nicht funktioniert. Ich habe Ihre Vorschläge für ternäre Operatoren in die Funktion aufgenommen. Ich bin bei der Ausgabe auf stdout geblieben, da ich keine kurze Möglichkeit sehe, ein Array zurückzugeben.
Level River St

Ja, Arrays, die als Funktionsargumente übergeben wurden, zerfallen in Zeiger. - In C ist es nicht ungewöhnlich, einen Zeiger an das Array zu übergeben, das die Ergebnisse als Funktionsparameter enthalten soll. Die Frage besagt, dass Sie davon ausgehen können, dass die Produkte kleiner als 2 ^ 31 sind, sodass Sie nur ein Array der Größe 512 übergeben können.
Dennis

3

Haskell, 27 Bytes

Dies ist eine Haskell-Implementierung von @ sudos CJam-Antwort als anonyme Funktion. Es wird die großartige Haskell-Lösung von @proud haskeller nicht schlagen, aber ich werde es trotzdem hier ablegen.

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

Erläuterung: foldr Nimmt eine Binärfunktion, einen Wert und eine Liste auf. Dann ersetzt es jede Nachteile Zelle in der Liste durch eine Anwendung der Funktion, und das Ende der Liste durch den Wert, wie folgt aus : foldr f v [a,b,c] == f a (f b (f c v)). Unser Wert ist eine Ein-Element-Liste, die 1die Binärfunktion enthält f = (=<<)(++).map.(*). Nimmt nun feine Zahl n, erstellt eine Funktion (n*), die mit multipliziert wird n, erstellt daraus eine Funktion g = map(n*), die diese Funktion auf alle Elemente einer Liste anwendet, und füttert diese Funktion (=<<)(++). Hier (++)ist die Verkettung Funktion und (=<<)ist monadischen binden , die in diesem Fall nimmt (++)und gund gibt eine Funktion , die in einer Liste nimmt, giltg zu einer Kopie davon, und verkettet die beiden.

Kurz gesagt: Beginnen Sie mit [1]und nkopieren Sie für jede Nummer in der Eingabeliste eine Kopie der aktuellen Liste, multiplizieren Sie alles mit nund hängen Sie sie an die aktuelle Liste an.


3

Python: 55 Zeichen

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

Generiert die Produkte rekursiv, indem Sie die einzelnen Nummern nacheinander ein- oder ausschließen.


Rekursive Lösung! Cool!
Todd Lehman

Ich denke, Sie können das Leerzeichen danach fallen lassen, andwenn Sie die Summe umgekehrt schreiben?
Mathmandan

@mathmandan Yup, das funktioniert, danke.
5.

3

PARI / GP , 26 Bytes

v->divisors(factorback(v))

Längere Versionen enthalten

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

(30 Bytes) und

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

(31 Bytes).

Wenn die Eingabe eine Faktorisierungsmatrix anstelle einer Menge wäre, könnten 18 Byte allein gespeichert werden divisors. Die Konvertierung einer Menge in eine Faktorisierungsmatrix scheint jedoch mehr als 18 Byte zu dauern. (Ich kann es in 39 Bytes direkt als v->concat(Mat(v~),Mat(vectorv(#v,i,1)))oder 24 Bytes durch Multiplikation und Re-Factoring v->factor(factorback(v))tun, kann jemand es besser machen?)


2

Salbei - 36 34

Im Wesentlichen die gleiche wie Martin Büttners Lösung , wenn ich es richtig verstehe. Wie ich es in einem Kommentar erwähnt habe, kann ich es auch als Antwort posten.

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

Dies ist eine anonyme Funktion, die beispielsweise folgendermaßen aufgerufen werden kann:

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

1
Sie könnten 2 Bytes rasieren, indem Sie es zu einer anonymen Funktion machen (es ist von der Frage erlaubt)
stolzer Haskeller

2

J (20)

Dies fiel länger aus als ich gehofft oder erwartet hatte. Trotzdem: kürzer als haskel!

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

Verwendung:

    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

Dies funktioniert für jeden Satz von Zahlen, nicht nur für Primzahlen. Außerdem können die Primzahlen eine unbegrenzte Größe haben, solange das Array das Postfix hat x:2 3 5 7x


*/@#~2#:@i.@^#ist eine Alternative für 14 Bytes.
Meilen


1

R, 56 Bytes

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

Ich überlege hier, dass s die Menge (und eine Liste) ist. Ich bin sicher, dass es noch kürzer gemacht werden kann. Ich werde sehen.


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";}
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.