![]() |
unerklärlicher fehler bei nichtprimzahl-test
hi, ich habe den code aus chackotays
![]() "[Fehler] Unit1.pas(63): E2015 Operator ist auf diesen Operandentyp nicht anwendbar [Warnung] Unit1.pas(63): W1023 Vorzeichenbehaftete und -lose Typen werden verglichen - beide Operanden werden erweitert" Zeile 63 und umgebende sehen so aus:
Code:
wenn mehr quelltext benötigt wird, kann ich gerne noch mehr rausrücken ;-)
58 implementation
59 {$R *.dfm} 61 function IsNotPrime(const a, n: longint): boolean; 62 begin 63 Result := (Power(a, n-1) mod n) <> 1; 64 end; 65 procedure TForm1.createnewClick(Sender: TObject); vielen dank schonmal für eure bemühungen, bene |
Re: unerklärlicher fehler bei nichtprimzahl-test
Power gibt immer einen real-typ zurück. mod ist für Integer-Typen gedacht.
Mach 'n round um das power rum. |
Re: unerklärlicher fehler bei nichtprimzahl-test
Zitat:
|
Re: unerklärlicher fehler bei nichtprimzahl-test
also ich hab jetz beides getestet, funktinieren tun beide lösungen, ich werde mich jetzt mal über den unterschied informieren
edit: also ich hab mir jetzt beides angesehen und ich denke es sollte egal sein, was ich verwende, da ja eigentlich sowiso nur ganzzahlige ergebnisse erhalten sollte |
Re: unerklärlicher fehler bei nichtprimzahl-test
Sonderlich grosse Primzahlen kannst du mit dem Test aber nicht testen, oder? Da gibt es doch wunderschöne Optimierungen, die ganz ohne Power auskommen. Suche mal hier in der DP, negaH hat einen sehr sehr schnellen Primzahltester auf der Basis geschrieben.
|
Re: unerklärlicher fehler bei nichtprimzahl-test
das programm ist auch nur ein rechentrainer für kinder, da werden die zahlen nicht wirklcih gross, trotzdem danke für den tipp, werde mir das mal ansehen
|
Re: unerklärlicher fehler bei nichtprimzahl-test
Liste der Anhänge anzeigen (Anzahl: 1)
Delphi-Quellcode:
Also das kann garnicht funktionieren.
Result := (Power(a, n-1) mod n) <> 1;
Der Fermat-Test ist so definiert A ^ (N-1) mod N |= 1 mod N dies bedeutet das wir in modularen Ringen arbeiten. Angenommen A = 3 und N = 1000 dann würde Power(A, N-1) == 3^999 werden. Diese riesige Zahl kann aber in einem Fließkommadatentyp nicht mehr EXAKT gespeichert werden. Ergo: mit Fließkommazahlen wird der Wert 3^999 gerundet/abgeschnitten gespeichert. Die nachfolgende modulare Division mit N wird also je nach Rundungsfehler in den Fliekommazahlen ein nicht mehr mathematisch aussagekräftiges Resulat liefern. Der obige Code ist also programmtechnisch eine falsche Umsetzung der nötigen Mathematik. Du solltest dir an solchen Beispielen kein Beispiel nehmen. Der richtige Weg wäre die Implementation einer eigenen modularen Exponentation die mit Ganzzahlen arbeitet. Beim Fermat Test MUSS jedes einzelne Zahlenbit absolut exakt berechnet werden, Fließkommazahlen haben darin nichts zu suchen. Es ist besser hier in Forum nach meinem schnellen Primzahltest zu suchen. Anbei mein Code zum schnellen Test einer Zahl < 2^32 auf Primzahleigenschaft. Der normale Fermat Test wie oben gezeigt würde nämlich auch Zusammengesetzte Zahlen als Primzahlen ausweisen die garkeine Primzahlen sind. Ich weis nicht was deine Kids davon halten sollen wenn sie durch dummen Zufall eine sogenannte Carmichael Zahl eingeben und dein Program sagt ads es eine Primzahl wäre, obwohl ads natürlich bei Carmichaelzahlen falsch ist. Gruß Hagen |
Re: unerklärlicher fehler bei nichtprimzahl-test
gibts die überhaupt unter 100?
naja egal, vielen danke für dein script, werde mich bemühen das ordentlich einzubinden, denn ich habe mit dem jetzigen eh einige probs. PS: chacko hatte mir das empfohlen unter der vorraussetzung, dass ich nur herausfinden muss, ob es keine primzahl ist. |
Re: unerklärlicher fehler bei nichtprimzahl-test
Der Ansatz ist ja auch richtig. Nur muß man eben bedenken das einfache Primzahltests, und Fermat ist wohl einer der einfacheren, bei ganz bestimmten zusammengesetzten Zahlen scheitern. Diese Zahlen sind zb. die Carmichaelzahlen.
Auch mein Primzahltest basiert auf einem abgewandelten Fermat Verfahren. Auch dieser sogenannte SPP, strong Pseudo Primality Test, kann an den Carmichaelzahlen scheitern. ABER! mein Test benutzt eine Kombination aus mehreren SPPs zu festen Basen die mit allen Zahlen bis < 4759123141 = $11BAA74C5 schon duch andere Mathematiker ausgetestet worden sind. Es ist also garantiert das bei diesem Test mit Cardinals < 2^32 die Rückgabe der Funktion eindeutig eine Primzahl von einer zusammengesetzte Zahl unterscheidet. Einbinden tuest du diese Unit ganz einfach. In der Uses Klausel deines Programmes "IsPrimeHRUnit" hinzufügen und in deinem Code dann IsPrime(Zahl) aufrufen, das wars. Das meine Unit nun in Assembler gecodet ist und teilweise sehr aufwendige Verfahren benutzt liegt einzigst daran das sie auf einem Programierer Contest entstanden ist. Dabei ging es eben darum so schnell wie auf heitigen CPUs möglich zu ermitteln ob einen Zahl 2^32 eine Primzahl ist. Falls du weitergehendes Interesse daran hast dann schau mal hier rein ![]() Gruß Hagen |
Re: unerklärlicher fehler bei nichtprimzahl-test
Hi Hagen,
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)? Zitat:
Zitat:
Natürlich kannst du Recht haben, dass dies kein optimaler Test ist und die Umsetzung vielleicht nicht zur Befriedung eines höheren Mathematikers ist, allerdings habe ich mit dem Mathe-Studium noch nicht angefangen und Assembler kann ich zu meiner Schande auch nicht. Hilft also nichts, bleibt mir nur die einfache, oben gepostete Lösung übrig. Was ich damit sagen will ist nur, dass ich bisher nicht die Möglichkeit hatte grundlegend daran was zu ändern. Er Ersetzung der Power-Methode ist natürlich ratsam, aber eine schnelle ließe sich wohl nur mit Assembler programmieren, jedoch hat bisher niemand diesen konstruktiven Vorschlag gemacht. Zitat:
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. :roll: Zitat:
Zitat:
Und wenn es dich wirklich stört, dass darin keine hoch-mathematischen Optimierung drinstecken: ich habe es bisher nicht geschafft Mathevorlesungen zu besuchen - dummerweise gibt es für mich noch sowas wie Schule. Für mich zumindest hat es gereicht, dass ich bereits mehrmals mit dem Fermattest zutun hatte und ich denke nicht, dass man mich dafür zerreißen kann, weil ich es nicht zu 100% perfekt umgesetzt habe - zumal sich beim Posting als Vorschlag kein Feedback bekommen habe, obwohl der Thread monatelang für Kritik freigegeben war. Ich weiß nicht genau, aber dein zweiter Post widerspricht sich ein wenig zum ersten ("Der Ansatz ist ja auch richtig."), aber ich hab jetzt nur mal versucht mich ein wenig zu rechtfertigen... :roll: Chris |
Re: unerklärlicher fehler bei nichtprimzahl-test
Zitat:
oder 0 == 0 mod N == N mod N Zitat:
Zitat:
1.) notwendige Genauigkeiten durch kleinere Zahlen 2.) erheblich bessere Effitzienz, und wir reden hier von mehr als 1000 mal schneller !! Zitat:
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:
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:
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:
Zitat:
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. Zitat:
Zitat:
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:
Gruß Hagen |
Re: unerklärlicher fehler bei nichtprimzahl-test
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:
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:
Zitat:
Chris |
Re: unerklärlicher fehler bei nichtprimzahl-test
Zitat:
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:
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 |
Alle Zeitangaben in WEZ +1. Es ist jetzt 13:57 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz