|
Antwort |
Registriert seit: 25. Jun 2003 Ort: Thüringen 2.950 Beiträge |
#11
Zitat:
Allerdings kommt es doch im Endeffekt auf's Gleiche raus, da 1 mod N grundsätzlich 1 ist, oder nicht (sofern N > 0, was allerdings eine Vorraussetzung ist)?
oder 0 == 0 mod N == N mod N
Zitat:
Zitat:
dies bedeutet das wir in modularen Ringen arbeiten.
Zitat:
Gut. Aber das ist wenn dann ein Problem des Fermat-Tests (er ließe sich durch eine schnellere Power-Methode ein wenig optimieren, aber ich denke nicht, dass es dadurch extreme Vorteile geben würde) und nicht des Codes.
1.) notwendige Genauigkeiten durch kleinere Zahlen 2.) erheblich bessere Effitzienz, und wir reden hier von mehr als 1000 mal schneller !!
Zitat:
Abgesehen davon handelt es sich hier - wie gesagt - um ein kleines Übungsprogramm. Solche große Zahlen kommen hier wohl nicht vor.
Angenommen N wäre nur 49. Wir benutzen die Basis 3, ergo 3^(49-1) mod 49. 3^48 übersteigt schon die Fähigkeiten von Double Datentypen diese Zahl aufs letzte Bit exakt zu speichern. Aber eine modulare Exponentation arbeitet in jedem Schritt mit Zahlen bis maximal 48*48 -1, größer können die Zwischenergebnisse nicht werden, da ja nach jedem Schritt modular mit 48 reduziert wird. Wir könnten also 3^(49-1) mod 49 mit Byte-Arithmetik exakt ausrechnen. Angenommen N=10000 -> 3^9999 mod 10000. Es ist nun ein gewaltiger Unterschied ob man 3^9999 erst komplett ausrechnet und so eine 15849 Bit große Zahl mit 10000 modular reduzieren muß -> dividieren. Oder ob man schon während des Ausrechnens von 3^9999 in jedem Zwischenschritt mit mod 10000 reduziert. Bei diesem Weg benötigt man insgesamt 13 Schritte und somit 13 modulare Quadierungen + 8 modulare Multiplikationen mit Zahlen < 10000^2. Statt mit 2^15849 !!
Zitat:
Ersetzung der Power-Methode ist natürlich ratsam
Es ist also nicht nur ratsam die obige Power Funktion zu ersetzen, sondern es ist damit alles mathematisch korrekt funktionieren kann zwingend erforderlich. Weist du, es würde mich in keinster Weise stören wenn dein Vorschlag korrekt funktionieren würde, aber unschön, ineffizient oder so wäre. Aber in diesem Falle produziert dieser Test schon mit sehr kleinen Zahlen falsche Ergebnisse.
Zitat:
Zitat:
Der obige Code ist also programmtechnisch eine falsche Umsetzung der nötigen Mathematik. Du solltest dir an solchen Beispielen kein Beispiel nehmen.
Der benutzte Fließkommadatentyp reicht bei weitem nicht aus um zb. Zahlen > 2^48 exxakt zu berechnen. Leider beinhaltet die Formel eine Exponentation, und diese hat die blöde Eigenschaft eben aus kleinen Zahlen ganz gewaltig schnell sehr große Zahlen werden zu lassen. Und zweites arbeiten wir in mordularen Ringen, Kongruenzklassen und die können als Formel nur dann funktionierern wenn man die Zahlen Bitexakt berechnet. Einem Physiker reichen meistens 20 Stellen nach dem Komma aus, um Primzahlen zu erkennen mit Fermats einfacher Formel müssen wir aber mit Ganzzahlen absolut korrekt rechnen. Schau, ich möchte nicht dich oder irgendjemand sonst beleidigen oder kritisieren, aber fakt ist das obige Lösung als Umsetzung der Fermatschen Formel absolut untauglich ist. Tja, was soll ich nun anderes tuen und exakt dieses "falsch" klipp und klar aussprechen. Man könnte jetzt lange drumherumreden, um ja nicht als Nörgler abgestempelt zu werden, um ja nicht irgendwelche Gefühle zu verletzen. Das ist aber nicht mein Ding, falsch bleibt falsch, die Begründung dafür habe ich geliefert. Kritik ist doch nichts schlechtes und eine "höflicher" ausgedrückte Kritik macht doch dan kritisierten Fehler nicht weniger zum Fehler. Ehrlich gesagt, nervt es mich auch ein bischen das in heutiger Zeit alle so empfindlich auf ein par Worte in einem Forum reagieren. Das kostet doch alles Zeit.
Zitat:
Ich muss aber sagen, dass ich bei meinem Ursprungs-Posting nicht an die Fließkomma-Verwendung gedacht habe.
Zitat:
Allerdings hättest du auch deine Kritik ein wenig früher üben können, als die Funktion auf diese Art und Weise zu zerreißen.
Zitat:
Schlauerweise steht ja auch unter dem Source - sofern du weitergelesen hast - dass es sich hier um einen NICHT-Primzahltest handelt.
Gäbe es eine weitere Unterscheidung, als nur die Negation des Resultates, zwischen Primzahl-Test und Nicht-Primzahl-Test so würde dies bedeuten das es nicht nur Primzahlen und Zusammengesetzte Zahlen gibt sondern noch eine dritte oder vierte Form. Dies ist zum Glück nicht der Fall (oh und bitte wir reden bekanntermaßen von Ganzzahlen und nichts anderem) also ist es wurscht ob man eine Zahl auf Primzahl testet oder auf Nicht-Primzahl, in beiden Fällen wird man bei einer 100% richtigen Aussage der Funktion wissen um welchen Typus es sich handelt.
Zitat:
Zitat von Wikipedia:
Wenn man nur auf die Basis 2 testet, dann kann man nur bis 340 sicher sein, dass man zu 100% ein korrektes Ergebnis bekommt.
Zitat:
Ich weiß nicht genau, aber dein zweiter Post widerspricht sich ein wenig zum ersten ("Der Ansatz ist ja auch richtig.")
Der Ansatz, für einen Primzahltest, auf Fermat und den davon abgeleiteten und besseren Primzahltest zu verweisen, als Lösung eines Zahlenproblemes, ist absolut richtig. Falsch wäre als Lösung vorzuschlagen Blaue Schuhe beim OBI kaufen zu gehen. Nicht korrekt ist aber die all zu simplizistische Umsetzung der Fermatschen Formel mit Hilfe von Fließkommazahlen und in der falschen Zahlendomain also nicht modularen Restringen.
Zitat:
aber ich hab jetzt nur mal versucht mich ein wenig zu rechtfertigen...
Gruß Hagen |
Zitat |
Registriert seit: 21. Jul 2002 Ort: Bonn 5.403 Beiträge Turbo Delphi für Win32 |
#12
Hi Hagen,
hm, okay, verstanden worum es dir geht und mir sind auch ein paar Sachen etwas klarer geworden. Und entschuldige, wenn ich ein wenig giftig geantwortet habe.
Zitat:
Aber sicher doch, nämlich die mathematische Sicht. Wenn man schreibt A^(n-1) == 1 mod N dann zeigt dies an das man in einer Kongruenzklasse arbeitet, in einem modularem Restering. Das bedeutet technisch zB. das man auf der Linken Seite alles mod N rechnen kann, in jedem Schritt. Statt also 3^999 komplett ausrechnen zumüssen kann man auch (((((3*3 mod N) * 3) mod N * 3) mod N ... usw. rechnen. Dies produziert ausgehend von der mathematischen Schreibweise eine komplett andere technische Umsetzung.
Delphi-Quellcode:
function PowerMod(Base, Exponent, Modul: longint): longint;
var idx: longint; begin Result := -1; if (Exponent < 0) then Exit; Result := 1; for idx:=1 to Exponent do begin Result := (Result * Base) mod Modul; end; end; function IsNotPrime(a, n: longint): boolean; begin Result := PowerMod(a, n-1, n) <> (1 mod n); end;
Zitat:
fakt ist das obige Lösung als Umsetzung der Fermatschen Formel absolut untauglich ist
Zitat:
Gäbe es eine weitere Unterscheidung, als nur die Negation des Resultates, zwischen Primzahl-Test und Nicht-Primzahl-Test so würde dies bedeuten das es nicht nur Primzahlen und Zusammengesetzte Zahlen gibt sondern noch eine dritte oder vierte Form. Dies ist zum Glück nicht der Fall (oh und bitte wir reden bekanntermaßen von Ganzzahlen und nichts anderem) also ist es wurscht ob man eine Zahl auf Primzahl testet oder auf Nicht-Primzahl, in beiden Fällen wird man bei einer 100% richtigen Aussage der Funktion wissen um welchen Typus es sich handelt
Chris |
Zitat |
Registriert seit: 25. Jun 2003 Ort: Thüringen 2.950 Beiträge |
#13
Zitat:
aja, wenn aber nun der Test sagt "false" (also die Zahl ist nicht keine Primzahl), dann heißt das doch noch nicht, dass sie automatisch eine Primzahl ist, oder?
Ergo: wenn der Test 100% die Aussage bringt FALSE dann sollte es zu 100% bedeuten das die zahl eine Primzahl ist. Soweit zur analytisch hypothetischen Seite des Problemes. Worauf du aber nun hinauswillst ist der Fakt das man mit Fermats Formel eben nicht 100%tig sicher sein kann wenn er sagt die Zahl IST eine Primzahl. Sagt der Test die Zahl ist KEINE Primzahl dann sollte diese Aussage 100% richtig sein ! Mit Fermats Formel und allen anderen Pseudo Primzahl Test kann man also eine Nicht-Primzahl immer zu 100% exakt bestimmen aber eine Primzahl nur mit einer großen Wahrscheinlichkeit unterhalb 100%. Ergo: Wenn dein Test die Frage beantwortet "ist die Zahl zusammengesetzt" dann kann dein Test auf Basis der Fermatschen Formel sehr wohl zu 100% sicher diese Aussage treffen wenn er erkennt das es eine zusammengesetzte Zahl ist. Wenn der Fermatsche Test aber sagt es wäre eine Primzahl dann ist dies nicht 100% sicher. Ich weis es ist ein bischen kompliziert zu verstehen und auch ich habe einige Zeit gebracht es zu verdauen. Praktisch gesehen bedeutet das: Wenn Fermats Formel eine Zahl als Zusammengesetzte = Nicht-Primzahl ausweist dann mit 100% Sicherheit. Dies bedeutet aber NICHT das Fermats Formel jede zusammengesetzte Zahl wirklich findet ! Es gibt also zusammengesetzte Zahlen die Fermats Formel als "ich glaube es ist eine Primzahl" ausweist. Nun kommen wird dem Punkt näher zu deiner ersten Lösung mit Fließkomma-Power. Da deren Zahlenbereich auf Grund der Floats sehr schnell überschritten sind würde eine darauf basierende Funktion auch bei Zusammengesetzten Zahlen eine falsche Antwort liefern. Eben ganz im Gegensatz zu Fermatschen Formel. Das heist aber praktisch gesehen eben nicht das der Fermatsche Test jede zusammengesetzte Zahl auch wirklich findet ! Es ist also ein Unterschied ob man die Sicherheit betrachtet wann der Test eine Zahl als zusammengesetzt erkennt oder wie sicher man sich sein kann wenn er eine zusammengesetzte Zahl erkannt hat. Sagt Fermats Formel das eine Zahl zusammengesetzt ist dann kann man sich absolut sicher sein das diese Zahl eine zusammengesetzte, also Nicht-Primzahl ist. Wenn der Test aber sagt das es eine Primzahl ist dann besteht die minimale Wahrscheinlichkeit das es denoch eine zusammengesetzte Zahl ist. Der Test erkennt also nicht sicher ob eine Zahl nun zusammengesetzt oder prim ist, aber wenn er eine zusammengesetzte Zahl erkannt hat dann mit 100% Sicherheit. Wenn er eine Zahl als Primzahl ausweist dann kann man sich nicht 100% sicher sein. Deine Power Funktion auf Basis der Floats würde aber nun bei einer zusammengesetzten Zahl eben nicht mehr zu 100% sicher sein. Viel schlimmer noch, auf Grund der Ungenauigkeiten der Floats könnte sie Zahlen als prim ausweisen die ein korrekt umgesetzter Test als zusammengesetzt erkennen würde. So jetzt muß ich mich erstmal wieder zusammensetzen um prim zu werden Es reicht.
Zitat:
Delphi-Quellcode:
function PowerMod(Base, Exponent, Modul: longint): longint;
var idx: longint; begin Result := -1; if (Exponent < 0) then Exit; Result := 1; for idx:=1 to Exponent do begin Result := (Result * Base) mod Modul; end; end; Das ist schonmal ein richtiger Ansatz aber eben wieder simplizistisch bzw. straight forward. Diese Methode spart nichts an Rechenzeit, leider. Einfaches Beispiel: 3^8 mod X du machst 3 mod X * 3 mod X * 3 mod X... abgekürzt also 3*3*3*3*3*3*3*3 wobei nach jeder Multiplikation modulo gerechnet wird. Wie wäre es aber mit (((3^2 mod X)^2 mod X)^2 mod X, wobei nun ^2 eine Quadierung ist ? Für 3^8 benötigen wir nun nur noch 3 modulare Quadrierungen statt 8 modulare Multiplikationen. Man muß dabei wissen das eine Quadrierung auf einem Rechner 150% schneller ausgeführt werden kann als eine generische Multiplikation zweier gleichgroßer Multiplikaten. Dieser Faktor von 150% bzw. 1.5 ist ein mathematisch bewiesener Faktor und die heutzutage theoretisch angenommene und mathematisch bewiesene maximale Schranke. D.h. aus Sicht heutiger Mathematik kann man nicht schneller als 1.5 mal schneller Quadrieren als Multiplizieren. Aber dies reicht uns ja schon aus, denn es bedeutet das ein Algorithmus der mit gleicher Anzahl an Quadrierungen arbeitet statt Multiplikationen immer bis zu 1.5 mal schneller sein kann. Ich persönlich konnte in meinem DECMath exakt die 1.5 praktisch bestätigen. Mit normalen Integern oder der ineffizienten Int64 Borland Funktionen kann man diesen Faktor nicht nachweisen. So wie kommen wir aber zu einem Algo. der die korrekte Sequenz von Quadrierungen+Multiplikationen der Exponentation ermitteln kann ? Betrachten wir 3^9: Die kürzeste Formel lautet 3^8 * 3^1 = 3^(8 +1) weil 8 zerlegt werden kann in 2^3, ergo 3^2^2^2*3 wobei in jedem Schritt modular reduziert werden muß. Für 3^9 mod X benötigen wird also 3 Quadrierungen und 1 Multiplikation. Nun schauen wir uns mal den Exponenten 9 als Binärzahl an 1001b. Wir wisen das diese Zahl 4 Bits hat und 2 Bit sind auf 1 gesetzt. Wir schneiden das oberste Bit ab, ignorieren es, es bleiben 3 Bit Größe und 1 Bit auf 1 gesetzt -> ergibt 3 Quadrierungen + 1 Multiplikation. Anderes Beispiel 3^11: 11 in binär ist 1011b wir schneiden oberstes Bit ab -> 011b es bleiben 3 Bit Gesamtgröße und 2 Bits gesetzt ergo 3 Quadrierungen + 2 Multiplikationen, nämlich ((3^2)^2*3)^2*3. Unsere Schleife benötigt 3 Durchläufe die man an den Klammern erkennt, also 3 Quadrierungen und 2 Multipliaktionen. Der Algo sähe als nun so aus
Delphi-Quellcode:
Diese Methode nennt sich Modulare Exponentation nach der Binären Links-nach-Rechts expansion. Es gibt noch einige andere, zb. rekursive von Rechts-nach-Links oder trinäre mit +- Basen zb. in der Elliptischen Kurven Multipliaktion häufig verwendet. Es gibt einen ganzen Wissenschaftszweig der sich mit dem Problem der Zerlegung des Exponenten in den kürzesten Weg mit der geringsten Anzahl an Quadrierungen und Multipliaktionen forscht. Dieses Pronlem in ein angeblich NP vollständiges Problem und fällt auch in die große Gruppe der Kantenioptimierungen, Wegealgorithmen etc.pp.
Base := Base mod Modulus;
Result := Base; for I := HighestBit(Exponent) -1 downto 0 do begin Result := (Result * Result) mod Modulus; if BitIsSet(Exponent, I) then Result := (Result * Base) mod Modulus; end; Aber obiger Pseudocode ist "nearly optimal" und findet aufeinfache Weise fast immer den kürzesten Weg, zumindestens ausreichend für unsere Bedürfnisse. Gruß Hagen |
Zitat |
Ansicht |
Linear-Darstellung |
Zur Hybrid-Darstellung wechseln |
Zur Baum-Darstellung wechseln |
ForumregelnEs ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.
BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus. Trackbacks are an
Pingbacks are an
Refbacks are aus
|
|
Nützliche Links |
Heutige Beiträge |
Sitemap |
Suchen |
Code-Library |
Wer ist online |
Alle Foren als gelesen markieren |
Gehe zu... |
LinkBack |
LinkBack URL |
About LinkBacks |