-3

How can I generate random number between 0 and 2 excluding 1? The function I am currently using is:

public static int DecRandomNumber(int min, int max)
{
      lock (syncLock)
      {
           // synchronize
           int val = Convert.ToInt32(random.Next(0, 3));
           return(val == 1 ? 2 : 0);
      }
}

However this is not at all generalized as I am not using min and max and happen to know that min will always be 1 and max be 3. What's the best way to achieve this? Thanks.

Jishan
  • 1,654
  • 4
  • 28
  • 62

3 Answers3

2

There are a couple ways. One could be to generate a random number from 0 to 1 and multiply by two:

int val = random.Next(0, 2); // gives 0 or 1
return val * 2; // returns 0 * 2 = 0 or 1 * 2 = 2 with equal probability

Or you could generate a double and use a ternary, to control the probability:

return random.NextDouble() < 0.5 ? 0 : 2;
Andrew
  • 4,953
  • 15
  • 40
  • 58
1

EDIT: Misunderstood your question, trying again. This solution uses your min & max values:

return random.Next() % 2 == 0 ? min : max;
Troels Larsen
  • 4,462
  • 2
  • 34
  • 54
  • This is probably the simplest way of doing it. – But I'm Not A Wrapper Class Jul 07 '14 at 20:32
  • 1
    @CyberneticTwerkGuruOrc In general it's better to avoid the modulo operator to obtain a range of outcomes because of [modulo bias](http://stackoverflow.com/questions/10984974/why-do-people-say-there-is-modulo-bias-when-using-a-random-number-generator). – pjs Jul 07 '14 at 22:17
  • @pjs: While that is true for low values of random generation, I think it is quite neglible using Next() without parameters will only have an extremely tiny bias (which is also mentioned in your link). If that bias is too large, OP shouldn't even use Random as it is slightly biased itself. – Troels Larsen Jul 08 '14 at 05:52
  • @CyberneticTwerkGuruOrc Whether bias will manifest or not for a particular case, it's a bad choice to use as your go-to tool. – pjs Jul 08 '14 at 13:27
  • 1
    @pjs: Modulo is not always bad. In the case of Next(), there are 2147483647 possible values. Of those values, 1073741824 are even, and 1073741823 are odd (Due to starting with 0 and ending with Int.MaxValue - 1). This means there is a slight bias, yes. But it is 0,50000000023% vs 0,49999999977%. If you cannot live with this bias, I would argue that you are doing something very specialized that would also require a better random number generator than Random. Since OP never mentioned any special requirements in this regard, I don't see your point. – Troels Larsen Jul 08 '14 at 14:02
  • @pjs I didn't know about modulo bias. Thanks. Although, I don't think it's that big of a bias with just generating between two numbers this way. – But I'm Not A Wrapper Class Jul 08 '14 at 15:34
  • @TroelsLarsen You're right, it's not always bad. However, it sometimes is. When there are two or more ways to do something, and one of them is known to screw up sometimes, the ways that don't screw up are better tools to have in your toolbox. It doesn't matter that the bias is negligible in this particular case, if you use modulo as your range tool for uniform random numbers you will get burned someday. – pjs Jul 08 '14 at 15:51
  • @pjs: Understanding WHY something CAN be bad is more important than absolute statements. In your linked example, it was bad because the distribution was 3/3/4. Using rng.Next(0, Int32.MaxValue-1) % 2 == 0 will have no bias other than the one imposed by the the RNG itself. Modulo is NOT introducing any bias at all when used correctly. – Troels Larsen Jul 08 '14 at 17:17
  • @TroelsLarsen Used "correctly" is the wrong phraseology, it implies there is always a correct way if only you would use it. Used "when appropriate" would be better. The problem is that most people who are using it have no idea when it is or is not appropriate, and other techniques exist which don't suffer from that problem. – pjs Jul 08 '14 at 18:09
0

This is a funny question in general, but for anyone needing more functionality, I'd propose the following pseudo code for thought:

public class RandomBrokenSequence
{
   private List<int> items;
   private Random random;

   public RandomBrokenSequence()
   {
     items = new List<int>();
     random = new Random();
   }

   public int Next()
   {
     return items[random.Next(0,items.Count)];
   }

   public void Add(int item){ /*You get the idea*/ }
   public void RemoveIfFound(int item){ /*You get the idea*/ }

   public void AddRange(int start, int end){ /*You get the idea*/ }
   public void RemoveRange(int start, int end){ /*You get the idea*/ }
}

Then you could add range 0-100, and then say remove 7 and 15-25, or whatever your heart's content. Essentially we just created a mapping. This would be a little bit overboard if you were only needing two random values, but interestingly could be used in a scenario where your random set was changing.

Greg
  • 2,410
  • 21
  • 26