Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi verzweifle an fließkommazahlen....:-( (https://www.delphipraxis.net/59749-verzweifle-fliesskommazahlen.html)

DJ_Tom 28. Dez 2005 04:56


verzweifle an fließkommazahlen....:-(
 
Hallo,

ich sitze hier schon stundenlang an einem vermutlich simplen Problem aber ich weiß ehrlich gesagt absolut nicht mehr weiter... :gruebel: :wall: :(

Also folgendes:

Ich schreibe mir in das folgende Array ein paar Speicherinhalte

Code:
buffer:array[1..100000] of double;
wenn ich mir das zur Laufzeit ansehe, was da so drin steht dann ist das z.b. sowas hier: 2.121995791e-314

Jetzt möchte ich diese Zahl mit einer Integer bzw. Longint vergleichen aber egal was ich anstelle ob ich versuche die mit round auf ne Integer-Zahl zu runden oder einfach per floattostr zu nem string konventieren will bekomme ich immer den fehler:

Üngültige Gleitkommaoperation

Wie kann man so ne Zahl handlen damit man sie mit ner Integer-zahl vergleichen kann...bzw. wie bekomme ich die Integer-Zahl auf dieses Format damit ich sie direkt vergleichen kann...

Das nächste Problem ist nämlich die Umwandlung der Double dauert ziemlich lang daher wäre es praktisch wenn man die Integer Zahl anpassen könnte....

Wäre Euch sehr dankbar wenn Ihr da ne Idee hättet....

Bis denne....

marabu 28. Dez 2005 07:57

Re: verzweifle an fließkommazahlen....:-(
 
Herzlich willkommen in der Delphi-PRAXiS, DJ_Tom.

2.122e-314 ist aus Integer-Sicht nahe bei 0. Was willst du da noch vergleichen? Ansonsten funktionieren Round() und Trunc() auch in Verbindung mit Int64 - zumindest mit meiner Delphi Version.

Grüße vom marabu

Amateurprofi 28. Dez 2005 08:04

Re: verzweifle an fließkommazahlen....:-(
 
Zitat:

Zitat von DJ_Tom
Hallo,

wenn ich mir das zur Laufzeit ansehe, was da so drin steht dann ist das z.b. sowas hier: 2.121995791e-314

Jetzt möchte ich diese Zahl mit einer Integer bzw. Longint vergleichen aber egal was ich anstelle ob ich versuche die mit round auf ne Integer-Zahl zu runden oder einfach per floattostr zu nem string konventieren will bekomme ich immer den fehler:

Üngültige Gleitkommaoperation

Wie kann man so ne Zahl handlen damit man sie mit ner Integer-zahl vergleichen kann...bzw. wie bekomme ich die Integer-Zahl auf dieses Format damit ich sie direkt vergleichen kann...

Bis denne....

Bei mir wird die oben genannte zahl ohne jede Fehlermeldung
a) mit Round in einen Integerwert (nämlich 0) umgewandelt
b) mit FloatToStr korrekt ausgegeben.

Bei anderen Werten, (die den Bereich eines Integers überschreiten) wird natürlich die Round Funktion nicht mitspielen, FloatToStr sollte aber funktionieren. Aber es gibt ein paar spezielle Werte, bei denen die FPU eine Exception auslöst.

Zitat:

Ich schreibe mir in das folgende Array ein paar Speicherinhalte
Ich vermute, Du hast keine korrekten Double-Werte, sondern, wie auch immer, irgendwelche Daten in das Array gestellt. Nicht jeder Wert der im Speicher stehen kann wird auch als gültige Zahl interpretiert.

Velleicht beschreibst Du mal, wie Du das Array gefüllt hast.

DJ_Tom 28. Dez 2005 13:33

Re: verzweifle an fließkommazahlen....:-(
 
erstmal danke für die schnellen antworten....

also zz benutzte ich folgenden code:

Code:

     a:=16777215;
     while a < 268435455 do
     begin
          readprocessmemory(HandleWindow, ptr(a),@buffer, sizeof(buffer), bytesread);

          for b:= 1 to 100000 do
          begin
               if buffer[b] = MeineGesuchteIntegerZahl then
               begin
                    //habe wert gefunden...                  
               end;
          end;

          a:=a+100000;
     end;
ich habe einfach mal angenommen das meine gesuchte zahl im bereich FFFFFF bis FFFFFFF liegt, dass müßte eigentlich immer reichen....

wenn ich den wert mit artmoney suche dann muss ich nach einem "float 8 Byte" wert suchen

oder gibt es eine bessere möglichkeit den speicher nach einer float 8 byte zahl zu durchsuchen?

bye
Tommy

Amateurprofi 28. Dez 2005 14:29

Re: verzweifle an fließkommazahlen....:-(
 
Wenn ich das richtig verstehe, dann transferierst Du mit readprocessmemory einen bestimmten Speicherbereich in Deinen Buffer und nimmst einfach als gegeben an, daß der Speicherbereich den Du in den buffer lädst ausschließich aus Double-Werten besteht.
Wer sagt Dir denn, daß das so ist ?
Und dann verläßt Du Dich darauf, daß auch tatsächlich der Buffer vollständig gefüllt ist.
Die tatsächlich geladene Anzahl Bytes steht in bytesread, und nur auf den Wert solltest Du Dich verlassen.

marabu 28. Dez 2005 16:12

Re: verzweifle an fließkommazahlen....:-(
 
Hallo Tommy,

was auch immer du vorhast - die Suche nach einem double value funktioniert ohne Konvertierungsroutinen. Verwende einfach SysUtils.CompareMem() und alles wird gut.

Grüße vom marabu

DJ_Tom 28. Dez 2005 20:04

Re: verzweifle an fließkommazahlen....:-(
 
@Amateurprofi
hmmm ja hast schon recht aber wie soll ich denn nur die double werte auslesen?

das mit dem bytesread klingt logisch sollte man berücksichtigen...

@marabu
:thumb:
erstmal thx die compareMem funktion ist wirklich spitze....
wenn ich weiß welche adresse ich auslesen muß funktioniert das mit der funktion super, aber problematisch wird es immer dann wenn ich versuche den speicher in ein array zu packen und später wieder auszuwerten

und wie mir scheint kann compareMem ja nicht direkt speicherinhalte von anderen programmen vergleichen oder?!

also das ganze funktion wenn ich den buffer als normale double deklariere und jede adresse einzeln durchgehe nur das dauert bei dem umfang des durchzugehenden speichers natürlich ewig...
daher nehme ich mal an man muß schon sowas wie mit dem array machen oder? :gruebel:

marabu 28. Dez 2005 21:00

Re: verzweifle an fließkommazahlen....:-(
 
Ich versuche gerade zu verstehen, was du da eigentlich machst. Du suchst einen Integerwert im Hauptspeicher eines anderen Programms? Dazu besorgst du dir den Speicherinhalt in großen Blöcken. Du scheinst davon auszugehen, dass dein Integer-Wert als Double mit festem Alignment gespeichert ist. Darüberhinaus gibt es noch die Fallstricke, auf die dich Amateurprofi hingewiesen hat.

Wenn ein binärer Vergleich zulässig ist, dann kannst du deine Schleife über das Array dadurch beschleunigen, dass du einen Zeiger schiebst:

Delphi-Quellcode:
var
  pd: PDouble;
  d: Double;
  i: integer;
begin
  d := 123456;
  pd := @buffer[1];
  for i := 1 to 100000 do // beachte die Obergrenze
  begin
    if pd^ = d
      then Break
      else Inc(pd);
  end;
  // d gefunden bei index i, wenn i <= 1000000
end;
marabu

Letzten Kommentar präzisiert - wegen Klaus...

Amateurprofi 29. Dez 2005 08:44

Re: verzweifle an fließkommazahlen....:-(
 
marabu: sehr schöne und schnelle Lösung
Ich würde das dann aber besser so formulieren
Delphi-Quellcode:
var
  pd: PDouble;
  d: Double;
  i: integer;
begin
  d := 123456;
  pd := @buffer[1];
  for i := 1 to 100000 do // beachte die Obergrenze
  begin
    if int64(pd^) = int64(d) then
    begin
      // d gefunden bei index i
      exit;
    end else Inc(pd);
  end;
  // d nicht gefunden
end;
Warum :
Wenn der Wert nicht gefunden wurde kommt man nach Beendigung der for-schleife auch zu Deinem "Gefunden" Abschnitt.

Gruß, Klaus

DJ_Tom 29. Dez 2005 14:05

Re: verzweifle an fließkommazahlen....:-(
 
also zum auswerten is das ja schon so ne prima sache muß ganz ehrlich sagen das mit den zeigern is nicht so meine welt... :?

aber für das durchsuchen des speichers fehlt mir noch die ultimative lösung... :gruebel:

himitsu 29. Dez 2005 14:22

Re: verzweifle an fließkommazahlen....:-(
 
Ich muß wohl wirklich endlich mal den Fehler finden, damit ich mein kleines UCC komlett veröffentlichen kann. -.-''

Na ja, darin hab ich zwar nichts direkt für's Double, aber LargeWord macht's ja och :mrgreen:
Delphi-Quellcode:
var
  pd: PDouble;
  d: Double;
  i: integer;
begin
  i := FindData(PLargeWord(@d)^, pd, 100000) + 1;
Das Ergebnis der Funktion kann man mit dem von POS vergleichen, nur daß der Index hier bei 0 anfängt.
nichts gefunden: -1
Index der ersten Übereinstimmung: >=0


So und hier noch die entsprechende Funktion:
Delphi-Quellcode:
Function FindData(SerarchWord: LargeWord; Data: Pointer; Count: LongInt): LongInt;
  ASM
    PUSH   EBX
    TEST   &Data, &Data
    JE     @Exit
    TEST   &Count, &Count
    JLE    @Exit
    MOV    ECX, &Count
    MOV    EBX, DWORD PTR [&SerarchWord]
    MOV    EDX, DWORD PTR [&SerarchWord + 4]
    JMP    @InLoop

    @Loop:
    ADD    &Data, 8
    DEC    ECX
    JECXZ  @Exit
    @InLoop:
    CMP    EBX, [&Data]
    JNE    @Loop
    CMP    EDX, [&Data + 4]
    JNE    @Loop
    POP    EDX
    SUB    EAX, EDX
    SHR    EAX, 3
    POP    EBX
    POP    EBP
    RET

    @Exit:
    MOV    EAX, -1
    POP    EBX
  End;
Falls nötig, dann kann LargeWord auch in Int64 geändert werden.

Und wenn es jemanden interessiert, folgendes stünde och noch zur Verfügung.
Delphi-Quellcode:
Function FindData(SerarchWord: Byte;     Data: Pointer; Count: LongInt): LongInt; Overload;
Function FindData(SerarchWord: Word;     Data: Pointer; Count: LongInt): LongInt; Overload;
Function FindData(SerarchWord: LongWord; Data: Pointer; Count: LongInt): LongInt; Overload;
Function FindData(SerarchWord: LargeWord; Data: Pointer; Count: LongInt): LongInt; Overload;
Function FindData(SerarchWord: ShortInt; Data: Pointer; Count: LongInt): LongInt; Overload;
Function FindData(SerarchWord: SmallInt; Data: Pointer; Count: LongInt): LongInt; Overload;
Function FindData(SerarchWord: LongInt;  Data: Pointer; Count: LongInt): LongInt; Overload;
Function FindData(SerarchWord: LargeInt; Data: Pointer; Count: LongInt): LongInt; Overload;
Function FindData(SerarchData: Pointer;  Data: Pointer; Count: LongInt; ElementSize: LongInt): LongInt; Overload;
PosEx wird es nicht vorläufig nicht geben, da dieses ja eigentlich nicht benötigt wird:
Code:
i := FindData(PLargeWord(@d)^, pd [color=#ff0000]+ Offset[/color], 100000 [color=#ff0000]- Offset[/color]) + 1;

DJ_Tom 29. Dez 2005 15:02

Re: verzweifle an fließkommazahlen....:-(
 
Code:
Function FindData(SerarchWord: LargeWord; Data: Pointer; Count: LongInt): LongInt;
also verstehe ich das jetzt richtig das is ne funktion mit der ich prüfen kann ob ein largeword in dem pointer x enthalten ist?! und der rückgabewert sagt mir wo ich das im pointer finde???

aber das is noch nicht direkt zum durchsuchen von speicherbereichen von ext. programmen gedacht?

also das was ich hier z.b. machen will:

Code:
readprocessmemory(HandleWindow, ptr($FFFFF),@buffer, sizeof(buffer), bytesread);

himitsu 29. Dez 2005 15:48

Re: verzweifle an fließkommazahlen....:-(
 
Richtig erkannt.
Und da man dieser Funktion ja jeden beliebigen Pointer übergeben kann, ist es auch dafür verwendbar, es muß nur ein Lesezugrif auf den entsprechenden Speicherbereich möglich sein.

Außerdem holst du dir ja mit ReadProcessMemory eine Kopie des Speichers, der anderen Anwendung, in dein eigenes Programm und greifst dann auf diese Kopie (Buffer) zu.
Delphi-Quellcode:
ReadProcessMemory(HandleWindow, Ptr($FFFFF), @Buffer, SizeOf(buffer), BytesRead);
i := FindData(PLargeWord(@d)^, @Buffer, BytesRead div 8);

DJ_Tom 29. Dez 2005 17:05

Re: verzweifle an fließkommazahlen....:-(
 
hmmm ja aber das hieße ich müßte um einen kompletten bereich durchzugehen folgendes machen:

Code:
var buffer:double;
...

     a:=$FFFFFF;
     repeat
           ReadProcessMemory(HandleWindow, Ptr($a), @Buffer, SizeOf(buffer), BytesRead);
           i := FindData(PLargeWord(@d)^, @Buffer, BytesRead div 8);

           if i > -1 then
           begin
               //gefunden
           end;

           inc(a);
     until a = $FFFFFFF;
aber das dauert doch ewig um die range durchzugehen.... :(

kann man das nicht irgendwie optimieren :?:

himitsu 29. Dez 2005 17:15

Re: verzweifle an fließkommazahlen....:-(
 
Im Grunde nicht, aber du holst dir ja jedesmal nur 8 Byte ab.
Was dann diesem Code entsprechen täte :zwinker:
Delphi-Quellcode:
var buffer:double;
...

     a:=$FFFFFF;
     repeat
           ReadProcessMemory(HandleWindow, Ptr($a), @Buffer, SizeOf(buffer), BytesRead);

           if d = buffer then
           begin
               //gefunden
           end;

           inc(a, 8);
     until a = $FFFFFFF;
Versuch es mal damit:
Code:
[color=#ff0000]var buffer: packed Array[0..131071] of double;[/color] // 131072 * 8 = 1 MB
...

     a:=$FFFFFF;
     repeat
           ReadProcessMemory(HandleWindow, Ptr($a), @Buffer, SizeOf(buffer), BytesRead);
           i := FindData(PLargeWord(@d)^, @Buffer, BytesRead div 8);

           if i > -1 then
           begin
               //gefunden
           end;

           inc(a, SizeOf(buffer));
     until a = $FFFFFFF;

DJ_Tom 29. Dez 2005 20:18

Re: verzweifle an fließkommazahlen....:-(
 
wenn ich das so nehme meckert er schon beim PLargeWord das würde er net kennen...ändere ich das auf pint64 z.b. funzt es nicht... :wall:

himitsu 29. Dez 2005 20:35

Re: verzweifle an fließkommazahlen....:-(
 
Na ja, das Problem ist ja, daß es LargeWord nicht in jeder Delphi-Version gibt und wenn doch, dann meist unter 'nem anderem Namen -.-''
Und in meinem UCC hab ich dann die ganzen Typen vom Namen her auf ein einheitliches System gebracht. (daher gibt's halt abundzu mal kleine Problemchen, wenn ich daraus etwas exportiere)

Hier also mal meine Definitionen für den Unsigned 64 Bit-Integer:
Delphi-Quellcode:
Type
  LargeWord = {$IFDEF DELPHI_6_UP} System.UInt64 {$ELSE} Type System.Int64 {$ENDIF};
  PLargeWord = ^LargeWord;

Und mit dem Incementieren hast'e natürlich Recht da muß dann natürlich zum nächsten "Block" gesprungen werden. (hab meinen letzen Beitrag entsprechend geändert)

DJ_Tom 29. Dez 2005 20:45

Re: verzweifle an fließkommazahlen....:-(
 
hmmm jetzt hab ich das problem das er am ende deiner funktion mit ner zugriffsverletzung raus geht.... :roll:

himitsu 29. Dez 2005 20:51

Re: verzweifle an fließkommazahlen....:-(
 
hmmm, hatte bisher noch keine Probleme damit.

Aber wann und wo kommt den welche Fehlermeldung?

DJ_Tom 29. Dez 2005 21:12

Re: verzweifle an fließkommazahlen....:-(
 
Liste der Anhänge anzeigen (Anzahl: 1)
also sobald er die funktion das erste mal durchläuft, wobei bytesread=0 ist...

ASM
PUSH EBX
TEST &Data, &Data
JE @Exit
TEST &Count, &Count
=> JLE @Exit

bis dahin läuft er


dann gehts zum exit

@Exit:
=> POP &Data
MOV EAX, -1
POP EBX
end;

und dann kommt:

"Zugriffsverletzung bei 0x6b88a780: Lesen von Adresse 0x6b88a780" Prozeß angehalten.

wenn ich dann von hand weiter gehe im debugger kommt irgendwann die fehlermeldung anbei...

himitsu 29. Dez 2005 22:59

Re: verzweifle an fließkommazahlen....:-(
 
Menno, da war wohl noch'n Rest vom TestCode drin :wall:

Diese beiden Zeilen müssen raus:
Delphi-Quellcode:
PUSH   &Data
POP    &Data
Hab's vorne rausgelöscht.

DJ_Tom 31. Dez 2005 18:59

Re: verzweifle an fließkommazahlen....:-(
 
hab mal noch ne ganz simple frage:

wenn ich einen pointer habe der auf die adr. x zeigt wie schaff ich es dann das der auf die nächste adresse zeigt??? :gruebel:

also so geht ja nicht:

Code:
var p:pointer;
..
//also p ist jetzt sagen wir mal $AABBCC

//um dann zu erreichen das p gleich $AABBCD ist
inc(p);
:wall:

marabu 31. Dez 2005 19:15

Re: verzweifle an fließkommazahlen....:-(
 
Hallo Tommy,

ein pointer p braucht einen Basistyp, damit er mit Inc(p, 1) um die Größe seines Basistyps erhöht werden kann:

Delphi-Quellcode:
var
  p: pointer;
begin
  p := Pointer($12345678);
  Inc(PInteger(p), 1);
  ShowMessage(IntToHex(Integer(p), 8));
  Inc(PByte(p), 1);
  ShowMessage(IntToHex(Integer(p), 8));
end;
Guten Rutsch vom marabu

DJ_Tom 31. Dez 2005 22:57

Re: verzweifle an fließkommazahlen....:-(
 
juhu...dank dir genau das suchte ich.... :thumb:

wünsch dir auch einen guten rutsch und ein frohes neues! :cheers:


Alle Zeitangaben in WEZ +1. Es ist jetzt 07:17 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