Weird behavior of multithread random numbers generator - c#

Please check below code, this code try to compute birthday conflict possibility. To my surprise, if i execute those code with sequence, the result is expected around 0.44; but if try on PLinq, the result is 0.99.
Anyone can explain the result?
public static void BirthdayConflict(int num = 5, int people = 300) {
int N = 100000;
int act = 0;
Random r = new Random();
Action<int> action = (a) => {
List<int> p = new List<int>();
for (int i = 0; i < people; i++)
{
p.Add(r.Next(364) + 1);
}
p.Sort();
bool b = false;
for (int i = 0; i < 300; i++)
{
if (i + num -1 >= people) break;
if (p[i] == p[i + num -1])
b = true;
}
if (b)
Interlocked.Increment(ref act);
// act++;
};
// Result is around 0.99 - which is not OK
// Parallel.For( 0, N, action);
//Result is around 0.44 - which is OK
for (int i = 0; i < N; i++)
{
action(0);
}
Console.WriteLine(act / 100000.0);
Console.ReadLine();
}

You're using a shared (between threads) instance System.Random. It's not thread-safe then you're getting wrong results (well actually it just doesn't work and it'll return 0). From MSDN:
If your app calls Random methods from multiple threads, you must use a synchronization object to ensure that only one thread can access the random number generator at a time. If you don't ensure that the Random object is accessed in a thread-safe way, calls to methods that return random numbers return 0.
Simple (but not so efficient for parallel execution) solution is to use a lock:
lock (r)
{
for (int i = 0; i < people; i++)
{
p.Add(r.Next(364) + 1);
}
}
To improve performance (but you should measure) you may use multiple instances of System.Random, be careful to initialize each one with a different seed.

I find a useful explanation why random does not work under multi-thread, although it was original for Java, still can be benefitical.

Related

What's wrong with this simple method to sample from multinomial in C#?

I wanted to implement a simple method to sample from a multinomial distribution in C# (the first argument is an array of integers we want to sample and the second one is the probabilities of selecting each of those integers).
When I do this with numpy in python, the results make sense.
np.random.choice(np.array([1,2,3,4,5,6]),p=np.array([.624,.23,.08,.04, .02, .006]),size=len(b))
I get a lot of 1's (probability 62%), a bunch of 2's, some 3's etc.
However, when I try the implementation below in C# (pretty straightforward inverse transform sampling for multinomial, only relies on a uniform random variable), I get really weird results. For all 1000 samples, I'll often find all 1's. Sometimes, I'll find all 3's (!!??). The results never look like what you would expect (and what you get from the python function - try running it yourself a few times). This is really scary since we rely on these primitives. Does anyone have insight into what might be wrong with the C# version?
static void Main(string[] args)
{
int[] iis = new int[7];
int[] itms = new int[] { 1, 2, 3, 4, 5, 6 };
double[] probs = new double[] { .624, .23, .08, .04, .02, .006 };
for (int i = 0; i < 1000; i++)
{
iis[MultinomialSample(itms, probs)] += 1;
}
foreach (var ii in iis)
{
Console.Write(ii + ",");
}
Console.Read();
}
private static int MultinomialSample(int[] s, double[] ps)
{
double[] cumProbs = new double[ps.Length];
cumProbs[0] = ps[0];
for (int i = 1; i < ps.Length; i++)
{
cumProbs[i] = cumProbs[i - 1] + ps[i];
}
Random random = new Random();
double u = random.NextDouble();
for (int i = 0; i < cumProbs.Length - 1; i++)
{
if (u < cumProbs[i])
{
return s[i];
}
}
return s[s.Length - 1];
}
You're initializing Random each time you call MultinomialSample. If these calls are very close together, Random will be initialized with the same seed (based on the system clock). Try either making Random a private class field: private static Random random = new Random(); or pass it into the method as an argument from Main, where it would be initialized only once:
private static Random random = new Random();
private static int MultinomialSample(IReadOnlyList<int> sample,
IReadOnlyList<double> probabilities)
{
var cumProbs = new double[probabilities.Count];
cumProbs[0] = probabilities[0];
for (var i = 1; i < probabilities.Count; i++)
{
cumProbs[i] = cumProbs[i - 1] + probabilities[i];
}
for (var i = 0; i < cumProbs.Length - 1; i++)
{
if (random.NextDouble() < cumProbs[i])
{
return sample[i];
}
}
return sample[sample.Count - 1];
}
private static void Main()
{
var iis = new int[7];
var items = new[] {1, 2, 3, 4, 5, 6};
var probabilities = new[] {.624, .23, .08, .04, .02, .006};
for (int i = 0; i < 1000; i++)
{
iis[MultinomialSample(items, probabilities)] ++;
}
Console.WriteLine(string.Join(", ", iis));
Console.WriteLine("\nDone!\nPress any key to exit...");
Console.ReadKey();
}
I used Rufus' code in a simulation I was working on and noticed there is still a problem, even after seeding the random number generator just once (which is the correct thing to do). You will notice that as we are iterating, the call to random.NextDouble() generates a new random number each time. This is wrong.
for (var i = 0; i < cumProbs.Length - 1; i++)
{
if (random.NextDouble() < cumProbs[i])
{
return sample[i];
}
}
The random number should be generated outside of the loop, as follows:
var r = random.NextDouble();
for (var i = 0; i < cumProbs.Length - 1; i++)
{
if (r < cumProbs[i])
{
return sample[i];
}
}
You can compare it to the Excel algorithm given on Wikipedia: https://en.wikipedia.org/wiki/Multinomial_distribution. When I made the above change to Rufus' code, I got the desired frequency distribution as specified by the probabilities array.

Unwrap Tuple or keep it as it is?

Is it faster to process the unwrapping of Tuple and using a few variables instead of just using Tuple as it is. Consider this example :
Tuple<int,int> test = new Tuple<int,int>;
int numberOne = int.Parse(Console.Readline());
int numberTwo = int.Parse(Console.Readline());
test.Item1 = numberOne;
test.Item2 = numberTwo;
for(int i = 0; i < 10; i++)
{
if(test.Item1 * i > test.Item2 * i)
{// do stuff}
else
{// do stuff}
}
VS
Tuple<int,int> test = new Tuple<int,int>;
int numberOne = int.Parse(Console.Readline());
int numberTwo = int.Parse(Console.Readline());
test.Item1 = numberOne;
test.Item2 = numberTwo;
for(int i = 0; i < 1000; i ++)
{
int tempItem1 = test.Item1;
int tempItem2 = test.Item2;
if(tempItem1 * i > tempItem2 * i)
{// do stuff}
else
{// do stuff}
}
I also want to know if unwrapping the Tuple with 2 variables is faster than using item1 and item2. Will the result still be the same if we were using more than 2 variables ?
Thanks in advance
Both versions load the tuple items from memory into a temporary value. The only difference is whether it's a temporary on the IL execution stack or an actual IL local. Normally, this should be within reach of the JIT.
If this was a C compiler it would be 100% certain that the performance is the same. Any case where that was not so would be a bug.
The .NET JIT has a very poor optimizer so you might always get unlucky and step into an optimizer hole.

Random with a specific amount of a specific value

my problem is following: I need to create some random values for scheduling. For example process times are given. Lets say a job j on a machine i gets a random value between (1,99). thats the time the jobs needs on this machine.
Now, I need to manipulate this random values. I like to say of all random process times, 20% of them are zero process times. So does anybody know how it is possible to give an array with integers a specific amount with a specific time??
here the normal random:
p_machine_job_completionTime = new int[Constants.numberMachines][];
for (i = 0; i < Constants.numberMachines; i++)
{
p_machine_job_completionTime[i] = new int[Constants.numberJobs];
for (j = 0; j < Constants.numberJobs; j++)
{
p_machine_job_completionTime[i][j] = random.Next(1, 99);
}
}
Now, jobs may skip a machine and consequently have a processing time of 0. Is it possible to limit the random values, with guaranteeing that x% of all my random values has the value 0 ??
e.g.:
20% of p_machine_job_completionTime[i][j] = 0
80% of p_machine_job_completionTIme[i][j] = random (1,99)
I am very thankful for any small any tiny advice.
Just separate two cases: 20% when 0 should be returned and 80% when 1..99 is the outcome
Random random;
...
int value = random.Next(5) == 0 ? 0 : random.Next(99) + 1;
One way to do this would be by generating two random values: One for determining whether to use 0, and (possibly) another to generate non-zero values. However, you can combine both randoms into one by increasing the range of your random values by the appropriate amount, and converting any results above your limit to 0:
int val = random.Next(1, 123);
if (val >= 99)
val = 0;
In this case, your target range contains 98 possible values (1 to 98, since the upper bound is exclusive). To get 0 with 20% probability, you need to extend the range of your random generator to 1 / (1 - 20%), or 125% of its present value, which would be 123.
I think what the existing answers are missing is this important point:
"Is it possible to limit the random values, with guaranteeing that x%
of all my random values has the value 0"
If you need to guarantee that at the end of the day some random exactly x% of the items are given a value of zero, then you can't use random as in the answer from #Douglas. As #Douglas says, "To get 0 with 20% probability." But as stated in the question we don't want 20% probability, we want EXACTLY 20%, and the other exactly 80% to have random values. I think the code below does what you want. Filled in some values for numberMachines and numberJobs so the code can be run.
int numberMachines = 5;
int numberJobs = 20;
Random random = new Random();
var p_machine_job_completionTime = new int[numberMachines][];
var theTwentyPercent = new HashSet<int>(Enumerable.Range(0,(numberJobs * numberMachines) -1 ).OrderBy(x => Guid.NewGuid()).Take(Convert.ToInt32((numberMachines * numberJobs) * 0.2)));
for (int i = 0; i < numberMachines; i++) {
p_machine_job_completionTime[i] = new int[numberJobs];
for (int j = 0; j < numberJobs; j++) {
int index = (i * numberJobs) + j;
if (theTwentyPercent.Contains(index)) {
p_machine_job_completionTime[i][j] = 0;
}
else {
p_machine_job_completionTime[i][j] = random.Next(1, 99);
}
}
}
Debug.Assert( p_machine_job_completionTime.SelectMany(x => x).Count(val => val==0) == (numberMachines * numberJobs) * 0.2 );
I think that you do not need to include this within Random in your case. You could simply use modulo as a part of your for loop:
p_machine_job_completionTime = new int[Constants.numberMachines][];
int counter = 0;
for (i = 0; i < Constants.numberMachines; i++)
{
p_machine_job_completionTime[i] = new int[Constants.numberJobs];
for (j = 0; j < Constants.numberJobs; j++)
{
if( counter%5 == 0)
{
p_machine_job_completionTime[i][j] = 0;
}
else
{
p_machine_job_completionTIme[i][j] = random (1,99);
}
counter++;
}
}

C# perfect numbers exercise

can you help me with the following exercise pls? (it's not homework, just an exercise in the book I'm using.)
"An integer is said to be a perfect number if its factors, including one (but not the number itself), sum to the number. For example, 6 is a perfect number, because 6 = 1 + 2 + 3. Write method Perfect that determines whether parameter value is a perfect number. Use this method in an app that determines and displays all the perfect numbers between 2 and 1000. Display the factors of each perfect number to confirm that the number is indeed perfect."
so here's what i got so far:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Perfect_Numbers2
{
class Program
{
static bool IsItPerfect(int value)
{
int x = 0;
int counter = 0;
bool IsPerfect = false;
List<int> myList = new List<int>();
for (int i = value; i <= value; i++)
{
for (int j = 1; j < value; j++)
{
// if the remainder of i divided by j is zero, then j is a factor of i
if (i%j == 0) {
myList[counter] = j; //add j to the list
counter++;
}
for (int k = 0; k < counter; k++)
{
// add all the numbers in the list together, then
x = myList[k] + myList[k + 1];
}
// test if the sum of the factors equals the number itself (in which case it is a perfect number)
if (x == i) {
IsPerfect = true;
}
}
Console.WriteLine(i);
}
return IsPerfect;
}
static void Main(string[] args)
{
bool IsItAPerfectNum = false;
for (int i = 2; i < 1001; i++)
{
IsItAPerfectNum = IsItPerfect(i);
}
}
}
}
how would you do it? is my code fixable? how would you fix it? thanks!
im getting an error at line myList[counter] = j; (index was out of range) and besides it's not displaying the perfect numbers like it's supposed to....
EDIT = I made some changes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Perfect_Numbers2
{
class Program
{
static bool IsItPerfect(int value)
{
int x = 0;
int counter = 0;
bool IsPerfect = false;
List<int> myList = new List<int>();
for (int i = value; i <= value; i++)
{
for (int j = 1; j < i; j++)
{
if (i%j == 0) // if the remainder of i divided by j is zero, then j is a factor of i
{
myList.Add(j); //add j to the list
}
x = myList.Sum();
if (x == i) // test if the sum of the factors equals the number itself (in which case it is a perfect number)
{
IsPerfect = true;
}
}
Console.WriteLine(i);
}
return IsPerfect;
}
static void Main(string[] args)
{
bool IsItAPerfectNum = false;
for (int i = 2; i < 1001; i++)
{
IsItAPerfectNum = IsItPerfect(i);
Console.WriteLine(IsItAPerfectNum);
Console.ReadKey(true);
}
}
}
}
now i can cycle through all the numbers until 1000 and it displays if it's perfect or not (true or false) [which isn't what the exercise called for, but it's a step in the right direction (the exercise says that it should display only the perfect numbers)].
In any case, what's strange is that it says true at number 24, which isn't a perfect number.... http://en.wikipedia.org/wiki/Perfect_numbers#Examples
why is 24 different?
thanks very much
can you help me with the following exercise please?
Yes. Rather than showing you where your error is, I'll teach you how to find your error. Even better, the same technique will lower the chances of you causing the error in the first place.
The key here is to break the problem down into small parts where each small part can be tested independently. You have already started to do this! You have two methods: Main and IsItPerfect. You should have at least three more methods. The methods you should have are:
IsDivisor -- takes two integers, returns true if the first divides the second.
GetAllDivisors -- takes an integer, returns a list of all the divisors
Sum -- takes a list of integers, returns the sum
Your method IsPerfect should be calling GetAllDivisors and Sum and comparing the sum to the original number, and that's all it should be doing. Your method GetAllDivisors should be calling IsDivisor, and so on.
You can't find the bug easily because your method is doing too much. If you're not getting the correct result out and you have four methods instead of one then you can test each method independently to make sure that it works, or fix it if it does not.
Your first for loop will be executed exactly once.
for (int i = value; i <= value; i++)
For example for value = 6
for (int i = 6; i <= 6; i++)
Some help with the 24 issue you are having: 24 is returning true as you are actually checking if it is perfect on every additional factor. So 24 gets flipped to true here:
Factors of 24 | Total so far
1 1
2 3
3 6
4 10
6 16
8 24 <-- returns true
12 36 <-- should be false, but flag is never reset
I have just now completed the same exercise which is from a really great book called visual c# 2012 by Mr Deitel.
The way i started to tackle is, i started off with figuring out how to work out the factorials of numbers and then slowly kept building on from there.
Since you are following the same book, i would suggest you not to use things that are not covered up to that chapters exercise, like list collections which you have used, As this will make the exercise unnecessarily difficult. and negates the learning methodology set out by of the author.
here is my code which i hope can help you in some way.
class Program
{
static int factorTotal = 1;
static void Main(string[] args)
{
int count = 1;
while (count <= 10000)
{
bool isPerfect = IsPerfectNumber(count);
if (isPerfect && (factorTotal >1))
{
Console.WriteLine("Is Perfect: {0}", factorTotal);
}
factorTotal = 1;
count++;
}
} // end main
static bool IsPerfectNumber(int n)
{
int temp;
int counter = 2;
bool IsPerfect = false;
while (counter <= (n - 1))
{
temp = n % counter;
if (temp == 0) // if true than factor found
{
factorTotal = factorTotal + counter;
}
counter++;
}
if ((factorTotal) == n)
IsPerfect = true;
else
IsPerfect = false;
return IsPerfect;
}
}//end class
under the Main method of you console application copy and paste below code.
I explained few things at the end of the code...
=====================================================================
{
Console.WriteLine("perfect numbers/n");
Console.Write("Enter upper limit: ");
int iUpperLimit = int.Parse(Console.ReadLine());
string sNumbers = "";
List<int> lstFactor = new List<int>();
for(int i = 1;i<=iUpperLimit;i++)
{
for(int k = 1;k<i;k++)
{
if (i % k == 0)
{
lstFactor.Add(k); //this collect all factors
}
if (k == i-1)
{
if (lstFactor.Sum() == i) //explain1
{
sNumbers += " " + i;
lstFactor.Clear(); //explain2
break;
}
else
{
lstFactor.Clear(); //explain2
}
}
}
}
Console.WriteLine("\nperfect numbers are: " + sNumbers);
Console.ReadKey();
}
}
=======================================================================
note that i is a number that we test and k is its factors.
explain1 => we add all factors collected and check if they are equal to i (we simply check if i is perfect number)
explain2 => we have to clear our list before we can check if the next number i is a perfect number or not so that factors of the previous number does not interfere with factors of the current number.
int start=1;
int end=50;
for(int a=end ; a > start ;a--)
{
int b=1;
int c=0;
bool x=false;
for(int i=1 ; i < a ;i++)
{
b=a/i;
if(b*i==a)
{
c+=i;
}
if(c==a & i==a/2)
{
x=true;
}
}
if(x==true)
Console.Write("{0} is : {1}",a,x);
}

Most efficient way to randomly "sort" (Shuffle) a list of integers in C#

I need to randomly 'sort' a list of integers (0-1999) in the most efficient way possible. Any ideas?
Currently, I am doing something like this:
bool[] bIndexSet = new bool[iItemCount];
for (int iCurIndex = 0; iCurIndex < iItemCount; iCurIndex++)
{
int iSwapIndex = random.Next(iItemCount);
if (!bIndexSet[iSwapIndex] && iSwapIndex != iCurIndex)
{
int iTemp = values[iSwapIndex];
values[iSwapIndex] = values[iCurIndex];
values[iCurIndex] = values[iSwapIndex];
bIndexSet[iCurIndex] = true;
bIndexSet[iSwapIndex] = true;
}
}
A good linear-time shuffling algorithm is the Fisher-Yates shuffle.
One problem you'll find with your proposed algorithm is that as you near the end of the shuffle, your loop will spend a lot of time looking for randomly chosen elements that have not yet been swapped. This may take an indeterminate amount of time once it gets to the last element to swap.
Also, it looks like your algorithm will never terminate if there are an odd number of elements to sort.
static Random random = new Random();
public static IEnumerable<T> RandomPermutation<T>(IEnumerable<T> sequence)
{
T[] retArray = sequence.ToArray();
for (int i = 0; i < retArray.Length - 1; i += 1)
{
int swapIndex = random.Next(i, retArray.Length);
if (swapIndex != i) {
T temp = retArray[i];
retArray[i] = retArray[swapIndex];
retArray[swapIndex] = temp;
}
}
return retArray;
}
modified to handle lists or other objects implementing IEnumerable
We can make an extension method out of this to get a Random enumerator for any IList collection
class Program
{
static void Main(string[] args)
{
IList<int> l = new List<int>();
l.Add(7);
l.Add(11);
l.Add(13);
l.Add(17);
foreach (var i in l.AsRandom())
Console.WriteLine(i);
Console.ReadLine();
}
}
public static class MyExtensions
{
public static IEnumerable<T> AsRandom<T>(this IList<T> list)
{
int[] indexes = Enumerable.Range(0, list.Count).ToArray();
Random generator = new Random();
for (int i = 0; i < list.Count; ++i )
{
int position = generator.Next(i, list.Count);
yield return list[indexes[position]];
indexes[position] = indexes[i];
}
}
}
This uses a reverse Fisher-Yates shuffle on the indexes of the list we want to randomly enumerate through. Its a bit of a size hog (allocating 4*list.Count bytes), but runs in O(n).
As Greg pointed out the Fisher-Yates shuffle would be the best approach. Here is an implementation of the algorithm from Wikipedia:
public static void shuffle (int[] array)
{
Random rng = new Random(); // i.e., java.util.Random.
int n = array.length; // The number of items left to shuffle (loop invariant).
while (n > 1)
{
int k = rng.nextInt(n); // 0 <= k < n.
n--; // n is now the last pertinent index;
int temp = array[n]; // swap array[n] with array[k] (does nothing if k == n).
array[n] = array[k];
array[k] = temp;
}
}
The implementation above relies on
Random.nextInt(int) providing
sufficiently random and unbiased
results
I am not sure of the efficiency factor, but I have used something similar to the following, if you aren't opposed to using an ArrayList:
private ArrayList ShuffleArrayList(ArrayList source)
{
ArrayList sortedList = new ArrayList();
Random generator = new Random();
while (source.Count > 0)
{
int position = generator.Next(source.Count);
sortedList.Add(source[position]);
source.RemoveAt(position);
}
return sortedList;
}
Using this, you do not have to worry about the intermediate swapping.
To improve your efficiency you can keep a set of values/indices that have been swapped rather than a boolean for indicating they were swapped. Pick your randomized swap index from the remaining pool. When the pool is 0, or when you made it through the initial list then you are done. You don't have the potential to try to select a random swap index value.
When you do a swap, just remove them from the pool.
For the size of data you are looking at it is no big deal.
itemList.OrderBy(x=>Guid.NewGuid()).Take(amount).ToList()
ICR's answer is very fast, but the resulting arrays aren't distributed normally. If you want a normal distribution, here's the code:
public static IEnumerable<T> RandomPermutation<T>(this IEnumerable<T> sequence, int start,int end)
{
T[] array = sequence as T[] ?? sequence.ToArray();
var result = new T[array.Length];
for (int i = 0; i < start; i++)
{
result[i] = array[i];
}
for (int i = end; i < array.Length; i++)
{
result[i] = array[i];
}
var sortArray=new List<KeyValuePair<double,T>>(array.Length-start-(array.Length-end));
lock (random)
{
for (int i = start; i < end; i++)
{
sortArray.Add(new KeyValuePair<double, T>(random.NextDouble(), array[i]));
}
}
sortArray.Sort((i,j)=>i.Key.CompareTo(j.Key));
for (int i = start; i < end; i++)
{
result[i] = sortArray[i - start].Value;
}
return result;
}
Note that in my tests, this algorithm was 6 times slower than the one ICR provided, however this is the only way I could come up with to get a normal result distribution
Wouldn't something like this work?
var list = new[]{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
var random = new Random();
list.Sort((a,b)=>random.Next(-1,1));
what about :
System.Array.Sort(arrayinstance, RandomizerMethod);
...
//any evoluated random class could do it !
private static readonly System.Random Randomizer = new System.Random();
private static int RandomizerMethod<T>(T x, T y)
where T : IComparable<T>
{
if (x.CompareTo(y) == 0)
return 0;
return Randomizer.Next().CompareTo(Randomizer.Next());
}
voila!
Here is what I used.
This is surely not the fastest one, but it is probably good enough for most cases and most importantly, it is very simple.
IEnumerable<ListItem> list = ...;
Random random = new Random(); // important to not initialize a new random in the OrderBy() function
return list.OrderBy(i => random.Next());
You can use a NuGet package called ListShuffle (source code) to shuffle a list in a thread-safe way using the Fisher-Yates algorithm, with optional cryptographically-strong random.
var myList = new List<string>();
myList.Add("Item A");
myList.Add("Item B");
myList.Add("Item C");
myList.Shuffle();
or (less performant but cryptographically-strong)
var myList = new List<string>();
myList.Add("Item A");
myList.Add("Item B");
myList.Add("Item C");
myList.CryptoStrongShuffle();
I made a method using a temporary Hashtable, allowing the Hashtable's natural key sort to randomize. Simply add, read and discard.
int min = 1;
int max = 100;
Random random;
Hashtable hash = new Hashtable();
for (int x = min; x <= max; x++)
{
random = new Random(DateTime.Now.Millisecond + x);
hash.Add(random.Next(Int32.MinValue, Int32.MaxValue), x);
}
foreach (int key in hash.Keys)
{
HttpContext.Current.Response.Write("<br/>" + hash[key] + "::" + key);
}
hash.Clear(); // cleanup

Categories

Resources