AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Aus Bytefolge (zufällig) eine Realzahl bilden
Thema durchsuchen
Ansicht
Themen-Optionen

Aus Bytefolge (zufällig) eine Realzahl bilden

Ein Thema von Satty67 · begonnen am 10. Mär 2011 · letzter Beitrag vom 10. Mär 2011
Antwort Antwort
Satty67

Registriert seit: 24. Feb 2007
Ort: Baden
1.566 Beiträge
 
Delphi 2007 Professional
 
#1

Aus Bytefolge (zufällig) eine Realzahl bilden

  Alt 10. Mär 2011, 20:42
Ich baue mir gerade ein Klasse, die mir mit Hilfe von CryptGenRandom (AdvAPI32.DLL) eine Zufallszahl liefern soll.

Für ganze Zahlen kein Problem. CryptGenRandom liefert beliebig lange Bytefolgen, die ich dann einfach in den Speicherbereich der jeweiligen Ganzzahl (Byte/Integer/Cardinal/Int64) schiebe.

Bei reelen Zahlen (Single/Double) bin ich aber nicht zufrieden. Die sind ja nicht ganz so statisch aufgebaut, wie ein Integer-Wert (Vorzeichen, Exponent, Mantisse). Folgende Versuche habe ich hinter mir:

1) Schiebe ich nun einfach 8 Byte in den Speicherbereich eines Double, kommen zwar zufällige Zahlen dabei raus, aber 70% liegt bei 0.0, Rest extrem hoch (liegt wohl am theoretischen Wertebereich). Zudem scheine ich beim Single-Typ auch ab und zu eine ungültige Bit-Belegung zu produzieren.

2) Ich nehme eine zufällige Int64-Zahl (geht ja problemlos) und setze die Kommastelle zufällig. Das Ergebnis ist ganz OK, allerdings recht umständlich, die Dezimalstellen zu ermitteln und ich brauche Delphi-Random zum setzen des Komma (Mein Zufallsgenerator kann ja erst nach ermitteln einer Fließkommazahl (für %-Wert) eine Range-Methode liefern)

3) Ich ermittel zwei ganze Zahlen... Int64 als Vorkomma- und Cardinal als Nachkommawert. Sind aber beide Werte hoch, komme ich deutlich über die sinnvollen 16 Stellen für ein Double.

4) Ich nehme einfach ein Festkomma (Currency) in das ich die Bytes schiebe und weise es danach einem Double zu. Ist zumindest schnell und der Wertebereich ist ganz OK. Meine derzeit verwendete Methode.

***

Wie kann ich am besten auf Basis einer zufälligen Bytefolge eine Single/Double Zufallszahl bilden?
  Mit Zitat antworten Zitat
Benutzerbild von BUG
BUG

Registriert seit: 4. Dez 2003
Ort: Cottbus
2.094 Beiträge
 
#2

AW: Aus Bytefolge (zufällig) eine Realzahl bilden

  Alt 10. Mär 2011, 21:09
Oft bekommt man doch zufällige Gleitkommazahlen im Bereich [0,1) (siehe random).
Da könntest du einfach die Mantisse/fraction zufällig wählen und den Exponenten (konstant) so setzen, das dieser Wertebereich herauskommt. (z.B. Aufteilung Double siehe hier)

Was sollte man mit einer Zufallszahl aus dem ganzen Double-Wertebereich anfangen?
Intellekt ist das Verstehen von Wissen. Verstehen ist der wahre Pfad zu Einsicht. Einsicht ist der Schlüssel zu allem.
  Mit Zitat antworten Zitat
Satty67

Registriert seit: 24. Feb 2007
Ort: Baden
1.566 Beiträge
 
Delphi 2007 Professional
 
#3

AW: Aus Bytefolge (zufällig) eine Realzahl bilden

  Alt 10. Mär 2011, 21:15
Für die Berechnung einer Range wie beim original Random brauche ich nur 0<x<1, das stimmt.

Für Rückgabe eines Double wären nur 16 Stellen (Summe Vorkomma/Nachkomma), nicht der ganze Wertebereich interessant. Man spart sich halt weitere Berechnungen, wenn man Zufallszahlen im Double-Wertebereich braucht (z.B. Datum etc.). Aber wie gesagt, 0<x<1 reicht mir auch.

Also nur die unteren 52 Bit (Mantisse) zufällig setzen und den Exponenten gezielt? Das klingt interessant, werde mich gleich mal mit dem genauen Aufbau auseinandersetzen.

€: Hier die aktuelle Unit (noch mit der alten Methode für Double... experimentiere noch)

Es ist nur die AnsiVersion importiert, da aber beide StringParameter nicht gebraucht werde, ist das erst mal unwichtig.
Delphi-Quellcode:
unit CryptRandom;

interface

uses
  Windows;

