
Replies:
24

Last Post:
Aug 31, 2016 10:32 AM
Last Post By: Andrej Mrvar



Posts:
99
Registered:
10/20/10


It seems that random is not able to return int64 as a result? Am I right?
How can I generate a random int64 number then (e.g. number in range 1..10,000,000,000)?
Thanks.
Andrej



Posts:
99
Registered:
10/20/10


Is trunc(10000000000 * random) + 1 precise enough?
A.




Posts:
125
Registered:
1/22/07


Am 03.08.2016 um 11:22 schrieb Andrej Mrvar:
Is 10000000000 * random precise enough?
A.
No... The base is still a longword
Yo could do something like this (note there would be still a little
problem  the numbers are up to 31 bits due to the fact that integer is
used instead of longword):
fucntion rand64(aRange : Int64) : int64;
begin
Result := ( int64(Random(MaxInt)) shl 32 ) or
( int64(Random(MaxInt)) )
mod aRange;
end;




Posts:
99
Registered:
10/20/10


Thanks.
Probably mod should be executed at the end, therefore instead of
Result := ( int64(Random(MaxInt)) shl 32 ) or ( int64(Random(MaxInt)) ) mod aRange;
it should be
Result := ( ( int64(Random(MaxInt)) shl 32 ) or ( int64(Random(MaxInt)) ) ) mod aRange;
with additional ( and )
?




Posts:
362
Registered:
12/13/99


Den 8/3/2016 kl. 13:39 skrev Andrej Mrvar:
Thanks.
Probably mod should be executed at the end, therefore instead of
Result := ( int64(Random(MaxInt)) shl 32 ) or ( int64(Random(MaxInt)) ) mod aRange;
it should be
Result := ( ( int64(Random(MaxInt)) shl 32 ) or ( int64(Random(MaxInt)) ) ) mod aRange;
with additional ( and )
?
https://sites.google.com/site/kbbsoft/delphiprogamming
best regards
Kim/C4D




Posts:
99
Registered:
10/20/10


Thanks for providing this list. That is a lot of work behind indeed.
I am a bit lost with all this possibilities.
Maybe you can suggest a simple random function
to use to get integers in range 1 up to 10^10 (or 10^12 at most).
Actually I do not need the whole range of 64 bit integers.
Thanks in advance.
A.




Posts:
362
Registered:
12/13/99


Den 8/3/2016 kl. 15:54 skrev Andrej Mrvar:
Thanks for providing this list. That is a lot of work behind indeed.
I am a bit lost with all this possibilities.
Maybe you can suggest a simple random function
to use to get integers in range 1 up to 10^10 (or 10^12 at most).
Actually I do not need the whole range of 64 bit integers.
Thanks in advance.
A.
Whats your criteria for the random function?
Consider:
 Trueness? (ie.. is pseudo random good enough or must it rely on
physical randomness?)
 Speed?
 Distribution of values?
 Period? (how many random number generations before you start to see it
starting over with the same list of "random" numbers)
Its kind of a science to pick the best one for the job
A simple pseudo random generator is the LCG. Its using last value
generated to create next value.
https://en.wikipedia.org/wiki/Linear_congruential_generator
A function can easily be created for generating 64 bit psudo random LCG
values like this:
TRand64 = class
private
class var FValue:uint64;
public
class procedure Seed(const AValue:uint64);
class function Rand:uint64;
end;
class procedure TRand64.Seed(const AValue:uint64);
begin
FValue:=AValue;
end;
class procedure TRand64.Rand:uint64;
begin
FValue:=(uint64(6364136223846793005)*FValue +
uint64(1442695040888963407)) AND $FFFFFFFFFFFFFFFF;
Result:=FValue;
end;
Freely written. I havnt tried to compile it, but it ought to work
best regards
Kim/C4D




Posts:
362
Registered:
12/13/99


Den 8/3/2016 kl. 18:09 skrev Kim Madsen:
class procedure TRand64.Rand:uint64;
begin
...
Ofcourse that should be
class function TRand64.Rand:uint64;
begin
...




Posts:
99
Registered:
10/20/10


Thanks for providing the detailed solution. It works.
But I wonder if the following solution is faster?
Since I only need random numbers lower than 10^12 that is approx. 2^40, 40 bits=5 bytes, this 5 bytes should be sufficient:
8 bytes of the 64 bit integer result I fill in the following way:
 the lower five bytes with random values,
 the highest 3 bytes set to 0:
Int64Rec(Result).Words[0] := Random(High(Word));
Int64Rec(Result).Words[1] := Random(High(Word));
Int64Rec(Result).Bytes[4] := Random(High(Byte));
Int64Rec(Result).Bytes[5] := 0;
Int64Rec(Result).Words[3] := 0;
Result:=Result mod (maxvalue); // maxvalue is for example 1000000000000
Is that ok?




Posts:
362
Registered:
12/13/99


