Is it possible to get an extremely fast, but reliable (Same input = same output, so I can't use time) pseudo-random number generator? I want the end result to be something like float NumGen( int x, int y, int seed ); so that it creates a random number between 0 and 1 based on those three values. I found several random number generators, but I can't get them to work, and the random number generator that comes with Unity is far to slow to use. I have to make about 9 calls to the generator per 1 meter of terrain, so I don't really care if it's not perfectly statistically random, just that it works really quickly. Does anyone know of an algorithm that fits my needs? Thanks :)
I think you are underestimating the System.Random class. It is quite speedy. I believe your slow down is related to creating a new instance of the Random class on each call to your NumGen method.
In my quick test I was able to generate 100,000 random numbers using System.Random in about 1 millisecond.
To avoid the slow down consider seed points in your 2D plane. Disperse the seed points so that they cover a distance no greater than 100,000 meters. Then associate (or calculate) the nearest seed point for each meter, and use that point as your seed to System.Random.
Yes, you will be generating a ton of random numbers you will never use, but they are virtually free.
Pseudo-code:
double NumGen(x, y, distance, seed) {
Random random = new Random(seed);
double result = 0;
for (int i=0; i<distance; i++) {
result = random.NextDouble();
}
}
You could modify this simple outline to return a sequence of random numbers (possibly representing a grid), and couple that with a caching mechanism. That would let you conserve memory and improve (lessen) CPU consumption.
I guess you had to create a Random instance on every call to NumGen. To get the function to return the same number for the same parameters you could use a hash function.
I tested a few things, and this code was about 3 times faster than recreating intances of Random.
//System.Security.Cryptography
static MD5 hasher = MD5.Create();
static byte[] outbuf;
static byte[] inbuf = new byte[12];
static float floatHash(uint x, uint y, uint z) {
inbuf[0]= (byte)(x >> 24);
inbuf[1]=(byte)(x >> 16);
inbuf[2]=(byte)(x >> 8);
inbuf[3]=(byte)(x);
inbuf[4]=(byte)(y >> 24);
inbuf[5]=(byte)(y >> 16);
inbuf[6]=(byte)(y >> 8);
inbuf[7]=(byte)(y);
inbuf[8]=(byte)(z >> 24);
inbuf[9]=(byte)(z >> 16);
inbuf[10]=(byte)(z >> 8);
inbuf[11]=(byte)(z);
outbuf = hasher.ComputeHash(inbuf);
return ((float)BitConverter.ToUInt64(outbuf, 0))/ulong.MaxValue;
}
Another method using some RSA methods is about 5 times faster than new System.Random(seed):
static uint prime = 4294967291;
static uint ord = 4294967290;
static uint generator = 4294967279;
static uint sy;
static uint xs;
static uint xy;
static float getFloat(uint x, uint y, uint seed) {
//will return values 1=> x >0; replace 'ord' with 'prime' to get 1> x >0
//one call to modPow would be enough if all data fits into an ulong
sy = modPow(generator, (((ulong)seed) << 32) + (ulong)y, prime);
xs = modPow(generator, (((ulong)x) << 32) + (ulong)seed, prime);
xy = modPow(generator, (((ulong)sy) << 32) + (ulong)xy, prime);
return ((float)xy) / ord;
}
static ulong b;
static ulong ret;
static uint modPow(uint bb, ulong e, uint m) {
b = bb;
ret = 1;
while (e > 0) {
if (e % 2 == 1) {
ret = (ret * b) % m;
}
e = e >> 1;
b = (b * b) % m;
}
return (uint)ret;
}
I ran a test to generate 100000 floats. I used the index as seed for System.Random and as x parameter of floatHash (y and z were 0).
System.Random: Min: 2.921559E-06 Max: 0.9999979 Repetitions: 0
floatHash MD5: Min: 7.011156E-06 Max: 0.9999931 Repetitions: 210 (values were returned twice)
getFloat RSA: Min: 1.547858E-06 Max: 0.9999989 Repetitions: 190
Related
I need a high performance random number generator that is thread-safe. I need only random bytes in the value type (which is ulong for now), not within ranges. I've used the C# built-in Random class, but it was kind of slow and not thread-safe.
Later I moved to XORShift functions that actually works very fine, but to achieve thread-safeness I need to put the calculation in lock, and that degrades the performance drastically.
What I'm using to generate a random ulong is the following:
public class Rand
{
ulong seed = 0;
object lockObj = new object();
public Rand()
{
unchecked
{
seed = (ulong)DateTime.Now.Ticks;
}
}
public Rand(ulong seed)
{
this.seed = seed;
}
public ulong GetULong()
{
unchecked
{
lock (lockObj)
{
ulong t = 0;
t = seed;
t ^= t >> 12;
t ^= t << 25;
t ^= t >> 27;
seed = t;
return t * 0x2545F4914F6CDD1D;
}
}
}
}
This works fine and fast, but locking makes it take about 1-2us if it is called from 200 concurrent threads, otherwise calculation finishes under 100ns.
If I remove locking there is a chance two threads take the same seed and will calculate the same random which is not good for my purposes. If I'm removing the ulong t declaration and work directly on the seed then there will be a very little chance to generate the same random for two concurrent calls, but there is also a chance the value will be shifted out from the value range, like t << 25 will be called many times in a row by different threads without carrying the rotation it will become just simply 0.
I think the proper way would be if there is a shared value that may be changed by any concurrent call and work with that value in the calculation methods, since these values are atomic (at least withing CPU cores) it is not a problem if many calculations are using it in the same time, but that is a problem if this value shifts out from the bitrange.
Is there any good solution to solve this problem? I'd be thankful for any help.
Edit: Ok, I've forgot to mention I have no control over the threads, because async tasks are calling this function, so threads are coming randomly from the threadpool, using thread ID is also a no solution, since there is a chance one specific thread never will call this method again at all, and keeping an instance for that ID is not a good thing.
Simply create one instance of Rand on each thread. Thread-safe, no locking, thus very performant. This can be achieved using the ThreadStaticAttribute.
public static class Rand
{
[ThreadStatic] private static Rand defaultRand;
public static Rand Default => defaultRand ??= new Rand();
// Add extra methods for seeding the static instance...
}
// Then in any thread:
var randomNumber = Rand.Default.GetULong();
You can do it without locking and still be threadsafe. Assuming the calculation is very fast (it is) and there is slower code executing around it, it's likely faster to simply recalculate if another thread changes it in between starting the calculation and finishing it. You can do that with an Interlocked.CompareExchange spin loop. The only difficulty is that there is no ulong version of that so we have to use an unsafe method to get the equivalent.
private static unsafe ulong InterlockedCompareExchange(ref ulong location,
ulong value, ulong comparand)
{
fixed (ulong* ptr = &location)
{
return (ulong)Interlocked.CompareExchange(ref *(long*)ptr, (long)value, (long)comparand);
}
}
public ulong GetULong()
{
unchecked
{
ulong prev = seed;
ulong t = prev;
t ^= t >> 12;
t ^= t << 25;
t ^= t >> 27;
while (InterlockedCompareExchange(ref seed, t, prev) != prev)
{
prev = seed;
t = prev;
t ^= t >> 12;
t ^= t << 25;
t ^= t >> 27;
}
return t * 0x2545F4914F6CDD1D;
}
}
The less code we execute in the critical section, the faster it will work.
It runs 30-50% faster on my CPU.
You can also use an asynchronous process that will prepare the next collection
public sealed class Rand
{
private ulong seed = 0;
private readonly object lockObj = new object();
public Rand()
{
unchecked
{
seed = (ulong) DateTime.Now.Ticks;
}
_current = 500;
}
public Rand(ulong seed)
{
this.seed = seed;
}
private ulong[] _batch = new ulong[501];
private int _current = -1;
public ulong GetULong2()
{
unchecked
{
ulong t = 0;
lock (lockObj)
{
t ^= seed >> 12;
t ^= t << 25;
t ^= t >> 27;
seed = t;
}
return t * 0x2545F4914F6CDD1D;
}
}
public ulong GetULong5()
{
unchecked
{
var t = seed;
t *= (uint)Thread.CurrentThread.ManagedThreadId;
t ^= t >> 12;
t ^= t << 25;
t ^= t >> 27;
seed = t;
return t * 0x2545F4914F6CDD1D;
}
}
public ulong GetULong()
{
unchecked
{
do
{
var current = Interlocked.Increment(ref _current);
if (current < 501)
return _batch[current];
lock (lockObj)
{
if (_current >= 500)
{
ulong t = seed;
for (int i = 0; i < 501; i++)
{
t ^= t >> 12;
t ^= t << 25;
t ^= t >> 27;
var result = t * 0x2545F4914F6CDD1D;
_batch[i] = result;
}
seed = t;
_current = -1;
}
}
}while(true);
}
}
}
Ok this solution by l33t is a very nice and elegant way to fix the cross-thread issue, and this solution by Stanislav also a suitable way to prevent on-demand generation by pre-generating and caching batches. Thanks everyone for the ideas.
Meanwhile I changed the bitshift to rotate, this will avoid shifting out the seed to 0, and I could omit the locking. Apparently it works just fine, and with very small latency (200 concurrent threads with about 100-120ns/call)
public class Rand
{
ulong seed = 0;
object lockObj = new object();
public Rand()
{
unchecked
{
seed = (ulong)DateTime.Now.Ticks;
}
}
public Rand(ulong seed)
{
this.seed = seed;
}
public ulong GetULong()
{
unchecked
{
seed ^= (seed >> 12) | (seed << (64 - 12));
seed ^= (seed << 25) | (seed >> (64 - 25));
seed ^= (seed >> 27) | (seed << (64 - 27));
seed *= 0x2545F4914F6CDD1D;
int s = Environment.CurrentManagedThreadId % 64;
return (seed >> s) | (seed << (64 - s));
}
}
// even faster
public ulong GetULong2()
{
unchecked
{
seed ^= (seed >> 12) | (seed << (64 - 12));
seed ^= (seed << 25) | (seed >> (64 - 25));
seed ^= (seed >> 27) | (seed << (64 - 27));
ulong r = seed * 0x2545F4914F6CDD1D;
seed = r;
int s = Environment.CurrentManagedThreadId % 64;
return (seed >> s) | (seed << (64 - s));
}
}
// better entropy
public ulong GetULong3()
{
unchecked
{
int s = Environment.CurrentManagedThreadId % 12;
seed ^= (seed >> (12 - s)) | (seed << (64 - (12 - s)));
seed ^= (seed << (25 - s)) | (seed >> (64 - (25 - s)));
seed ^= (seed >> (27 - s)) | (seed << (64 - (27 - s)));
ulong r = seed * 0x2545F4914F6CDD1D;
seed = r;
s = Environment.CurrentManagedThreadId % 64;
return (r >> s) | (r << (64 - s));
}
}
}
While this solution fits my demands the most, I will not mark it as an answer because it does not produce the same randoms as the one in the question, but still produces seemingly unique randoms across all threads, so still might be a solution.
Edit: Ok, after some experimenting GetULong() was the fastest, but from 100 million random generations produced more than 23000 colliding values on 200 concurrent threads. Same with GetULong2(). Added a little extra for GetULong3() method to increase entropy, that produced only about 210 colliding values from 100 million generations on 200 concurrent threads, and only about 50 colliding values from 100 million generations on 500 concurrent threads.
For me this kind of entropy is more than enougn, because they must be unique, so in my application after each generation they are tried to be added to a collection atomically and if there is already one with the same key, then random is called again. 50-200 retry in 100 million events is acceptable even on general random generators, so this is more than enough for me, especially, because it is fast, and can be used tread-safe with only one instance of the random generator.
Thank you everyone for the help, I hope this may help others also.
I am trying to get the original 12-bit value from from a base15 (edit) string. I figured that I need a zerofill right shift operator like in Java to deal with the zero padding. How do I do this?
No luck so far with the following code:
static string chars = "0123456789ABCDEFGHIJKLMNOP";
static int FromStr(string s)
{
int n = (chars.IndexOf(s[0]) << 4) +
(chars.IndexOf(s[1]) << 4) +
(chars.IndexOf(s[2]));
return n;
}
Edit; I'll post the full code to complete the context
static string chars = "0123456789ABCDEFGHIJKLMNOP";
static void Main()
{
int n = FromStr(ToStr(182));
Console.WriteLine(n);
Console.ReadLine();
}
static string ToStr(int n)
{
if (n <= 4095)
{
char[] cx = new char[3];
cx[0] = chars[n >> 8];
cx[1] = chars[(n >> 4) & 25];
cx[2] = chars[n & 25];
return new string(cx);
}
return string.Empty;
}
static int FromStr(string s)
{
int n = (chars.IndexOf(s[0]) << 8) +
(chars.IndexOf(s[1]) << 4) +
(chars.IndexOf(s[2]));
return n;
}
Your representation is base26, so the answer that you are going to get from a three-character value is not going to be 12 bits: it's going to be in the range 0..17575, inclusive, which requires 15 bits.
Recall that shifting left by k bits is the same as multiplying by 2^k. Hence, your x << 4 operations are equivalent to multiplying by 16. Also recall that when you convert a base-X number, you need to multiply its digits by a power of X, so your code should be multiplying by 26, rather than shifting the number left, like this:
int n = (chars.IndexOf(s[0]) * 26*26) +
(chars.IndexOf(s[1]) * 26) +
(chars.IndexOf(s[2]));
I can't think of a good way to do this, and would appreciate some help, if possible!
I'm afraid I don't have any code to post yet as I haven't got that far.
I need to generate a sequence of values from 3 (or possible more) parameters in the range 0-999.
The value must always be the same for the given inputs but with a fair distribution between upper and lower boundaries so as to appear random.
For example:
function (1, 1, 1) = 423
function (1, 1, 2) = 716
function (1, 2, 1) = 112
These must be reasonably fast to produce, by which I mean I should be able to generate 100-200 during web page load with no noticeable delay.
The method must be do-able in C# but also in JavaScript, otherwise I'd probably use a CRC32 or MD5 hash algorithm.
If it helps this will be used as part of a procedural generation routine.
I had a go at asking this previously, but I think the poor quality of my explanation let me down.
I apologise if this is worded badly. Please just let me know if so and I'll try to explain further.
Thanks very much for any help.
Here's one:
function sequence(x, y, z) {
return Math.abs(441*x-311*y+293*z) % 1000;
}
It even produces the output from your example!
Using the Marsaglia generator from the Wiki
public class SimpleMarsagliaRandom
{
private const uint original_w = 1023;
private uint m_w = original_w; /* must not be zero */
private uint m_z = 0; /* must not be zero, initialized by the constructor */
public SimpleMarsagliaRandom()
{
this.init(666);
}
public void init(uint z)
{
this.m_w = original_w;
this.m_z = z;
}
public uint get_random()
{
this.m_z = 36969 * (this.m_z & 65535) + (this.m_z >> 16);
this.m_w = 18000 * (this.m_w & 65535) + (this.m_w >> 16);
return (this.m_z << 16) + this.m_w; /* 32-bit result */
}
public uint get_random(uint min, uint max)
{
// max excluded
uint num = max - min;
return (this.get_random() % num) + min;
}
}
and
simpleMarsagliaRandom = function()
{
var original_w = 1023 >>> 0;
var m_w = 0, m_z = 0;
this.init = function(z)
{
m_w = original_w;
m_z = z >>> 0;
};
this.init(666);
var internalRandom = function()
{
m_z = (36969 * (m_z & 65535) + (m_z >>> 16)) >>> 0;
m_w = (18000 * (m_w & 65535) + (m_w >>> 16)) >>> 0;
return (((m_z << 16) >>> 0) + m_w) >>> 0; /* 32-bit result */
};
this.get_random = function(min, max)
{
if (arguments.length < 2)
{
return internalRandom();
}
var num = ((max >>> 0) - (min >>> 0)) >>> 0;
return ((internalRandom() % num) + min) >>> 0;
}
};
In Javascript all the >>> are to coerce the number to uint
Totally untested
Be aware that what is done in get_random to make numbers from x to y is wrong. Low numbers will happen a little more times than higher numbers. To make an example: let's say you have a standard 6 faces dice. You roll it, you get 1-6. Now let's say you print on it the numbers 0-5. You roll it, you get 0-5. No problems. But you need the numbers in the range 0-3. So you do roll % 3... So we have:
rolled => rolled % 3
0 => 0,
1 => 1,
2 => 2,
3 => 0,
4 => 1,
5 => 2,
6 => 0.
The 0 result is more common.
Ideone for C# version: http://ideone.com/VQudcV
JSFiddle for Javascript version: http://jsfiddle.net/dqayk/
You should be able to use MD5 hashing in both C# and JS.
In C#:
int Hash(params int[] values)
{
System.Security.Cryptography.MD5 hasher = MD5.Create();
string valuesAsString = string.Join(",", values);
var hash = hasher.ComputeHash(Encoding.UTF8.GetBytes(valuesAsString));
var hashAsInt = BitConverter.ToInt32(hash, 0);
return Math.Abs(hashAsInt % 1000);
}
In JS, implement the same method using some MD5 algorithm (e.g. jshash)
I have a bit field consisting of 64 bits:
long bitfield = 0;
I can set the bit for a given index as follows:
void Set(long index)
{
bitfield |= 1L << (int)(index % 64);
}
i.e. if the index is 0, 64, 128, ... then bit 0 is set, if the index is 1, 65, 129, ... then bit 1 is set, and so on.
Question: given an index and a count (or a lower and upper index), how can I set the bits for all indexes in this range without using a loop?
long SetRangeMask(int lower, int upper) // 3..7
{
if (! (lower <= upper)) throw new ArgumentException("...");
int size = upper - lower + 1; // 7 - 3 + 1 = 5
if (size >= 64) return -1;
long mask = (1 << size) - 1; // #00100000 - 1 = #000011111
return mask << lower | mask >> -lower; // #00011111 << 3 = #011111000
}
You could use a lookup table for combined bit masks
A real simple approach with no thought to special cases or optimizations like these questions raised, would look like:
static readonly private long[] maskLUT = new long[64,64] { /* generated */ };
void SetRange(long lobit, long hibit)
{
lobit %= 64;
hibit %= 64;
bitfield |= lobit<hibit? maskLUT[lobit,hibit] : maskLUT[hibit,lobit];
}
Thoughts:
you might consider an optimization that given [lobit...hibit], if hibit-lobit>=64 you can set all bits at once.
There is a bit of thought to be put in the connected-ness of regions given the fact that both boundaries can wrap around (do you wrap-around both boundaries first, or do you wraparound lobit, and use the delta to find the hibit from the wrapped boundary, like with the optimization mentioned before?)
You can use 2x-1 to create a mask x bits long, then shift it and OR it in, like so:
void Set( int index, int count ) {
bitfield |= (long)(Math.Pow( 2, count ) - 1) << ((index-count) % 64);
}
Update: I like to think that Math.Pow optimizes powers of two to a left shift, but it may not. If that's the case, you can get a little more performance by replacing the call to Math.Pow with the corresponding left shift:
public void Set( int index, int count ) {
bitfield |= ((2 << count - 1) - 1) << ((index-count) % 64);
}
I need to pass a parameter as two int parameters to a Telerik Report since it cannot accept Long parameters. What is the easiest way to split a long into two ints and reconstruct it without losing data?
Using masking and shifting is your best bet. long is guaranteed to be 64 bit and int 32 bit, according to the documentation, so you can mask off the bits into the two integers and then recombine.
See:
static int[] long2doubleInt(long a) {
int a1 = (int)(a & uint.MaxValue);
int a2 = (int)(a >> 32);
return new int[] { a1, a2 };
}
static long doubleInt2long(int a1, int a2)
{
long b = a2;
b = b << 32;
b = b | (uint)a1;
return b;
}
static void Main(string[] args)
{
long a = 12345678910111213;
int[] al = long2doubleInt(a);
long ap = doubleInt2long(al[0],al[1]);
System.Console.WriteLine(ap);
System.Console.ReadKey();
}
Note the use of bitwise operations throughout. This avoids the problems one might get when using addition or other numerical operations that might occur using negative numbers or rounding errors.
Note you can replace int with uint in the above code if you are able to use unsigned integers (this is always preferable in this sort of situation, as it's a lot clearer what's going on with the bits).
Doing bit-manipulation in C# can be awkward at times, particularly when dealing with signed values. You need to be using unsigned values whenever you plan on doing bit-manipulation. Unfortunately it's not going to yield the nicest looking code.
const long LOW_MASK = ((1L << 32) - 1);
long value = unchecked((long)0xDEADBEEFFEEDDEAD);
int valueHigh = (int)(value >> 32);
int valueLow = (int)(value & LOW_MASK);
long reconstructed = unchecked((long)(((ulong)valueHigh << 32) | (uint)valueLow));
If you want a nicer way to do this, get the raw bytes for the long and get the corresponding integers from the bytes. The conversion to/from representations doesn't change very much.
long value = unchecked((long)0xDEADBEEFFEEDDEAD);
byte[] valueBytes = BitConverter.GetBytes(value);
int valueHigh = BitConverter.ToInt32(valueBytes, BitConverter.IsLittleEndian ? 4 : 0);
int valueLow = BitConverter.ToInt32(valueBytes, BitConverter.IsLittleEndian ? 0 : 4);
byte[] reconstructedBytes = BitConverter.IsLittleEndian
? BitConverter.GetBytes(valueLow).Concat(BitConverter.GetBytes(valueHigh)).ToArray()
: BitConverter.GetBytes(valueHigh).Concat(BitConverter.GetBytes(valueLow)).ToArray();
long reconstructed = BitConverter.ToInt64(reconstructedBytes, 0);
For unigned the following will work:
ulong value = ulong.MaxValue - 12;
uint low = (uint)(value & (ulong)uint.MaxValue);
uint high = (uint)(value >> 32);
ulong value2 = ((ulong)high << 32) | low;
long x = long.MaxValue;
int lo = (int)(x & 0xffffffff);
int hi = (int)((x - ((long)lo & 0xffffffff)) >> 32);
long y = ((long)hi << 32) | ((long)lo & 0xffffffff);
Console.WriteLine(System.Convert.ToString(x, 16));
Console.WriteLine(System.Convert.ToString(lo, 16));
Console.WriteLine(System.Convert.ToString(hi, 16));
Console.WriteLine(System.Convert.ToString(y, 16));
Converting it to and from a string would be much simpler than converting it two and from a pair of ints. Is this an option?
string myStringValue = myLongValue.ToString();
myLongValue = long.Parse(myStringValue);
Instead of mucking with bit operations, just use a faux union. This also would work for different combinations of data types, not just long & 2 ints. More importantly, that avoids the need to be concerned about signs, endianness or other low-level details when you really only care about reading & writing bits in a consistent manner.
using System;
using System.Runtime.InteropServices;
public class Program
{
[StructLayout(LayoutKind.Explicit)]
private struct Mapper
{
[FieldOffset(0)]
public long Aggregated;
[FieldOffset(0)]
public int One;
[FieldOffset(sizeof(int))]
public int Two;
}
public static void Main()
{
var layout = new Mapper{ Aggregated = 0x00000000200000001 };
var one = layout.One;
var two = layout.Two;
Console.WriteLine("One: {0}, Two: {1}", one, two);
var secondLayout = new Mapper { One = one, Two = two };
var aggregated = secondLayout.Aggregated;
Console.WriteLine("Aggregated: {0}", aggregated.ToString("X"));
}
}