![]() |
Re: Faktorisierung
ok ich bräuchte dann nochmal eure Hilfe.
Und zwar beim Statusbalken. Ich hab mir folgendes überlegt: Ich habe zwei Werte: i -> Variable die alle Werte bis zur Wurzel der zu faktorisierenden Zah durchgeht a -> Wurzel der zu faktorisierenden Zahl. Wenn ich jetzt wissen will wieviel Prozent i von a ist. Rechne Ich i/a*100. Da ich mit Integer Werten arbeite rechne ich aber erst i*100 und das Ergebnis davon durch a, was aufs selbe rauskommt. Mein Code sieht jetzt so aus:
Delphi-Quellcode:
Das funktioniert soweit auch sehr gut. Es wird alles richtig angezeigt, nur wenn ich folgende Primzahl teste:
Nmul(z,i,100);
Ndiv(z,a); Progressbar1.Position:= Nint32(z); Application.Processmessages; 2813418473392999 dann dauert das auf meinem System über 2 Minuten bis das Programm mir anzeigt das es eine Primzahl ist. Während dessen wächst der Statusbalken brav. Nehme ich jetzt aber den oben geposteten COde raus, braucht das Programm nur noch 4 Sekunden(!). Das heisst der Code bremst das Programm immens ab. ALso müsste ich ihn seltener ausführen lassen. HAt jemand eine Idee wie ich das bewerkstellige, bzw. am besten bewerkstellige. Ich könnte natürlich alle Variablen global definieren, also aus der eigentlichen Faktorisierungsprozedur rausholen und mit einem Timer alle paar Sekunden den Status abfragen, aber vielleicht gibts da noch eine bessere methode?! danke schonmal :) edit: wobei sich dieser Balken eigentlich sowieso nur bei Primzahlen lohnt, da bei allen anderen Zahlen sowieso vor der Wurzel der Zahl abgebrochen wird, wenn die faktorisierung abgeschlossen ist. Von daher würde der Balken irgendwo bei einem drittel oder so abbrechen, was auch wieder blöd wäre.... |
Re: Faktorisierung
rechne
Delphi-Quellcode:
oder so
var
Root,Steps,Counter: begin Root := N^0.5; Steps := N / Root / 2 / 100; Counter := Steps; repeat if Counter <= 0 then begin ProgressBar.Position := Root / Prime * 100; Counter := Steps; end; Counter := Counter -1; until .... end;
Delphi-Quellcode:
Im letzten Fall wird die ProgressBar nur 4 mal pro Sekunde = 250ms aktualisiert. Ich würde diese Methode vorziehen da sie die ProgressBar unabhängig vom eigentlichen Programmcode in einem exakten zeitlichen Interval aktualisert.
var
Tick: Cardinal; begin Tick := GetTickCount + 250; repeat if GetTickCount >= Tick then begin Tick := GetTickCount + 250; ProgressBar.Position := Prime / Root * 100; ProgressBar.Update; end; until ... end; Ansonsten solltest du mit NIsProbablePrime(N) VOR jeder Trial Divison auf Prim überprüfen (aber nur bei großem N -> NSize(N) > 32). NIsProbablePrime() soll laut Pomerance (anerkannter Mathematiker) erst bei Zahlen größer 10^1000 eine Falschantwort liefern. Pomerance hat ein Preisgeld ausgesetzt für denjenigen der als erster eine Zahl findet bei dem sein Primzahltest diese Zahl als Primzahl ausweist obwohl es keine ist. Das ist bei Pseudo-Primzahl-Tests immer eine Wahrscheinlichkeit, weshalb es eben nur ein Pseudo-Primzahl-Test ist. Bisher hat noch kein Mensch eine solche Zahl gefunden, Pomerance sitzt also noch auf seinem Preisgeld. Gruß Hagen |
Re: Faktorisierung
Deine zweite Methode gefällt mir. Ich werd das mal einbauen, danke :)
Zitat:
|
Re: Faktorisierung
Zitat:
Allerdings wenn du NSPP(N, [1,2]) statt NIsProbablePrime(N) benutzt dann wird intern keine Trial Division mehr durchgeführt, das wäre dann schneller. In meiner DEMO zum DECMath solltest du dir mal die Unit TestUnit.pas genauer anschauen. Darin dürftest du 3 Funktion finden
Delphi-Quellcode:
Das sind alles Faktorizations-Verfahren.
function NPollardRho(var D: IInteger; const N: IInteger): Boolean;
function NPollardPM1(var D: IInteger; const N: IInteger; Bound: Cardinal = 0): Boolean; function NWilliamsPP1(var D: IInteger; const N: IInteger): Boolean; Gruß Hagen |
Re: Faktorisierung
Probiere mal die Zahl 18303891083514198529 == 1919369 * 9536410707641 mit Methode 3 aus.
Gruß Hagen |
Re: Faktorisierung
Vielen Dank für den Hinweis. Hat etwas gedauert bis ich mich rangesetzt hab, weil ich irgendwie keine Lust hatte den Fehler zu suchen, wenn er bei einer einzigen Zahl vorkommt. Es war aber nur ein Ausgabe Fehler. Das heisst er hat die 2 Faktoren gefunden, aber an einer bestimmten Stelle im Code wurde der Wert prim trotzdem auf true gesetzt, so dass die Meldung ** ist Prim ausgegeben wurde. Ich lade die neue Version gleich hoch.
edit: direkt das nächste Problem: Ich kann den Vorgang bei Methode 3 nicht abbrechen lassen. Ich sage bei jedem Schleifendurchlauf: Application.Processsmessages; genau wie bei Methode 1 und da funktioniert es. Bei Methode 3 kann ich aber nichtmal aufden Button der den Vorgang abbrechen soll klicken, die Anwendung hängt sich einfach auf. Gibts da noch einen Trick für? |
Re: Faktorisierung
Zitat:
Gruß Hagen |
Re: Faktorisierung
naja mein Code sieht grob so aus
Delphi-Quellcode:
Mit einem Klick auf Button 2 kann man die Variable abbruch auf true setzen und damit die Schleife abbrechen. Wie gesagt funktioniert das bei Methode 1, bei Methode 2 aus irgendeinem Grund jedoch nicht.
while (true) {Abfragen} and (not abbruch) do begin
... ... Application.Processmessages; end; Daher meine Frage: Gibt es noch eine andere Methode die Applikation vor dem "aufhängen" zu bewahren? |
Re: Faktorisierung
ich mache solche dinge immer so
Delphi-Quellcode:
1.) FInAction: Integer wird als Field in deinem TForm deklariert. FInAction kann 3 Staties annehmen
procedure TForm1ButtonClick(Sender: TObject);
var Tick: Cardinal; begin if FInAction = 0 then try Inc(FInAction); Button.Caption := 'Abbruch'; Tick := GetTickCount + 100; while FInAction = 1 do begin ... if Tick >= GetTickCount then begin Inc(Tick, 100); Application.ProcessMessages; end; end; finally FinAction := 0; Button.Caption := 'Start'; end else begin Inc(FInAction); // ist >= 1, wir setzte FInAction auf > 1, bedeutet Abbrechen Button.Caption := 'beende'; end; end; FInAction == 0, bedeutet nichts wird aktuell berechnet und zb. Button hat die Caption == "Start" FInAction == 1, bedeutet unsere Berechnung läuft, Button.Caption = "Abbrechen" FinAction >= 2, bedeutet unsere Berechnung soll auf Benutzerwusch hin beendet werden 2.) FInAction macht also die Methode .ButtonClick() vor Rekursionen sicher das diese Methode nicht reentrant sein kann -> weil wir ja Application.ProcessMessages aufrufen 3.) Application.ProcessMessage wird in einem festen Intervall aufgerufen, hier alle 100 Millisekunden. Das macht deine Berechnung weitaus schneller In deiner TForm1.OnCloseQuery() Methode solltest du nun Abfragen ob FInAction == 0 ist. Wenn ja, dann kannst du das Form schließen lassen, wenn nein dann wird FInAction inkrementiert und OnCloseQuery verhindert das Form zu schließen. Gruß Hagen Gruß Hagen |
Re: Faktorisierung
Ein kleiner Dreher ist drin: beim Vergleich der 'Ticks' müssen die beiden Seiten vertauscht werden:
Delphi-Quellcode:
Gruß Hawkeye
if GetTickCount >= Tick then
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 03:08 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-2025 by Thomas Breitkreuz