Difference between revisions of "Delphi compatible LCG Random"

From Lazarus wiki
Jump to navigationJump to search
 
 
(26 intermediate revisions by 3 users not shown)
Line 1: Line 1:
 
=== Delphi compatible random numbers ===
 
=== Delphi compatible random numbers ===
Many Freepascal programmers also maintain a sourcecode in Delphi.<br>
+
Many Free Pascal programmers also maintain sourcecode in Delphi.<br>
Even if you have moved to Freepascal from Delphi you may have data that relies on Delphi's Random.<br>
+
Even if you have moved to Free Pascal from Delphi you may have data that relies on Delphi's Random.<br>
Here are compatible routines that generate Delphi-identical pseudo-random numbers:
+
Here are cross-platform functions that generate Delphi-identical pseudo-random numbers given the same RandSeed:
<syntaxhighlight>
+
<syntaxhighlight lang=pascal>
unit drandom;
+
unit lcg_random;
// Delphi compatible LCG random number generator routines for Freepascal.
+
// Delphi compatible LCG random number generator routines for Free Pascal.
 
// (c)2017, Thaddy de Koning. Use as you like
 
// (c)2017, Thaddy de Koning. Use as you like
 
// Algorithm, Delphi multiplier and increment taken from:
 
// Algorithm, Delphi multiplier and increment taken from:
 
// https://en.wikipedia.org/wiki/Linear_congruential_generator
 
// https://en.wikipedia.org/wiki/Linear_congruential_generator
 
// The default Delphi RandomSeed is determined as zero.
 
// The default Delphi RandomSeed is determined as zero.
{$mode objfpc}{$H+}
+
{$ifdef fpc}{$mode objfpc}{$endif}
  
 
interface
 
interface
  
function DelphiRandom: Double; overload;inline;
+
function LCGRandom: extended; overload;inline;
function DelphiRandom(range:integer):integer;overload;inline;
+
function LCGRandom(const range:longint):longint;overload;inline;
  
 
implementation
 
implementation
  
function IM:dword;inline;
+
function IM:cardinal;inline;
 
begin
 
begin
 
   RandSeed := RandSeed * 134775813  + 1;
 
   RandSeed := RandSeed * 134775813  + 1;
Line 25: Line 25:
 
end;
 
end;
  
function DelphiRandom: Double; overload;inline;
+
function LCGRandom: extended; overload;inline;
 +
begin
 +
  Result := IM * 2.32830643653870e-10;
 +
end;
 +
 
 +
function LCGRandom(const range:longint):longint;overload;inline;
 +
begin
 +
  Result := IM * range shr 32;
 +
end;
 +
 
 +
end.</syntaxhighlight>
 +
<br>
 +
A small demo
 +
<syntaxhighlight lang=pascal>
 +
program lcgdemo;
 +
// Compile and run in both Delphi and FPC and compare the output.
 +
// It is exactly the same
 +
{$ifdef fpc}{$mode objfpc}
 +
{$Macro on}{$define random := LCGRandom}
 +
{$endif}
 +
{$ifdef mswindows}{$apptype console}{$endif}
 +
uses lcg_random;
 +
 
 +
var i:integer;
 +
begin
 +
  RandSeed := 999;  // default delphi randseed is zero
 +
  for i := 1 to 20 do
 +
  begin
 +
    write(Random(100):4); // Delphi: Random FPC:LCGRandom. See macro
 +
    if i mod 5 = 0 then writeln;
 +
  end;
 +
 
 +
  RandSeed := 999;  // default delphi randseed is zero
 +
  for i := 1 to 20 do
 +
  begin
 +
    write(Random:4:8,' ');// Delphi: Random FPC:LCGRandom
 +
    if i mod 5 = 0 then writeln;
 +
  end;
 +
  Readln;
 +
end.</syntaxhighlight>
 +
 
 +
Here is another one with the randseed factored out. You can use that for non-delphi compatible purposes:
 +
<syntaxhighlight lang=pascal>unit lcg_random2;
 +