Den 8/3/2016 kl. 23:06 skrev Andrej Mrvar:
Thanks for providing the detailed solution. It works.
But I wonder if the following solution is faster?
Since I only need random numbers lower than 10^12 that is approx. 2^40, 40 bits=5 bytes, this 5 bytes should be sufficient:
8 bytes of the 64 bit integer result I fill in the following way:
 the lower five bytes with random values,
 the highest 3 bytes set to 0:
Int64Rec(Result).Words[0] := Random(High(Word));
Int64Rec(Result).Words[1] := Random(High(Word));
Int64Rec(Result).Bytes[4] := Random(High(Byte));
Int64Rec(Result).Bytes[5] := 0;
Int64Rec(Result).Words[3] := 0;
Result:=Result mod (maxvalue); // maxvalue is for example 1000000000000
Is that ok?
Hi,
It will provide you with some sort of randomness, but it wont be faster,
and the period of that combination of random values is unknown. It may
end up actually having a pretty bad randomness.
Further it will be slower since Random is called multiple times, and
internall Random makes something similar (although with different
constants) to the one I provided.
If you want a 40 bit random value, you can change it to:
class function TRand64.Rand:uint64;
begin
FValue:=(uint64(6364136223846793005)*FValue +
uint64(1442695040888963407)) MOD uint64($10000000000);
Result:=FValue;
end;
best regards
Kim/C4D




Posts:
99
Registered:
10/20/10


Thanks for explanation and the updated function for generating 40 bit random integer.
I do not see how to use correctly?
Should I first call TRand64.Seed with some number to initialize it (like randomize)?
And later TRand64.Rand.
Please provide me with an example of declarations needed and correct call of your function to obtain
the random 40 bit integer..
Thanks.
Andrej




Posts:
362
Registered:
12/13/99


Den 8/4/2016 kl. 07:16 skrev Andrej Mrvar:
Thanks for explanation and the updated function for generating 40 bit random integer.
I do not see how to use correctly?
Should I first call TRand64.Seed with some number to initialize it (like randomize)?
And later TRand64.Rand.
Please provide me with an example of declarations needed and correct call of your function to obtain
the random 40 bit integer..
Thanks.
Andrej
Hi,
Yes you ought to set Seed to something. There are two ways to use it:
A) You set it to some fixed value (for example 0) everytime you want to
have your "random" number sequence to start over from start. This
obviously makes the random number non random, but instead predictable.
Thats useful for creating test cases, where you want to be sure to
compare a fixed outcome of some algorithm requiring random numbers.
B) You can set it once in start of your application, to a value based on
a time function. Like GetTickCount or similar changing value. This makes
the "random" sequence unpredictable, which more resembles true
randomness, and is what should typically be used when you run your
application.
After that you use the Rand function as many times as you need.
best regards
Kim/C4D
The best ntier for the best developers
www.components4developers.com




Posts:
99
Registered:
10/20/10


Thanks, I see.
A simple random number generator for generating integer numbers in range 1 to 10 billions would be also
x := Random(1,000,000,000) + Random(10)*1,000,000,000
i.e. generating random number between 0 and one billion (standard random generator, since that is still 32 bit)) and than add zero, one, two, three ,..., or 9 billions by random.
Am I right? Would that be random enough?




Posts:
362
Registered:
12/13/99


Den 8/4/2016 kl. 12:22 skrev Andrej Mrvar:
Thanks, I see.
A simple random number generator for generating integer numbers in range 1 to 10 billions would be also
x := Random(1,000,000,000) + Random(10)*1,000,000,000
i.e. generating random number between 0 and one billion (standard random generator, since that is still 32 bit)) and than add zero, one, two, three ,..., or 9 billions by random.
Am I right? Would that be random enough?
Hi,
As I wrote, using Random multiple times potentially results in unknown
periods and randomness. It may be good enough for your purpose, but only
you know what you actually need.
It will also be slower, but again, it may be fast enough for your purpose.
Please check my previous replies on that topic.
best regards
Kim/C4D
The best ntier for the best developers
http://www.components4developers.com




Posts:
99
Registered:
10/20/10


Thanks again for your answer.
I can understand that your function is more random.
One final question:
would it be possible to rewrite your function in 'plain' pascal,
I mean without defining new objects, classes,
just function which returns int64 as a result?
I just want to keep things as simple as possible




Posts:
362
Registered:
12/13/99


Den 8/4/2016 kl. 16:13 skrev Andrej Mrvar:
Thanks again for your answer.
I can understand that your function is more random.
One final question:
would it be possible to rewrite your function in 'plain' pascal,
I mean without defining new objects, classes,
just function which returns int64 as a result?
I just want to keep things as simple as possible
Hi,
unit xxxx;
interface
procedure Seed(const AValue:uint64);
function Rand:uint64;
implementation
var FValue:uint64;
procedure Seed(const AValue:uint64);
begin
FValue:=AValue;
end;
function Rand:uint64;
begin
FValue:=(uint64(6364136223846793005)*FValue +
uint64(1442695040888963407)) MOD uint64($10000000000);
Result:=FValue;
end;
best regards
Kim/C4D




