Author Topic: Random  (Read 420 times)

Paolo

  • Hero Member
  • *****
  • Posts: 771
Random
« on: August 06, 2026, 11:12:32 am »
Hello (Laz 4.8 + fpc324RC1, win10/64)

I understand that a call to "Random" generates a number in the range [0, 1), and I use this function to select a number in the range [X1, X2] using the formula:

Code: Pascal  [Select][+][-]
  1. X := X1 + Random * (X2 - X1);
  2.  

If I am not mistaken, this allows for X = X1 but not X = X2 (meaning the actual range of X is [X1, X2), excluding X2).
I assume it is possible to obtain values ​​very close to X2 without compromising the rest of the calculation; however, I would like to know if there is a way to obtain X = X2 as well.

Thanks.

Чебурашка

  • Hero Member
  • *****
  • Posts: 602
  • СЛАВА УКРАЇНІ! / Slava Ukraïni!
Re: Random
« Reply #1 on: August 06, 2026, 12:17:20 pm »
I also had same question some time ago, seems there's no builtin way to get X2 out of the box.

A very ugly solution is to make a upper limit X2 + epsilon, create a wrapping function that discards values beyond X2 and recalc random X2+epsilon,

Code: Pascal  [Select][+][-]
  1.  
  2. const
  3.   EPSILON=10E-9
  4.  
  5. function TheUgliestRandomIncludingUpperBound(x,y: real): real;
  6. begin
  7.   // verify x < y, bla bla bla
  8.   repeat
  9.     Result := x + (y+EPSILON-x)*Random();
  10.   until Result <= y;
  11. end;
  12.  
  13.  
« Last Edit: August 06, 2026, 12:30:15 pm by Чебурашка »
FPC 3.2.0/Lazarus 2.0.10+dfsg-4+b2 on Debian 11.5
FPC 3.2.2/Lazarus 2.2.0 on Windows 10 Pro 21H2

Mike.Cornflake

  • Hero Member
  • *****
  • Posts: 1309
Re: Random
« Reply #2 on: August 06, 2026, 12:23:23 pm »
I *think* Math.RandomRange(X1, X2) is what you're after.

Though, don't know for sure sorry.

Code: [Select]
function RandomRange(const aFrom, aTo: Integer): Integer;
begin
  Result:=Random(Abs(aFrom-aTo))+Min(aTo,AFrom);
end;

function RandomRange(const aFrom, aTo: Int64): Int64;
begin
  Result:=Random(Abs(aFrom-aTo))+Min(aTo,AFrom);
end;   
   


Lazarus Trunk/FPC latest fixes on Windows 11
  How to use the forum:  https://wiki.lazarus.freepascal.org/Forum

Чебурашка

  • Hero Member
  • *****
  • Posts: 602
  • СЛАВА УКРАЇНІ! / Slava Ukraïni!
Re: Random
« Reply #3 on: August 06, 2026, 12:28:57 pm »
I *think* Math.RandomRange(X1, X2) is what you're after.

Though, don't know for sure sorry.

Code: [Select]
function RandomRange(const aFrom, aTo: Integer): Integer;
begin
  Result:=Random(Abs(aFrom-aTo))+Min(aTo,AFrom);
end;

function RandomRange(const aFrom, aTo: Int64): Int64;
begin
  Result:=Random(Abs(aFrom-aTo))+Min(aTo,AFrom);
end;   


I think this will never return value Max(aTo,AFrom) as OP seems require.
FPC 3.2.0/Lazarus 2.0.10+dfsg-4+b2 on Debian 11.5
FPC 3.2.2/Lazarus 2.2.0 on Windows 10 Pro 21H2

creaothceann

  • Sr. Member
  • ****
  • Posts: 430
Re: Random
« Reply #4 on: August 06, 2026, 12:34:34 pm »
With integers you can use

Code: Pascal  [Select][+][-]
  1. Randomize;
  2. {...}
  3. X := X1 + Random(X2 - X1 + 1);

You can use that with the maximum range:

Code: Pascal  [Select][+][-]
  1. Randomize;
  2. {...}
  3. RNG_0_to_1 := Random(high(Int64)) / (high(Int64) - 1);  // Random(9223372036854775807) / 9223372036854775806
  4. X          := X1 + (RNG_0_to_1 * (X2 - X1));
« Last Edit: August 06, 2026, 12:37:44 pm by creaothceann »

Paolo

  • Hero Member
  • *****
  • Posts: 771
Re: Random
« Reply #5 on: August 06, 2026, 12:46:52 pm »
uhmmm... with double I can think something like

