By registering with us, you'll be able to discuss, share and private message with other members of our community.
SignUp Now!It's not that simple!WAD - the maximum value allowed is 2147483647 - 1. I've corrected the help to reflect this.
v:\> do i=1 to 5 ( echo %@random[-1,2147483646] )
-405438847
-272795195
-311299433
1073697800
384306837
Someone might have a use for it. But, really, it's all screwed up. Compare it to v20.Is that a real use case?
p:\4utils\release> echo %@random[%@eval[2**32], %@eval[2**63-2]]
1881353011
p:\4utils\release> echo %@random[8999999999999999000,9000000000000000000]
-494666116
p:\4utils\release> echo %@random[%@eval[2**32], %@eval[2**64-3]]
TCC: (Sys) The parameter is incorrect.
"%@random[4294967296, 18446744073709551613]"
I see in the help that you changed @RANDOM (significantly) so that it now can produce 64-bit numbers. Internally it may be OK, but the output isn't. It always outputs a number in the INT range. This one shouldn't be in the INT range.
Code:p:\4utils\release> echo %@random[%@eval[2**32], %@eval[2**63-2]] 1881353011
This one always gives a negative result (in the INT range).
Code:p:\4utils\release> echo %@random[8999999999999999000,9000000000000000000] -494666116
And here (below) while the range meets the stated criterion, there's a bad parameter message.
Code:p:\4utils\release> echo %@random[%@eval[2**32], %@eval[2**64-3]] TCC: (Sys) The parameter is incorrect. "%@random[4294967296, 18446744073709551613]"
(do i=1 to 10000 (echo %@random[-6148914691236517205,6148914691236517205])) > clip:
v:\> do i=1 to 100 (echo %@random[-6148914691236517205,6148914691236517205]) | ffind /v /t"-" /u
66 lines in 1 file
INT WINAPI f_TEST ( LPWSTR psz )
{
LONGLONG llLo = 0, llHi = 0; // inclusive, limited to plus/minus (_I64_MAX-1) = 9223372036854775806
Sscanf(psz, L" %I64d , %I64d ", &llLo, &llHi);
if ( llHi < llLo )
{
TCError(ERROR_INVALID_PARAMETER, psz);
return -1;
}
ULONGLONG x, span = llHi - llLo + 1, limit = span*(0xFFFFFFFFFFFFFFFF/span);
do x = genrand64_int64(); while ( x >= limit );
// take your pick
//_i64tow_s(llLo + (x % span), psz, 32, 10);
Sprintf(psz, L"%I64d", llLo + ( x % span ));
return 0;
}
v:\> timer & do i=1 to 10000 (echo %@random[-6148914691236517205,6148914691236517205]) | ffind /v /t"-"
/u & timer
Timer 1 on: 23:57:03
6624 lines in 1 file
Timer 1 off: 23:57:06 Elapsed: 0:00:02.65
v:\> timer & do i=1 to 10000 (echo %@test[-6148914691236517205,6148914691236517205]) | ffind /v /t"-" /u
& timer
Timer 1 on: 23:58:07
5019 lines in 1 file
Timer 1 off: 23:58:10 Elapsed: 0:00:02.53
A very, very slightly better workaround would be to use 2^64 where I used 0xFFFFFFFFFFFFFFFF, but that's hard to do on my computer! :-)
v:\> timer /q & do i=1 to 10000 (noop %@random[0,1]) & timer
Timer 1 off: 12:06:33 Elapsed: 0:00:02.21
v:\> timer /q & do i=1 to 10000 (noop %@test[0,1]) & timer
Timer 1 off: 12:06:40 Elapsed: 0:00:02.23
v:\> echo %@test[%@eval[-(2**63)],%@eval[2**63-1]]
-6901783667727303969
INT WINAPI f_TEST ( LPWSTR psz )
{
LONGLONG llLo = 0, llHi = 0; // inclusive range, no restrictions
if ( Sscanf(psz, L" %I64d , %I64d ", &llLo, &llHi) != 2 || llHi < llLo )
{
TCError(ERROR_INVALID_PARAMETER, psz);
return -1;
}
ULONGLONG x, span = llHi - llLo + 1, limit;
// span == 0 means span == 2^64 (which is OK)
// the second disjunct below is equivalent to span being a power of 2
// in either case there are no bad guys to throw away
if ( span == 0 || (limit = span*(0xFFFFFFFFFFFFFFFF/span)) + span == 0 )
x = genrand64_int64();
else // else there will be bad guys at the top; disallow them
{ do x = genrand64_int64(); while ( x >= limit ); }
//_i64tow_s(llLo + (span == 0 ? x : (x % span)), psz, 32, 10);
Sprintf(psz, L"%I64d", llLo + (span == 0 ? x : (x % span)));
return 0;
}
#include <random>
extern std::default_random_engine g;
// global scope
std::default_random_engine g; // will be Mersenne Twister ...
// in InitializePlugin()
g.seed(GetTickCount()); // ... according to g.seed's bubble help
#include <random>
INT WINAPI f_TEST ( LPWSTR psz ) // compare to @RANDOM
{
LONGLONG lo = 0, hi = 0; // inclusive range, no restrictions
if ( Sscanf(psz, L" %I64d , %I64d ", &lo, &hi) != 2 || hi < lo )
{
TCError(ERROR_INVALID_PARAMETER, psz);
return -1;
}
std::uniform_int_distribution<LONGLONG> m(lo, hi);
Sprintf(psz, L"%I64d", m(g));
return 0;
}
ULONGLONG x, span = hi - lo + 1, limit, mod;
// span == 0 means span == 2^64, which is good ... no bad guys.
// mod == (span - 1) is also good ... no bad guys.
if ( span == 0 || (mod = (0xFFFFFFFFFFFFFFFF % span)) == (span - 1) )
x = genrand64_int64();
else // else disregard the bad guys at the top
{
limit = 0xFFFFFFFFFFFFFFFF - mod;
do x = genrand64_int64(); while ( x >= limit );
}
//_i64tow_s(lo + (span == 0 ? x : (x % span)), psz, 32, 10);
Sprintf(psz, L"%I64d", lo + (span == 0 ? x : (x % span)));
This persists in build 30.
The distribution of values of @RANDOM[lo,hi] is only uniform (every number equally likely) when (hi - lo +1) is a power of 2. That's because you can only divide up 0 ~ UINT64_MAX into intervals of 0 ~ n-1 (using module, %) EVENLY when n is a power of 2. Here's a histogram of the distribution of values of @random[-6148914691236517205,6148914691236517205] which is an almost-worst case.
do i=1 to 100 (echo %@random[-4611686018427387903,4611686018427387903]) | ffind /v /t"-" /u/code]
returns evenly distributed numbers. Do you have a real-world need for random numbers > -4 quintillion and < 4 quintillion?
That's DWORD_MAX. Don't you mean 0x7FFFFFFFFFFFFFFE? The signed 64-bit integers range from -(2^63) to (2^63-1). That's -9223372036854775808 to 9223372036854775807.Your example @random[-6148914691236517205,] has invalid arguments - the args are signed int 64's, and the max range is 0x7FFFFFFE. So you're specifying a negative range.
The signed 64-bit integers range from -(2^63) to (2^63-1). That's -9223372036854775808 to 9223372036854775807.
There's already @MRAND in 4UTILS. The public version still uses the 32-bit Mersenne Twister. At home it has been updated to produce any 64-bit unsigned integer (0 ~ 2^64-1); subtract 2^63 for 64-bit signed numbers ( -(2^63) ~ 2^63-1). I haven't published it yet.Sound like you have working code, Vince. Why not publish a plugin to replace @RANDOM?
I don't know if we're talking about the same thing, but this certainly handles negative numbers, in fact all pairs of LONGLONGs with lo <= hi. And it uses the Mersenne Twister and doesn't need a uniformity correction.std::rand doesn't support negative numbers (which you apparently want since you keep trying to use them!).
std::uniform_int_distribution<LONGLONG> m(lo, hi);