type
  HCryptProv = DWord;
  PCryptProv = ^HCryptProv;

  TCryptRandom = class
  private
    FProvider : HCryptProv;
    function GetContext: Boolean;
    procedure ReleaseContext;
  public
    constructor Create();

    procedure GetBytes(Bytes : PByte; Size : Integer);
    function GetByte: Byte;
    function GetInteger: Integer;
    function GetCardinal: Cardinal;
    function GetInt64: Int64;
    function GetASCIIString(Size : Integer): AnsiString;
    function GetDouble: Double;
    function Random : Double; overload;
    function Random(Range : Integer): Integer; overload;
  end;

{ BOOL WINAPI CryptAcquireContext( __out  HCRYPTPROV *phProv,
                                  __in  LPCTSTR pszContainer,
                                  __in  LPCTSTR pszProvider,
                                  __in  DWORD dwProvType,
                                  __in  DWORD dwFlags );
}

function CryptAcquireContext(phProv : PProvider;
                             pszContainer :PAnsiChar;
                             pszProvider : PAnsiChar;
                             dwProvType : DWord;
                             dwFlags : DWord) : BOOL; stdcall;

{ BOOL WINAPI CryptReleaseContext( __in  HCRYPTPROV hProv,
                                  __in  DWORD dwFlags );
}

function CryptReleaseContext(hProv : HCryptProv; dwFlags : DWord) :BOOL;stdcall;

{ BOOL WINAPI CryptGenRandom( __in    HCRYPTPROV hProv,
                              __in    DWORD dwLen,
                              __inout  BYTE *pbBuffer );
}

function CryptGenRandom(hProv : HCryptProv;
                        dwLen : DWord;
                        pbBuffer : PByte) : BOOL; stdcall;

const
  CRYPT_VERIFYCONTEXT = $F0000000; // using ephemeral keys [default]
  CRYPT_NEWKEYSET = $8; // Creates a new key container "pszContainer"
  CRYPT_DELETEKEYSET = $10; // Delete the key container "pszContainer"

  PROV_RSA_FULL = 1;
{ PROV_RSA_AES
  PROV_RSA_SIG
  PROV_RSA_SCHANNEL
  PROV_DSS
  PROV_DSS_DH
  PROV_DH_SCHANNEL
  PROV_FORTEZZA
  PROV_MS_EXCHANGE
  PROV_SSL
}

  AdvApiDll = 'AdvAPI32.DLL';

implementation

function CryptAcquireContext; external AdvApiDll Name 'CryptAcquireContextA';
function CryptReleaseContext; external AdvApiDll Name 'CryptReleaseContext';
function CryptGenRandom; external AdvApiDll Name 'CryptGenRandom';

{ TCryptRandom }

constructor TCryptRandom.Create();
begin
  FProvider := 0;
end;

function TCryptRandom.GetContext: Boolean;
begin
  CryptAcquireContext(@FProvider, NIL, NIL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
  Result := GetLastError = 0;
end;

procedure TCryptRandom.ReleaseContext;
begin
  if FProvider <> 0 then
  begin
    CryptReleaseContext(FProvider, 0);
    FProvider := 0;
  end;
end;

procedure TCryptRandom.GetBytes(Bytes : PByte; Size : Integer);
begin
  if GetContext then
  begin
    try
      CryptGenRandom(FProvider, size, Bytes);
    finally
      ReleaseContext;
    end;
  end;
end;

function TCryptRandom.GetByte: Byte;
begin
  GetBytes(@Result, SizeOf(Result));
end;

function TCryptRandom.GetInteger: Integer;
begin
  GetBytes(@Result, SizeOf(Result));
end;

function TCryptRandom.GetCardinal: Cardinal;
begin
  GetBytes(@Result, SizeOf(Result));
end;

function TCryptRandom.GetInt64: Int64;
begin
  GetBytes(@Result, SizeOf(Result));
end;

function TCryptRandom.GetASCIIString(Size : Integer): AnsiString;
var
  i : Integer;
  b : Byte;
begin
  SetLength(Result, Size);
  GetBytes(@Result[1], Size);

  for i := 1 to Size do
  begin
    b := Ord(Result[i]);
    Result[i] := Chr((b div 4) + 33);
  end;
end;

function TCryptRandom.GetDouble: Double;
var
  c : Currency;
begin
  GetBytes(@c, SizeOf(c));
  Result := c;
end;

function TCryptRandom.Random : Double;
begin
  // 0 <= Result < 1, max 18 decimal digits
  Result := Frac(Abs(GetInt64 / 1000000000000000000));
end;

function TCryptRandom.Random(Range : Integer): Integer;
begin
  Result := Trunc(Random * Range);
end;

end.

Geändert von Satty67 (11. Mär 2011 um 11:34 Uhr)
  Mit Zitat antworten Zitat
Antwort Antwort


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 06:25 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