Code: Pascal  [Select][+][-]
  1. X:=X1+Random*(X2-X1); // X2 > X1
  2.  

and then

Code: Pascal  [Select][+][-]
  1. if (X2-X) < Sometolerance then //X2 always > X
  2.   X:=X2
  3.  

for integer if I have to map the range [Xint1..Xint2] I'll do

Code: Pascal  [Select][+][-]
  1. Xint:=Xint1+random(Xint2-Xint1+1);
  2.  

Ah, I saw @creaothceann answer...

but I did not understand his latest case ... how can that achieves X=X2 ?

Paolo

  • Hero Member
  • *****
  • Posts: 771
Re: Random
« Reply #6 on: August 06, 2026, 12:53:07 pm »
..and in  my case I am more interested to reach the higher value so I rewrote in this way

Quote
X := X2 - Random * (X2 - X1);
« Last Edit: August 06, 2026, 01:04:23 pm by Paolo »

H₂SO₄

  • Sr. Member
  • ****
  • Posts: 485
Re: Random
« Reply #7 on: August 06, 2026, 01:30:13 pm »
You're working with floats, right?

The probability of drawing any specific real number from any probability distribution is exactly 0, so theoretically (at least for the uniform distribution used by  Random)  it makes no difference whether the interval is  [0, 1)  or  [0, 1].

Practically Random(): Extended  divides a random 32-bit integer by the 32-bit integer maximum plus one, so the probability of finding exactly 1.0 (if it were included) would be around 1 in 4.3 billion. Does that really make a difference in your application?

Чебурашка

  • Hero Member
  • *****
  • Posts: 602
  • СЛАВА УКРАЇНІ! / Slava Ukraïni!
Re: Random
« Reply #8 on: August 06, 2026, 01:49:56 pm »
Does that really make a difference in your application?

OP says he is interested in obtaining also upper bound. So likely answer is "yes".
FPC 3.2.0/Lazarus 2.0.10+dfsg-4+b2 on Debian 11.5
FPC 3.2.2/Lazarus 2.2.0 on Windows 10 Pro 21H2

Paolo

  • Hero Member
  • *****
  • Posts: 771
Re: Random
« Reply #9 on: August 06, 2026, 02:02:59 pm »
Now I understood what wrote Creaothceann. thanks.

Quote
Does that really make a difference in your application?

as said in previous post

Quote
I assume it is possible to obtain values ​​very close to X2 without compromising the rest of the calculation

where the meaning is that palying with float we have to accept some kind of tolerance (rounding, computation, etc..) I am well aware of that, and can be well accepted in this my specific case. But I asked and as usual I received very intersting ansewers on the subject.

PS: maybe you mean "minus" ? as specificed by creathoceann ?

Quote
Practically Random(): Extended  divides a random 32-bit integer by the 32-bit integer maximum plus one, so the probability of finding exactly 1.0 (if it were included) would be around 1 in 4.3 billion.

H₂SO₄

  • Sr. Member
  • ****
  • Posts: 485
Re: Random
« Reply #10 on: August 06, 2026, 02:49:23 pm »
Practically Random(): Extended  divides a random 32-bit integer by the 32-bit integer maximum plus one, so the probability of finding exactly 1.0 (if it were included) would be around 1 in 4.3 billion.

PS: maybe you mean "minus" ? as specificed by creathoceann ?

I do mean plus one. The maximum value of a 32-bit unsigned integer is 4294967295, but  Random  divides by 4294967296 (hence why the cast to  Int64  is needed):

Code: Pascal  [Select][+][-]
  1. function random: extended;
  2. begin
  3.   random := mtwist_u32rand * (extended(1.0)/(int64(1) shl 32));
  4. end;

If you want 1.0 to be obtainable you'd have to divide by  Cardinal($FFFFFFFF)not UInt32(0)(Int64(1) shl 32) - 1  or some other synonym of 4294967295.

Paolo

  • Hero Member
  • *****
  • Posts: 771
Re: Random
« Reply #11 on: August 06, 2026, 08:07:50 pm »
Thanks all for the info here provided.

marcov

  • Administrator
  • Hero Member
  • *
  • Posts: 12984
  • FPC developer.
Re: Random
« Reply #12 on: August 06, 2026, 08:13:59 pm »
const
  EPSILON=10E-9

Epsilon is a binary value, not a decimal one. So this is not exact.

Paolo

  • Hero Member
  • *****
  • Posts: 771
Re: Random
« Reply #13 on: August 06, 2026, 08:18:11 pm »
I think the point here is that it is a small number not its exactness.

 

TinyPortal © 2005-2018