// Delphi compatible LCG random number generator routines for Freepascal.
 +
// (c)2017, Thaddy de Koning. Use as you like
 +
// Algorithm, Delphi multiplier and increment taken from:
 +
// https://en.wikipedia.org/wiki/Linear_congruential_generator
 +
// The default Delphi RandomSeed is determined as zero.
 +
//
 +
// In this version the system randseed is factored out.
 +
{$ifdef fpc}{$mode objfpc}{$endif}{$J+}
 +
 
 +
interface
 +
const
 +
  RandSd:cardinal = 0;
 +
 
 +
function LCGRandom: extended; overload;inline;
 +
function LCGRandom(const range:longint):longint;overload;inline;
 +
 
 +
implementation
 +
 
 +
function IM:cardinal;inline;
 +
begin
 +
  RandSd := RandSd * 134775813  + 1;
 +
  Result := RandSd;
 +
end;
 +
 
 +
function LCGRandom: extended; overload;inline;
 
begin
 
begin
 
   Result := IM * 2.32830643653870e-10;
 
   Result := IM * 2.32830643653870e-10;
 
end;
 
end;
  
function DelphiRandom(range:integer):integer;overload;inline;
+
function LCGRandom(const range:longint):longint;overload;inline;
 
begin
 
begin
 
   Result := IM * range shr 32;
 
   Result := IM * range shr 32;
Line 36: Line 103:
  
 
end.</syntaxhighlight>
 
end.</syntaxhighlight>
 +
 +
You can use this for example for simple encryption and decryption based on the predictability and repeatability of a any Pseudo Random Number Generator:
 +
<syntaxhighlight lang=pascal>program cryptrandom;
 +
{$mode objfpc}{$modeswitch typehelpers}{$H+}
 +
{ This is demo that you can actually use random to encrypt/decrypt.
 +
  This is due to the nature of a Pseudo Random Number Generator,
 +
  where given a certain random seed, the sequence is predictable.
 +
  Here I use the Random Seed as a key to encrypt/decrypt a string.
 +
  The same code would also work with the Default random from FreePascal,
 +
  but it is better not to touch system.randseed, So I used a different
 +
  Random.
 +
 
 +
  Have fun, Thaddy}
 +
uses
 +
lcg_random2;
 +
 +
 
 +
function Crypt(const value:AnsiString;const Key:Cardinal):AnsiString;
 +
var
 +
  i:integer;
 +
begin
 +
  RandSd := Key;
 +
  SetLength(Result,Length(Value));
 +
  for i := 1 to length(Value) do
 +
    Result[i] := Chr(Ord(Value[i]) xor lcgrandom(255));
 +
end;
 +
 +
var
 +
a:AnsiString;
 +
begin
 +
a:='This is the text to encrypt/decrypt.';
 +
writeln(a);
 +
writeln('Encrypting..');
 +
a:=Crypt(a, 12345);
 +
writeln(a);
 +
writeln('Decrypting..');
 +
a:=Crypt(a, 12345);
 +
writeln(a);
 +
end.</syntaxhighlight>
 +
 +
=== See also ===
 +
#[https://en.wikipedia.org/wiki/Linear_congruential_generator LCG on wikipedia]
 +
#[[Generating Random Numbers]]
 +
 +
== See also ==
 +
* [http://en.wikipedia.org/wiki/Linear_congruential_generator Wikipedia article on the linear congruential generator algorithm]
 +
 +
[[Category:Statistical algorithms]]
 +
[[Category:Modelling and Simulation]]

Latest revision as of 19:48, 14 May 2024

Delphi compatible random numbers

Many Free Pascal programmers also maintain sourcecode in Delphi.
Even if you have moved to Free Pascal from Delphi you may have data that relies on Delphi's Random.
Here are cross-platform functions that generate Delphi-identical pseudo-random numbers given the same RandSeed:

unit lcg_random;
// Delphi compatible LCG random number generator routines for Free Pascal.
// (c)2017, Thaddy de Koning. Use as you like
// Algorithm, Delphi multiplier and increment taken from:
// https://en.wikipedia.org/wiki/Linear_congruential_generator
// The default Delphi RandomSeed is determined as zero.
{$ifdef fpc}{$mode objfpc}{$endif}

interface

function LCGRandom: extended; overload;inline;
function LCGRandom(const range:longint):longint;overload;inline;

implementation

function IM:cardinal;inline;
begin
  RandSeed := RandSeed * 134775813  + 1;
  Result := RandSeed;
end;

function LCGRandom: extended; overload;inline;
begin
  Result := IM * 2.32830643653870e-10;
end;

function LCGRandom(const range:longint):longint;overload;inline;
begin
  Result := IM * range shr 32;
end;

end.


A small demo

program lcgdemo;
// Compile and run in both Delphi and FPC and compare the output.
// It is exactly the same
{$ifdef fpc}{$mode objfpc}
{$Macro on}{$define random := LCGRandom}
{$endif}
{$ifdef mswindows}{$apptype console}{$endif}
uses lcg_random;

var i:integer;
begin
  RandSeed := 999;  // default delphi randseed is zero
  for i := 1 to 20 do
  begin
    write(Random(100):4); // Delphi: Random FPC:LCGRandom. See macro
    if i mod 5 = 0 then writeln;
  end;

  RandSeed := 999;  // default delphi randseed is zero
  for i := 1 to 20 do
  begin
    write(Random:4:8,' ');// Delphi: Random FPC:LCGRandom
    if i mod 5 = 0 then writeln;
  end;
  Readln;
end.

Here is another one with the randseed factored out. You can use that for non-delphi compatible purposes:

unit lcg_random2;
// Delphi compatible LCG random number generator routines for Freepascal.
// (c)2017, Thaddy de Koning. Use as you like
// Algorithm, Delphi multiplier and increment taken from:
// https://en.wikipedia.org/wiki/Linear_congruential_generator
// The default Delphi RandomSeed is determined as zero.
//
// In this version the system randseed is factored out.
{$ifdef fpc}{$mode objfpc}{$endif}{$J+}

interface
const 
  RandSd:cardinal = 0; 
  
function LCGRandom: extended; overload;inline;
function LCGRandom(const range:longint):longint;overload;inline;

implementation

function IM:cardinal;inline;
begin
  RandSd := RandSd * 134775813  + 1;
  Result := RandSd;
end;

function LCGRandom: extended; overload;inline;
begin
  Result := IM * 2.32830643653870e-10;
end;

function LCGRandom(const range:longint):longint;overload;inline;
begin
  Result := IM * range shr 32;
end;

end.

You can use this for example for simple encryption and decryption based on the predictability and repeatability of a any Pseudo Random Number Generator:

program cryptrandom;
{$mode objfpc}{$modeswitch typehelpers}{$H+}
{ This is demo that you can actually use random to encrypt/decrypt.
  This is due to the nature of a Pseudo Random Number Generator,
  where given a certain random seed, the sequence is predictable.
  Here I use the Random Seed as a key to encrypt/decrypt a string.
  The same code would also work with the Default random from FreePascal,
  but it is better not to touch system.randseed, So I used a different
  Random.
  
  Have fun, Thaddy}
uses 
lcg_random2;

  
function Crypt(const value:AnsiString;const Key:Cardinal):AnsiString;
var
  i:integer;
begin
  RandSd := Key;
  SetLength(Result,Length(Value));
  for i := 1 to length(Value) do
    Result[i] := Chr(Ord(Value[i]) xor lcgrandom(255));
end;

var 
 a:AnsiString;
begin
 a:='This is the text to encrypt/decrypt.';
 writeln(a);
 writeln('Encrypting..');
 a:=Crypt(a, 12345);
 writeln(a);
 writeln('Decrypting..');
 a:=Crypt(a, 12345); 
 writeln(a);
end.

See also

  1. LCG on wikipedia
  2. Generating Random Numbers

See also