Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Random() in PurePascal (https://www.delphipraxis.net/134097-random-purepascal.html)

Win32.API 15. Mai 2009 13:12


Random() in PurePascal
 
Hallo,

ich habe mir gerade die Random-Funktion einmal näher angeschaut und mir sind 2 Fragen in den Sinn gekommen.

Wieso wird EBX auf Null gesetzt, und dann versucht den Speicher von [EBX+@RandSeed] zu lesen? Das XOR ist doch hier vollkommen überflüssig (Bzw. EBX).

Random funktion aus der System.pas:
Delphi-Quellcode:
function Random(const ARange: Integer): Integer;
asm
        PUSH   EBX
        XOR    EBX, EBX //<<<<<<
        IMUL   EDX,[EBX].RandSeed,08088405H
        INC    EDX
        MOV    [EBX].RandSeed,EDX
        MUL    EDX
        MOV    EAX,EDX
        POP    EBX
end;

Meine übersetzte Funktion gibt andere Werte zurück als die Funktion aus der System.pas. Ich könnte mir Vorstellen, dass es an dem mod liegt. Aber was anderes macht hier doch keinen Sinn, oder?

Delphi-Quellcode:
MUL EDX //EAX := EAX * EDX und EDX = ?
Meine Übersetzung:
Delphi-Quellcode:
function MyRandom2(const ARange: Cardinal): Cardinal;
begin
  result := Cardinal(RandSeed * $08088405 + 1) mod aRange;
  RandSeed := result;
end;

Gruß,
Win32

himitsu 15. Mai 2009 13:34

Re: Random() in PurePascal
 
vielleicht ist dir noch nicht aufgefallen, daß RandSeed auch noch verändert wird (sonst würdest du beim nächsten Aufruf deiner Funktion den seben Wert erhalben :zwinker: )

ich hatte mir das mal vor langer Zeit etwa so übersetzt ... glaub ich :gruebel:
Delphi-Quellcode:
Function Random(Range: LongInt): LongInt;
  Begin
    RandSeed := Int64(RandSeed) * 134775813 + 1;
    Result := TLargeIntRec(Int64(Range) * LongWord(RandSeed)).Hi;
  End;
aber was mit EBX ist ... k.A.

BUG 15. Mai 2009 14:23

Re: Random() in PurePascal
 
Code:
XOR EBX, EBX
entspricht
Code:
MOV EBX, 0
braucht aber weniger Prozessortakte, da 0 nicht erst aus dem Speicher geladen werden muss.

Ob das heute noch Sinn macht: keine Ahnung.

MfG,
Bug

Win32.API 15. Mai 2009 14:29

Re: Random() in PurePascal
 
Zitat:

Zitat von himitsu
vielleicht ist dir noch nicht aufgefallen, daß RandSeed auch noch verändert wird (sonst würdest du beim nächsten Aufruf deiner Funktion den seben Wert erhalben :zwinker: )

ich hatte mir das mal vor langer Zeit etwa so übersetzt ... glaub ich :gruebel:
Delphi-Quellcode:
Function Random(Range: LongInt): LongInt;
  Begin
    RandSeed := Int64(RandSeed) * 134775813 + 1;
    Result := TLargeIntRec(Int64(Range) * LongWord(RandSeed)).Hi;
  End;
aber was mit EBX ist ... k.A.

Ja, das mit RandSeed ist mir bewust. Man kann es entweder auskommentieren, oder das Prigramm 2 mal starten (Ohne randomize()). Beides bringt aber nicht das erwartete Ergbenis.

Zitat:

Zitat von BUG
Code:
XOR EBX, EBX
entspricht
Code:
MOV EBX, 0
braucht aber weniger Prozessortakte, da 0 nicht erst aus dem Speicher geladen werden muss.

Ob das heute noch Sinn macht: keine Ahnung.

MfG,
Bug

Die Begründung das 0 er aus dem Speicher geladen werden müsste ist falsch, und ja es ist auch Heute noch schneller.

brechi 15. Mai 2009 14:48

Re: Random() in PurePascal
 
wenn du dir den erstellten Assemblercode anschaust sollte es klar werden:

004035CD 31DB xor ebx,ebx
004035CF 6993087084000584 imul edx,[ebx+$00847008],$08088405


wird wohl schneller sein als ein

mov ebx, randseed
imul edx, ebx, $08088405

-----------
Und bei einem

mov ebx, 0

wird die 0 (0 als opcode parameter) sehr wohl aus dem speicher geladen

Win32.API 15. Mai 2009 15:01

Re: Random() in PurePascal
 
Hi brechi,


Zitat:

Zitat von brechi
wenn du dir den erstellten Assemblercode anschaust sollte es klar werden:

004035CD 31DB xor ebx,ebx
004035CF 6993087084000584 imul edx,[ebx+$00847008],$08088405


wird wohl schneller sein als ein

mov ebx, randseed
imul edx, ebx, $08088405

Kann man es nicht einfach so umschreiben:

Delphi-Quellcode:
xor ebx,ebx
imul edx,[ebx+$00847008],$08088405
->
imul edx,[0 + $00847008],$08088405
->
imul edx,[$00847008],$08088405
Das ist doch bestimmt schneller als erst EBX auf 0 zu setzen und dann nochmal auf EBX lesend zugreifen (Das PUSH/POP nicht zu vergessen).


Zitat:

Zitat von brechi
bei einem

mov ebx, 0

wird die 0 (0 als opcode parameter) sehr wohl aus dem speicher geladen

Da hast du recht, habe nicht soweit gedacht. Für mich ist es aber kein "echtes" laden, da der OP-Code immer "geladen" werden muss.



Gruß

gammatester 15. Mai 2009 18:48

Re: Random() in PurePascal
 
Bei der ganzen Diskussion mit EBX etc ist doch etwas untergangen, warum der Ausgangscode nicht funktioniert und warum nicht mod benutzt wird. Zum ersten war himitsu ziemlich nahe dran. Hier ein Delphiprogramm, daß exakt random reproduziert (zumindest bis D10):
Delphi-Quellcode:
program rt;

{$apptype console}

{$q-,r-}

uses
  windows,sysutils;

var
  myrandseed: cardinal;

function myrandom(range: cardinal): cardinal;
begin
  myrandseed := myrandseed *  $08088405 + 1;
  result := (int64(range) * myrandseed) shr 32;
end;

var
  k: integer;
  r1,r2: cardinal;
begin
  myrandseed := randseed;
  for k:=1 to 10 do begin
    r1 := random(100000);
    r2 := myrandom(100000);
    writeln(r1:10, r2:10, myrandseed mod 2:4, myrandseed mod 4:4)
  end;
  readln;
end.
Ausgabe ist:
Code:
 
.        0         0   1   1
.     3137      3137   0   2
.    86104     86104   1   3
.    20258     20258   0   0
.    27292     27292   1   1
.    67165     67165   0   2
.    31869     31869   1   3
.    16179     16179   0   0
.    37223     37223   1   1
.    42567     42567   0   2
Die letzen beiden Spalten zeigen, warum mod nicht 'gut' ist: die unteren Bits sind halt nicht besonders zufällig :)

Selbst random und die hohen Bits haben eine klein Bias, aber für den Hausgebrauch reichts (für wissenschaftliche Zwecke ist die Periode von random eh zu klein, und für Kryptographie sowieso völlig ungeignet).

Gammatester

Win32.API 16. Mai 2009 17:09

Re: Random() in PurePascal
 
Hallo gammatester,

danke für die ausführliche Erklärung! Ich hatte verdrengt, dass mul das Ergebnis in edx:eax speichert. Und somit immer mit den falschen 4byte gerechnet.

Delphi-Quellcode:
function MyRandom2(const ARange: Cardinal): Cardinal;
begin
  result := Cardinal(RandSeed * $08088405 + 1) * Int64(ARange) shr 32;
  RandSeed := result;
end;
Gruß,
Win32


Alle Zeitangaben in WEZ +1. Es ist jetzt 17:07 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz