I have recently used Visual Basic .Net to write a particle system which emits particles with random velocities in the x and y direction and is affected by gravity. I switched to C# .Net and used the XNA Game Studio which makes the graphics handling much more convenient than GDI+.
The problem I have with C# is that the random numbers are not "random enough". My particle system has 2500 particles but you can clearly see that the particles are distributed in a grid-like fashion about 100 pixels apart and I did not have that problem with Visual Basic's Rnd() function.
What does Visual Basic do which C# does not, and how can I get the same results in C#?
I have tried to re-initialise my random numbers at different stages of the game loop but I end up either with my particles staying at one position or emitting just in a constant stream in one direction.
This is my C# code: LoadContent is called first thing after the program has started. I'm using the millisecond as a seed just so that I start each time with a different configuration.
The next time I re-seed is after all the calculations are done on the system just before rendering. The other alternative I tried is to re-seed after every 100 particles have been calculated but with no difference.
protected override void LoadContent()
{
// Create a new SpriteBatch, which can be used to draw textures.
spriteBatch = new SpriteBatch(GraphicsDevice);
mousePos = Content.Load<Texture2D>("Point");
spriteTex = Content.Load<Texture2D >("Point");
rnd = new Random(a.Millisecond);
for (int i = 0; i < spritePos .Length; i++)
{
newPos[i] = new Vector2(800, 450);
spritePos[i] = newPos[i] ;
Scale[i] = rnd.Next(100,500);
renderCol[i] = new Color(rnd.Next(255), rnd.Next(255), rnd.Next(255), 1);
spriteVelocity[i] = new Vector2((rnd.Next(2000)-1000)/100, -rnd.Next(500,1500)/100);
Life[i] = rnd.Next(60);
Rotate[i] = (rnd.Next(1000)-500) * 0.001f;
RotateSpeed[i] = (rnd.Next(1000)-500) * 0.0001f;
}
}
This is my VB code, the only place where I use the rnd function:
For i = x To x + 1000
ptc(i) = New particle(New Vector((Rnd() * 200) - 200 * Rnd(), Rnd() * -100 - 200 * Rnd() - 200), New Vector(e.X, e.Y), 500, Color.FromArgb(Rnd() * 255, 255, 0))
x += 1
Next
In my VB code there is no place where I call the randomize function, I have noticed that my particles have the same pattern-like behaviour if I do. Excuse all the strange arithmetic, it's all just experimentation.
Ok, what you do to fix it Charl, is to create a single Random object (which you are) with no seed, and use it over and over again. So something like:
const double max = 1000.0;
Random rand = new Random(); // Like mentioned, don't provide a seed, .NET already picks a great seed for you
for(int iParticle = 0; iParticle < 2500; iParticle++)
{
double x = rand.NextDouble() * max; // Will generate a random number between 0 and max
double y = rand.NextDouble() * max;
}
To get a random floating point value (float or double) between a lower and upper bound, you can use something like:
double x = (rand.NextDouble() * (max - min)) + min;
EDIT: And make sure to use double or float. Ints are whole numbers only, doubles and floats can store real numbers and is probably what VB was using.
If you had posted some code we would probably have been able to point out where you are creating a new Random() object for each call .
Like in, for example, Random number in a loop
After seeing the code,
are you aware that (rnd.Next(2000)-1000)/100 is an integer only expression? The result will be converted to float but always end in ##.0.
In VB I / J yields a double.
Random class ensures pseudo-randomness, if that is what you are using. Have a look at RNGCryptoServiceProvider.
Related
I am using Unity c#, and I am coding something that relies on Perlin noise to determine a random number between 0 and 1. I would like to implement a feature in my code that allows the user to define a specific pre-determined seed number to use for this, but I am not sure if the Perlin noise function actually uses the same random seed as the Random class does.
For example; if I want to generate Perlin noise using Mathf.PerlinNoise() - will it always be the same if I always set the RNG seed priory, using the same number?
minimal code example:
Random.InitState(4815162342);
float _randomSample = Mathf.PerlinNoise(yada yada yada);
I would like to use this for a Minecraft-like system of generating a procedural game world and having a way for the player to choose a seed would be great. in that code example, the player's chosen seed was the numbers from the TV show "Lost". (4815162342)
The two are not related!
The only thing that Random.InitState changes is the way how e.g. Random.Range or Random.value work.
Without using it it would simply use values based on the system time instead.
Mathf.PerlinNoise is not connected to that. You can actually try different seeds and always see the same perlin result. This is actually stated in the API
The same coordinates will always return the same sample value but the plane is essentially infinite so it is easy to avoid repetition by choosing a random area to sample from.
They already give you a hint how to solve your problem: Use a different offset!
Now here comes your seed into play: Simply choose a random offset based on the seed -> random but always equal for the same seed!
Random.InitState(4815162342);
var randomOffsetX = Random.value;
var rabdomOffsetY = Random.value;
var values = new float[25];
for(var x = 0; x < 5; x++)
{
for(var y = 0; y < 5; y++)
{
values[x*5 + y] = Mathf.PerlinNoise(x + randomOffsetX, y + randomOffsetY);
}
}
This should give you 25 random values (between 0 and 1). But they should be equal for every time you use the same seed.
If you actually don't need the noise pattern but only one single value basically you could achieve the same thing simply using
Random.InitState(4815162342);
var value = Random.Range(0f, 1f);
I need to generate a number of float numbers with approximately normal distribution over a range from 0 to a specific ceiling.
I've searched on stack overflow and found similar questions for other languages, but none for .net core.
internal List<float> function(int ceiling, int repetitions)
{
List<float> list = new List<float>();
for (int i = 0; i<= repetitions;i++)
{
list.Add(Random.nextFloat() * ceiling);
}
return list;
}
I expect the function to return a list of random positive floatnumbers, in range from 0 to a given ceiling with at least approximately normal distribution.
If you're seeking something "at least approximately normal" with bounds at 0 and ceiling, summing three uniforms will yield a result which is symmetric, bell-shaped, and bounded, and can subsequently be rescaled to any range you wish. I'm not a C# programmer, but if you have a PRNG named prng:
(prng.NextDouble() + prng.NextDouble() + prng.NextDouble()) * ceiling / 3.0
will yield a result in the range [0, ceiling]. Here's what 100,000 observations look like with ceiling set to 3:
You can generalize this to sum k uniforms and replace the 3 by k in the divisor for the rescaling. The larger k is, the closer this will get to normality by the central limit theorem, but since you don't seem to be asking for actual normals (which don't have a bounded range anyway) that quickly gets into diminishing returns.
Note that while this approach uses multiple uniforms, it is computationally relatively efficient because it avoids transcendental functions.
Well, you could use truncated normal together with taking absolute values to make result positive.
Along the lines
double R = 10.0; // upper value of the truncated normal
var seed = 31234567;
Random rng = new Random( seed );
double u1 = rng.NextDouble();
double u2 = rng.NextDouble();
double phi = 2.0*Math.PI*u2;
double r = Math.Sqrt(-2.0*Math.Log(1.0 - u1*(1.0 - Math.Exp(-R*R/2.0))));
return new Tuple<double,double>(Math.Abs(r*Math.Cos(phi)), Math.Abs(r*Math.Sin(phi)));
Code above shall return couple of sampled values in the interval from 0 to R which looks like truncated gaussian. You could compare with Box-Muller for standard gaussain sampling
I am trying to "fake 3D" in a game in WPF. Think of a road, and that the objects appear somewhere in the distant. As they get closer, they look bigger, and eventually they grow in size very fast.
I'm thinking that when the object appears, it's close to 0 in width and height. As it moves towards the player, it becomes closer to hundred percent of its true size.
I think I will need to solve this using logarithmic calculations, and there are several threads on that. What I would really want to do however, is to send in three values to a LogaritmicGrowth method:
the starting Y point
the point at which the object should appear at 100%
the y point where the object is at this very moment.
Thus, what I would like to get in return is the scaling factor for the object in question. So if it's halfway between the starting point and the ending point, then perhaps 0.3 (or so) should be returned.
I can write the method inputs and outputs myself, but need help with the calculation. Thanks!
I am not entirely sure about the use of log here. This is a simple geometry problem.
Think about a point P which is D distance in front of you, which has a height Y (from your line of observation). Your screen is d distance in front of you. The intersection point of the light from P on the screen is p, which makes a height y on screen.
Then, by considering the similar triangles, one can show that:
y = (Y/D) d
Just in case someone else is looking at this question in the future, here's the correct reply (I figured it out myself):
/// <summary>
/// Method that enlargens the kind of object sent in
/// </summary>
public void ExponentialGrowth2(string name, float startY, float endY)
{
float totalDistance = endY - startY;
float currentY = 0;
for (int i = 0; i < Bodies.Bodylist.Count; i++)
{
if (Bodies.Bodylist[i].Name.StartsWith(name)) //looks for all bodies of this type
{
currentY = Bodies.Bodylist[i].PosY;
float distance = currentY - startY + (float)Bodies.Bodylist[i].circle.Height;
float fraction = distance / totalDistance; //such as 0.8
Bodies.Bodylist[i].circle.Width = Bodies.Bodylist[i].OriginalWidth * Math.Pow(fraction, 3);
Bodies.Bodylist[i].circle.Height = Bodies.Bodylist[i].OriginalHeight * Math.Pow(fraction, 3);
}
}
}
The method could be worked on further, such as allowing randomized power-to values (say from 1.5 to 4.5). Note that the higher the exponential value, the greater the effect.
I am creating a stock trading simulator where the last days's trade price is taken as opening price and simulated through out the current day.
For that I am generating random double numbers that may be somewhere -5% of lastTradePrice and 5% above the lastTradePrice. However after around 240 iterations I see how the produced double number gets smaller and smaller closing to zero.
Random rand = new Random();
Thread.Sleep(rand.Next(0,10));
Random random = new Random();
double lastTradeMinus5p = model.LastTradePrice - model.LastTradePrice * 0.05;
double lastTradePlus5p = model.LastTradePrice + model.LastTradePrice * 0.05;
model.LastTradePrice = random.NextDouble() * (lastTradePlus5p - lastTradeMinus5p) + lastTradeMinus5p;
As you can see I am trying to get random seed by utilising Thread.sleep(). And yet its not truly randomised. Why is there this tendency to always produce smaller numbers?
Update:
The math itself is actually fine, despite the downwards trend as Jon has proven it.
Getting random double numbers between range is also explained here.
The real problem was the seed of Random. I have followed Jon's advice to keep the same Random instance across the thread for all three prices. And this already is producing better results; the price is actually bouncing back upwards. I am still investigating and open to suggestions how to improve this. The link Jon has given provides an excellent article how to produce a random instance per thread.
Btw the whole project is open source if you are interested. (Using WCF, WPF in Browser, PRISM 4.2, .NET 4.5 Stack)
The TransformPrices call is happening here on one separate thread.
This is what happens if I keep the same instance of random:
And this is generated via RandomProvider.GetThreadRandom(); as pointed out in the article:
Firstly, calling Thread.Sleep like this is not a good way of getting a different seed. It would be better to use a single instance of Random per thread. See my article on randomness for some suggested approaches.
However, your code is also inherently biased downwards. Suppose we "randomly" get 0.0 and 1.0 from the random number generator, starting with a price of $100. That will give:
Day 0: $100
Day 1: $95 (-5% = $5)
Day 2: $99.75 (+5% = $4.75)
Now we can equally randomly get 1.0 and 0.0:
Day 0: $100
Day 1: $105 (+5% = $5)
Day 2: $99.75 (-5% = $5.25)
Note how we've got down in both cases, despite this being "fair". If the value increases, that means it can go down further on the next roll of the dice, so to speak... but if the value decreases, it can't bounce back as far.
EDIT: To give an idea of how a "reasonably fair" RNG is still likely to give a decreasing value, here's a little console app:
using System;
class Test
{
static void Main()
{
Random random = new Random();
int under100 = 0;
for (int i = 0; i < 100; i++)
{
double price = 100;
double sum = 0;
for (int j = 0; j < 1000; j++)
{
double lowerBound = price * 0.95;
double upperBound = price * 1.05;
double sample = random.NextDouble();
sum += sample;
price = sample * (upperBound - lowerBound) + lowerBound;
}
Console.WriteLine("Average: {0:f2} Price: {1:f2}", sum / 1000, price);
if (price < 100)
{
under100++;
}
}
Console.WriteLine("Samples with a final price < 100: {0}", under100);
}
}
On my machine, the "average" value is always very close to 0.5 (rarely less then 0.48 or more than 0.52) but the majority of "final prices" are always below 100 - about 65-70% of them.
Quick guess: This is a math-thing, and not really related to the random generator.
When you reduce the trade price by 5%, you get a resulting value that is lower than that which you began with (obviously!).
The problem is that when you then increase the trade price by 5% of that new value, those 5% will be a smaller value than the 5% you reduced by previously, since you started out with a smaller value this time. Get it?
I obviously haven't verified this, but I have strong hunch this is your problem. When you repeat these operations a bunch of times, the effect will get noticeable over time.
Your math should be:
double lastTradeMinus5p = model.LastTradePrice * 0.95;
double lastTradePlus5p = model.LastTradePrice * (1/0.95);
UPDATE: As Dialecticus pointed out, you should probably use some other distribution than this one:
random.NextDouble() * (lastTradePlus5p - lastTradeMinus5p)
Also, your range of 5% seems pretty narrow to me.
I think this is mainly because the random number generator you are using is technically pants.
For better 'randomness' use RNGCryptoServiceProvider to generate the random numbers instead. It's technically a pseudo-random number generated, but the quality of 'randomness' is much higher (suitable for cryptographic purposes).
Taken from here
//The following sample uses the Cryptography class to simulate the roll of a dice.
using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;
class RNGCSP
{
private static RNGCryptoServiceProvider rngCsp = new RNGCryptoServiceProvider();
// Main method.
public static void Main()
{
const int totalRolls = 25000;
int[] results = new int[6];
// Roll the dice 25000 times and display
// the results to the console.
for (int x = 0; x < totalRolls; x++)
{
byte roll = RollDice((byte)results.Length);
results[roll - 1]++;
}
for (int i = 0; i < results.Length; ++i)
{
Console.WriteLine("{0}: {1} ({2:p1})", i + 1, results[i], (double)results[i] / (double)totalRolls);
}
rngCsp.Dispose();
Console.ReadLine();
}
// This method simulates a roll of the dice. The input parameter is the
// number of sides of the dice.
public static byte RollDice(byte numberSides)
{
if (numberSides <= 0)
throw new ArgumentOutOfRangeException("numberSides");
// Create a byte array to hold the random value.
byte[] randomNumber = new byte[1];
do
{
// Fill the array with a random value.
rngCsp.GetBytes(randomNumber);
}
while (!IsFairRoll(randomNumber[0], numberSides));
// Return the random number mod the number
// of sides. The possible values are zero-
// based, so we add one.
return (byte)((randomNumber[0] % numberSides) + 1);
}
private static bool IsFairRoll(byte roll, byte numSides)
{
// There are MaxValue / numSides full sets of numbers that can come up
// in a single byte. For instance, if we have a 6 sided die, there are
// 42 full sets of 1-6 that come up. The 43rd set is incomplete.
int fullSetsOfValues = Byte.MaxValue / numSides;
// If the roll is within this range of fair values, then we let it continue.
// In the 6 sided die case, a roll between 0 and 251 is allowed. (We use
// < rather than <= since the = portion allows through an extra 0 value).
// 252 through 255 would provide an extra 0, 1, 2, 3 so they are not fair
// to use.
return roll < numSides * fullSetsOfValues;
}
}
According to your code, I can derive it in a simpler version as below:
Random rand = new Random();
Thread.Sleep(rand.Next(0,10));
Random random = new Random();
double lastTradeMinus5p = model.LastTradePrice * 0.95; // model.LastTradePrice - model.LastTradePrice * 0.05 => model.LastTradePrice * ( 1 - 0.05 )
double lastTradePlus5p = model.LastTradePrice * 1.05; // model.LastTradePrice + model.LastTradePrice * 0.05 => model.LastTradePrice * ( 1 + 0.05 )
model.LastTradePrice = model.LastTradePrice * ( random.NextDouble() * 0.1 + 0.95 ) // lastTradePlus5p - lastTradeMinus5p => ( model.LastTradePrice * 1.05 ) - ( model.LastTradePrice * 0.95 ) => model.LastTradePrice * ( 1.05 - 0.95)
So you are taking model.LastTradePrice times a fractional number(between 0 to 1) times 0.1 which will always decrease more to zero, but increase less to 1 !
The litle fraction positive part comes because of the + 0.95 part with the zero-tending random.NextDouble() * 0.1
I am making a program in C# that creates a list of tree objects that have graphics that display them all in a grid like fashion. After creating them I will have it to where each individual tree is moveed a random distance between -10 and 10 over the x and y axis; this will hopefully produce a look of scattered trees. I'm still new to C# basically.
My main problems are:
I'm not sure if it's possible to generate a number between -10 and 10 with my method
int randX = RandomClass.Next(-10, 10);
When I "skew" (skew is a loose term that I used to mean "move" in this context, its nothing literal) each tree's position, it seems as though I am applying the save amount of vertical and horizontal movement to many trees and not to one single tree individually.
public void SkewTrees()
{
if (skewed == false)
{
Vector2 emptyVector = Vector2.Zero;
int randX = RandomClass.Next(0, 100);
int randY = RandomClass.Next(0, 100);
Vector2 randSkew = new Vector2(randX , randY);
position=new Vector2(position.X+randSkew.X, position.Y+randSkew.Y);
skewed = true;
}
}
Full Code with link to actual output:
http://pastebin.com/zZ246t7U
For the random between -10 to 10, try something this way :
int rand = RandomClass.Next(1, 10) - RandomClass.Next(1, 10);
Or
int rand = RandomClass.Next(0, 20) - 10;
Or
int rand = RandomClass.Next(-10, 10);
Works too.
The Random-class produces a deterministic and reproducible sequence of numbers. It takes its seed from Environment.TickCount which changes every 15ms approximately. Therefore every instance of Random that you construct within such a 15ms time interval will produce exactly the same numbers.
In order to fix your code you need to ensure that you either use a good seed value or reuse a single Random class.
I recommend that you create a static variable with a single Random instance. Your entire program can reuse this variable.