I'm using the current clock ticks as a seed for random number generation. The random number is used in a pseudo GUID and a check in my database will make sure it doesn't already exist before returning. On average, this method will be called around 10k times in succession during the life of the process.
My concern is that an identical number might be generated back to back resulting in multiple unnecessary recursive calls to my database checking for the same ID. I'd like to avoid this if possible. What is the best way to test this scenario?
If it matters, application is .NET 4 and database is SQL Server 2008.
private static string GenerateUniqueDelId()
{
// Generate a random integer using the current number of clock ticks as seed.
// Then prefix number with "DEL" and date, finally padding random integer with leading zeros for a fixed 25-character total length.
int seed = (int)DateTime.Now.Ticks;
Random number = new Random(seed);
string id = string.Format("DEL{0}{1}", DateTime.Today.ToString("yyyyMMdd"), number.Next().ToString("D14"));
// Lookup record with generated ID in Sesame. If one exists, call method recursively.
string query = "SELECT * FROM Lead WHERE Esm_Id = #Esm_Id";
SqlParameter[] parameters = { new SqlParameter("#Esm_Id", id) };
if (DataManager.GetRow(query, parameters, DelConnection.Sesame) != null) return GenerateUniqueDelId();
// Otherwise, return ID.
return id;
} //// End GenerateUniqueDelId()
You are right in your concern: You should move the creation of your Random instance out of your method body - otherwise you will re-seed with the same value many times which results in the same number sequence.
Also you are kinda re-inventing the wheel: the default constructor of the Random class already uses the current clock time as default seed.
The question is why don't you avoid all of this and just use an auto-generated Guid on the database side?
Quoting Jon Skeet
When you see the word "random" in a question title on Stack Overflow you can almost guarantee it will be the same fundamental problem as countless similar questions. This article takes a look at why randomness causes so many problems, and how to address them.
Check his article about random number generators
http://csharpindepth.com/Articles/Chapter12/Random.aspx
basically his solution looks like:
using System;
using System.Threading;
public static class RandomProvider
{
private static int seed = Environment.TickCount;
private static ThreadLocal<Random> randomWrapper = new ThreadLocal<Random>(() =>
new Random(Interlocked.Increment(ref seed))
);
public static Random GetThreadRandom()
{
return randomWrapper.Value;
}
}
Related
This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 7 years ago.
This is really weird, and I cannot see why this is happening. In the foreach cycle, I am iterating through a class A collection, and for each class, I call the Count() method, where r1 and r2 numbers are generated from range [-1,1]. The problem is that Random.Next returns the same "random" numbers for each instance. When the results for the first instance are 0 and -1, the same ones will be returned from following instances. Please, could you tell me why this is happening? Also, I cannot get different results in each class A instance. This is the code:
class a
{
Random rnd = new Random();
private void Count()
{
int r1 = rnd.Next(-1, 1);
int r2 = rnd.Next(-1, 1);
}
}
class b
{
List<a> listofA=new list<a>();
foreach (a ACLASS in listofA)
{
ACLASS.Count();
}
}
The problem is that you are creating instances of the Random class too close in time.
When you create a Random object, it's seeded with a value from the system clock. If you create Random instances too close in time, they will all be seeded with the same random sequence.
Create a single Random object and pass its reference to the constructor when you create instances of the "a" class, instead of creating one Random object for each "a" instance.
Use a single, static Random number generator for all instances of the class.
class a
{
private static Random rnd;
static a() {
rnd = new Random();
}
private void Count()
{
int r1 = rnd.Next(-1, 2);
int r2 = rnd.Next(-1, 2);
}
}
Note the change to give you numbers in the range -1,1 rather than -1,0
You're creating new instances of Random very close together (your loop is very tight) so each instance is effectively using the same seed value.
A better approach would be to create one instance and pass that to your Count method.
You probably know this next bit, but I'll include it here for completeness:
The MSDN has the details on this, but basically your problem is the Random.Next method you're using generates:
A 32-bit signed integer greater than or equal to minValue and less than maxValue; that is, the range of return values includes minValue but not maxValue. If minValue equals maxValue, minValue is returned.
because of this your calls will return -1 or 0.
You include a random instance for each A instance. It sounds like they're all getting the same default seed value. You probably want to make a static random for all A instances and use it repeatedly, or alternatively provide a seed value to the Random() instance in the A constructor.
I am using the below code to generate random keys like the following TX8L1I
public string GetNewId()
{
string result = string.Empty;
Random rnd = new Random();
short codeLength = 5;
string chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
StringBuilder builder = new StringBuilder(codeLength);
for (int i = 0; i < codeLength; ++i)
builder.Append(chars[rnd.Next(chars.Length)]);
result = string.Format("{0}{1}", "T", builder.ToString());
return result;
}
Every-time a key is generated a correspondent record is created on the database using the generated result as primary key. Off course this is not safe since a primary key violation might occur.
What's the correct approach to this? Should I load all existing keys and verify against tha t list if the key already exist and if yes generate another one?
Or maybe a more efficient way would be to move this logic into the database side? But even on the database side I still need to check that the random key generated does not exist on the current table.
Any ideas?
Thanks
Move the decision to the database. Add a primary key of type uniqueidentifier. Then its a simple "fire and forget" algorithm.. the database decides what the key is.
I think you should use Random instance outside of your method.
Since Random object is seeded from the system clock, which means that if you call your method several times very quickly, it will use the same seed each time, which means that you'll get the same string at the end.
well my decision to use the random is that I don't want the users to be able to know how the keys are generated (format), since the website is public and I don't want users to be trying to access keys that.
You've merged two problems into one that are really separate:
Identify a row in a database.
Have an identifier that is passed to and from clients, that matches this, but is not predictable.
This is a specific case of a more general set of two problems:
Identify a row in a database.
Have an identifier that is passed to and from clients, that matches this.
In this case, when we don't care about guessing, then the easiest way to deal with it is to just use the same identifier. E.g. for the database row identified by the integer 42 we use the string "42" and the mapping is a trivial int.Parse() or int.TryParse() in one direction and a trivial .ToString() or implicit .ToString() in the other.
And that's therefore the pattern we use without even thinking about it; public IDs and database keys are the same (perhaps with some conversion).
But the best solution to your specific case where you want to prevent guessing is not to change the key, but to change mapping between the key and the public identifier.
First, use auto-incremented integers ("IDENTITY" in SQL Server, and various similar concepts in other databases).
Then, when you are sending the key to the client (i.e. using it in a form value or appending it to a URI) then map it as so:
private const string Seed = "this is my secret seed ¾Ÿˇʣכ ↼⊜┲◗ blah balh";
private static string GetProtectedID(int id)
{
using(var sha = System.Security.Cryptography.SHA1.Create())
{
return string.Join("", sha.ComputeHash(Encoding.UTF8.GetBytes(id.ToString() + Seed)).Select(b => b.ToString("X2"))) + id.ToString();
}
}
For example, with an ID of 123 this produces "989178D90470D8777F77C972AF46C4DED41EF0D9123".
Now map back to a the key with:
private static bool GetIDFromProtectedID(string str, out int id)
{
int chkID;
if(int.TryParse(str.Substring(40), out chkID))
{
using(var sha = System.Security.Cryptography.SHA1.Create())
{
if(string.Join("", sha.ComputeHash(Encoding.UTF8.GetBytes(chkID.ToString() + Seed)).Select(b => b.ToString("X2"))) == str.Substring(0, 40))
{
id = chkID;
return true;
}
}
}
id = 0;
return false;
}
For "989178D90470D8777F77C972AF46C4DED41EF0D9123" this returns true and sets the id argument to 123. For "989178D90470D8777F77C972AF46C4DED41EF0D9122" (because I tried to guess the ID to attack your site) it returns false and sets id to 0. (The correct ID for key 122 is "F8AD0F55CA1B9426D18F684C4857E0C4D43984BA122", which is not easy to guess from having seen that for 123).
If you want, you can remove some of the 40 characters of the output to produce smaller IDs. This makes it less secure (an attacker has fewer possible IDs to brute-force) but should still be reasonable for many uses.
Obviously, you should used a different value for Seed than here, so that someone reading this answer can't use it to predict your ID; change the seed, change the ID. Seed cannot be changed once set without altering every ID in the system. Sometimes that's a good thing (if identifiers are never meant to have long-term value anyway), but normally it's bad (you've just 404d every page in the site that used it).
I would move the logic to the database instead. Even though the database still have to check for the existence of the key, it's already within the database operation at that point, so there is no back-and-forth happening.
Also, if there's an index on this randomly generated key, a simple if exists will be quick enough to determine if the key has been used before or not.
You can do the following:
Generate your string as well as concatenate the following onto it
string newUniqueString = string.Format("{0}{1}", result, DateTime.Now.ToString("yyyyMMddHHmmssfffffff"));
This way, you will never have the same key ever again!
Or use
var StringGuid = Guid.NewGuid();
You've commited a typical sin with Random: one shouldn't create Random instance
each time they want to generate random value (otherwise one'll get badly skewed distribution with many repeats). Put Random away form function:
// Let Generator be thread safe
private static ThreadLocal<Random> s_Generator = new ThreadLocal<Random>(
() => new Random());
public static Random Generator {
get {
return s_Generator.Value;
}
}
// For repetition test. One can remove repetion test if
// number of generated ids << 15000
private HashSet<String> m_UsedIds = new HashSet<String>();
public string GetNewId() {
int codeLength = 5;
string chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
while (true) {
StringBuilder builder = new StringBuilder(codeLength);
for (int i = 0; i < codeLength; ++i)
builder.Append(chars[Generator.Next(chars.Length)]); // <- same generator for all calls
result = string.Format("{0}{1}", "T", builder.ToString());
// Test if random string in fact a repetition
if (m_UsedIds.Contains(result))
continue;
m_UsedIds.Add(result);
return result;
}
}
For codeLength = 5 there're Math.Pow(chars.Length, codeLength) possible
strings (Math.Pow(36, 5) == 60466176 = 6e7). According to birthday paradox
you can expect 1st repetition at about 2 * sqrt(possible strings) == 2 * sqrt(6e7) == 15000. If it's OK, you can skip the repetition test, otherwise HashSet<String> could
be a solution.
Is this class written by me is sufficient (I mean the way the pro's do it) to be included in a code/project? Or am I missing important things? I don't know how to use constructors etc so I did not use the same (I m just a beginner in C#) but please comment if so are required.
using System;
using System.Collections.Generic;
using System.Text;
namespace RandBit
{
/// <summary>
/// By: Author
/// Version 0.0.1
/// Pseudo-Random 16-Bit (Max) Generator.
/// </summary>
public class RandomBit
{
/// <param name="input">The Bit-size(int)</param>
/// <returns>Random Bit of Bit-size(string)</returns>
public static string Generate(int input)
{
int bitSize = 0;
Random choice = new Random();
if (input == 0 || input > 16)
{
bitSize = 0;
}
else if (input == 1)
{
bitSize = 1;
}
else
{
int randomChoice = choice.Next(0, (1 << input));
bitSize = randomChoice;
}
string binary = Convert.ToString(bitSize, 2);
binary = binary.PadLeft(input, '0');
return binary;
}
}
}
Thanks.
It appears that you are using Random incorrectly. I'd suggest starting with Jon Skeet's article on the subject. Relevant quote:
If you start off an instance of Random with the same initial state
(which can be provided via a seed) and make the same sequence of
method calls on it, you'll get the same results.
So what was wrong in our example code? We were using a new instance of
Random on each iteration of the loop. The parameterless constructor
for Random takes the current date and time as the seed - and you can
generally execute a fair amount of code before the internal timer
works out that the current date and time has changed. Therefore we're
using the same seed repeatedly - and getting the same results
repeatedly.
In other words, since you are creating a new instance of Random with each call, you are greatly increasing the chances that the return value won't be as "random" as you would expect.
It's also worth mentioning that there are potentially better PRNG classes already in the .Net BCL. Here's another way of writing similar code.
private static readonly RNGCryptoServiceProvider _crypto = new RNGCryptoServiceProvider();
public static long Generate(){
// use whatever size you want here; bigger has a better chance of
// being unique in a given scope
byte[] bytes = new byte[8];
// puts random bytes into the array
_crypto.GetBytes( bytes );
// do something (your choice) with the value...
return BitConverter.ToInt64( bytes, 0 );
}
You may only change one thing, since your class only contains a single static member, why don't make the class as static.
If I were the project team leader I would require that you drop summary/author/version comments. They are redundant (source control has that info), take a some time to write/modify and are ambiguous (in a file modified by 7 people who's the author?).
Here's a discussion on this topic, perhaps not the only one: https://softwareengineering.stackexchange.com/q/48562/30927
Move the variable "Choice" close to its usage i.e within the else loop.
Otherwise, You will be allocating un necessary memory to Random Object even if not used.
See here
To clarify, multiple students objects and all of them are getting the same value.
I know this question has been asked before, but I have had no luck with the other posts about his topic. I have a random number generator ranging from 1-3. I then us %2 to make a bool value true or false. Every time I run the program I either get all true or all false. Here is my code. I know that random is not really random. What can I do to get more random numbers.
Random random = new Random();
public Student()
{
int randomLevel=random.Next(1,3);
level = (randomLevel % 2 == 0);
}
public bool readingLevel()//this always returns one value for the entire program.
{
return level;
}
You are only assigning a random value to 'level' once during the constructor, so it will always have the initial value.
Try:
public bool readingLevel()
{
return (random.Next(1,3) % 2 == 0);
}
Edit:
Static Random random = new Random();
...
It looks like you're trying to get a random number!
Clippy
Well you can try something like this:
static Random random = new Random();
public Student()
{
lock (random)
{
int randomLevel=random.Next(1,3);
level = (randomLevel % 2 == 0);
}
}
public bool readingLevel()//this always returns one value for the entire program.
{
return level;
}
The problem with your snippet seems to be that you are instantiating a new Random class with each of your class instances.
This is not the way Random is supposed to be used, but instead a single Random class instance should be used for acquiring multiple random numbers.
The Rationale for this is that Random in .Net uses a pseudo random algorithm based on state (a seed) that changes every time you ask for a new random number. By instantiating multiple random classes in a relatively short time span, there is a high chance that all of them will be initiated with the same seed (Based on system time) and all will give the same random number.
It looks like your random generator is an instance variable of the Student. Since the generator uses the current time as the seed, if you create a bunch of students within a short time, they will all have each have a generator with the same seed and the same results. You could make the random generator a static variable or, better yet, use constructor injection and pass the level into the Student's constructor.
class Student
{
private static Random random = new Random();
public Student()
{
level = random.NextDouble() < 0.5;
}
public bool readingLevel()
{
return level;
}
}
or use constructor injection so your student class is deterministic.
class Student
{
private boolean level;
public Student(boolean readingLevel)
{
this.level = readingLevel;
}
public boolean readingLevel()
{
return level;
}
}
Create only one instance of Random and reuse it. Creating multiple instances of random in quick succession seeds to the same value and thus leads to the same sequence.
If your code in single threaded you can simply use a static property to hold the instance of Random.
The default seed value is derived from the system clock and has finite resolution. As a result, different Random objects that are created in close succession by a call to the default constructor will have identical default seed values and, therefore, will produce identical sets of random numbers. This problem can be avoided by using a single Random object to generate all random numbers. You can also work around it by modifying the seed value returned by the system clock and then explicitly providing this new seed value to the Random(Int32) constructor. For more information, see the Random(Int32) constructor.
http://msdn.microsoft.com/en-us/library/h343ddh9.aspx
public Student()
{
int randomLevel=random.Next(1,3);
level = (randomLevel % 2 == 0);
}
seems very much like a constructor for the Student class. In this constructor you are basically calculating a random number and storing it inside the level field. So if you use the same instance of Student throughout your entire program and call the readingLevel() method multiple times on this instance it will obviously return the same value -> the one that was done during the construction of this instance and that you stored in the level field.
So you might consider moving the random number generation logic into the readingLevel() method instead of simply returning the same value over and over again:
public class Student
{
private Random random = new Random();
public bool readingLevel()
{
int randomLevel = random.Next(1,3);
return (randomLevel % 2 == 0);
}
}
Now everytime you call this method on the same instance you should get a new calculation of a random number.
Some others have said this, but I think the point deserves underscoring with an example.
public class Student
{
Random random = new Random();
public Student()
{
int randomLevel=random.Next(1,3);
level = (randomLevel % 2 == 0);
}
public bool readingLevel()//this always returns one value for the entire program.
{
return level;
}
}
public class Program
{
public static void Main()
{
var students = new List<Student>();
for (int i = 0; i < 10; i++)
students.Add(new Student());
//Now you have 10 Students; each Student has its own random number generator
//The generators were created within microseconds of each other, so they most likely have THE SAME SEED
//Because they have the same seed, they will generate identical sequences of numbers
//Each student's reading level is calculated from the first call to .Next(1, 3) on its own RNG.
//The RNGs have the same seed, so each will return the same value for the first call to .Next(1, 3)
//Therefore, all students will have the same reading level!
}
}
You are using random to simulate a true/false situation, so you are trying to limit the result to either 1 or 2. Given that you are doing an odd/even test on the result you might be better off doing:
int randomLevel = random.Next();
level = (randomLevel % 2 == 0);
Also If you create all your students in quick succession there's a good chance that your current code will return the same value for subsequent calls.
Well.
Consider what is happening here. When your Student is constructued, you get some random number, and then set it to the member variable level.
Then, at some other point, you call a function, readingLevel, which returns this previously set value.
Then, you may ponder to yourself: Exactly when would this function give a different value? Well, it will only do so when level gets a different value. And when does that happen? Well, it only happens in the constructor, so, that means, it never happens again for the life of the object ....
Try the following. Move the selection of the random level to the readingLevel function.
Random random = new Random();
public Student()
{
}
public bool readingLevel()//this always returns one value for the entire program.
{
int randomLevel=random.Next(1,3);
level = (randomLevel % 2 == 0);
return level;
}
That is because you are using the random.Next() and the level evaluation within the constructor of your class, remember that the constructor is only executed when you create a new instance of your object, for having it executed several times create a different method where you call the random and the level evaluation, that way you'll get different values every time or use Something like this:
public bool Level()
{
int randomLevel=random.Next(1,3);
level = (randomLevel % 2 == 0);
return level;
}
Random random = new Random(DateTime.Now.Ticks);
This question already has answers here:
Random number generator only generating one random number
(15 answers)
Closed 7 years ago.
This is really weird, and I cannot see why this is happening. In the foreach cycle, I am iterating through a class A collection, and for each class, I call the Count() method, where r1 and r2 numbers are generated from range [-1,1]. The problem is that Random.Next returns the same "random" numbers for each instance. When the results for the first instance are 0 and -1, the same ones will be returned from following instances. Please, could you tell me why this is happening? Also, I cannot get different results in each class A instance. This is the code:
class a
{
Random rnd = new Random();
private void Count()
{
int r1 = rnd.Next(-1, 1);
int r2 = rnd.Next(-1, 1);
}
}
class b
{
List<a> listofA=new list<a>();
foreach (a ACLASS in listofA)
{
ACLASS.Count();
}
}
The problem is that you are creating instances of the Random class too close in time.
When you create a Random object, it's seeded with a value from the system clock. If you create Random instances too close in time, they will all be seeded with the same random sequence.
Create a single Random object and pass its reference to the constructor when you create instances of the "a" class, instead of creating one Random object for each "a" instance.
Use a single, static Random number generator for all instances of the class.
class a
{
private static Random rnd;
static a() {
rnd = new Random();
}
private void Count()
{
int r1 = rnd.Next(-1, 2);
int r2 = rnd.Next(-1, 2);
}
}
Note the change to give you numbers in the range -1,1 rather than -1,0
You're creating new instances of Random very close together (your loop is very tight) so each instance is effectively using the same seed value.
A better approach would be to create one instance and pass that to your Count method.
You probably know this next bit, but I'll include it here for completeness:
The MSDN has the details on this, but basically your problem is the Random.Next method you're using generates:
A 32-bit signed integer greater than or equal to minValue and less than maxValue; that is, the range of return values includes minValue but not maxValue. If minValue equals maxValue, minValue is returned.
because of this your calls will return -1 or 0.
You include a random instance for each A instance. It sounds like they're all getting the same default seed value. You probably want to make a static random for all A instances and use it repeatedly, or alternatively provide a seed value to the Random() instance in the A constructor.