Posts:
99
Registered:
10/20/10


Thanks for your patience
Now I included it to my program  the function is much simpler and
according to testing also faster than other functions that I have tried before.
And now a 'final final' two questions:
For the starting value of FValue I take random 32 (actually 31) bit integer which is generated by Delphi itself:
FValue:=uint64(random(maxint));
maybe:
FValue:= uint64(random(maxint)) * uint64(random(maxint)) );
would be better?
Since I finally need a int64 as a result, I divide the FValue by two, to avoid negative values:
Result:= int64(FValue div 2) mod 10000000000;
Do you agree with this or should I do it differently?
Best.
Andrej




Posts:
362
Registered:
12/13/99


Hi,
That should be fine.
Although I personally would want to use Seed function to set the
starting value (which can be anything as long as it fits in a 64 bit
unsigned integer).
This way you can reseed (when you need to), to a previous value and get
the same "random" values again and again for testing purposes.
When you run in production, you can seed it with random or gettickcount
or trunc(now*10000)trunc(now) or something like that.
As long as the value is depending on "external circumstances" like a
counter or a Real time clock or something with enough precision to make
the seed start seem unpredictable.
best regards
Kim/C4D
Den 8/5/2016 kl. 08:30 skrev Andrej Mrvar:
Thanks for your patience
Now I included it to my program  the function is much simpler and
according to testing also faster than other functions that I have tried before.
And now a 'final final' two questions:
For the starting value of FValue I take random 32 (actually 31) bit integer which is generated by Delphi itself:
FValue:=uint64(random(maxint));
maybe:
FValue:= uint64(random(maxint)) * uint64(random(maxint)) );
would be better?
Since I finally need a int64 as a result, I divide the FValue by two, to avoid negative values:
Result:= int64(FValue div 2) mod 10000000000;
Do you agree with this or should I do it differently?
Best.
Andrej




Posts:
362
Registered:
12/13/99


BTW, you dont need to divide by 2 if you want the result in an int64.
You asked for the function only to return 40 bits of the possible 64
bits, so you will be able to cast the value directly to int64 without
problems.
best regards
Kim/C4D




Posts:
99
Registered:
10/20/10


Thanks again. Problem solved now. No more questions
Best wishes.
Andrej




Posts:
7,731
Registered:
9/22/99


Andrej Mrvar wrote:
Is trunc(10000000000 * random) + 1 precise enough?
A.
No. Just generate two random Integers and do:
MyRandomInt64 := Int64(RandomInt1) shl 32 or RandomInt2;

Rudy Velthuis http://www.rvelthuis.de
"This isn't life in the fast lane, it's life in the oncoming traffic."
 Terry Pratchett




Posts:
99
Registered:
10/20/10


No. Just generate two random Integers and do:
MyRandomInt64 := Int64(RandomInt1) shl 32 or RandomInt2;
As I learned there is at least one problem with this solution:
Delphi random generator gives you random 31 bit number and not 32 bit number.




Posts:
7,731
Registered:
9/22/99


Andrej Mrvar wrote:
No. Just generate two random Integers and do:
MyRandomInt64 := Int64(RandomInt1) shl 32 or RandomInt2;
As I learned there is at least one problem with this solution:
Delphi random generator gives you random 31 bit number and not 32 bit
number.
That's right. Simply do:
RandomInt1 := RandSeed;
Random(MaxInt);
RandomInt2 := RandSeed;
MyRandomInt64 := Int64(RandomInt1) shl 32 or RandomInt2;

Rudy Velthuis http://www.rvelthuis.de
"Every day people are straying away from the church and going
back to God."
 Lenny Bruce




Posts:
125
Registered:
1/22/07


Am 10.08.2016 um 10:30 schrieb Andrej Mrvar:
No. Just generate two random Integers and do:
MyRandomInt64 := Int64(RandomInt1) shl 32 or RandomInt2;
As I learned there is at least one problem with this solution:
Delphi random generator gives you random 31 bit number and not 32 bit number.
Hey you can check out my random generator class from the mrMath library
> it got an implementation of the mersenne twister random generator. It
results in an 32 bit value but it's "periodicity" is 2^19937  1
> it also got an interface to the os random number functions as well as
the Intel RDRAND assembler instruction.
( https://en.wikipedia.org/wiki/Mersenne_Twister)
check it out on:
https://github.com/mikerabat/mrmath
kind regards
Mike




Posts:
99
Registered:
10/20/10


Function provided by Kim Madsen worked just fine for me so I included it into my program.
Thanks anyway.
Andrej




Legend


Helpful Answer
(5 pts)


Correct Answer
(10 pts)


Connect with Us