Stack Overflow in random number generator - c#

For some reason, this code works fine when I don't use a seed in the Random class, but if I try to use DateTime.Now to get a more random number, I get a StackOverflowException! My class is really simple. Could someone tell me what I'm doing wrong here? See MakeUniqueFileName.
public class TempUtil
{
private int strcmp(string s1, string s2)
{
try
{
for (int i = 0; i < s1.Length; i++)
if (s1[i] != s2[i]) return 0;
return 1;
}
catch (IndexOutOfRangeException)
{
return 0;
}
}
private int Uniqueness(object randomObj)
{
switch (randomObj.ToString())
{
case "System.Object":
case "System.String":
return randomObj.ToString()[0];
case "System.Int32":
return int.Parse(randomObj.ToString());
case "System.Boolean":
return strcmp(randomObj.ToString(), "True");
default:
return Uniqueness(randomObj.ToString());
}
}
public string MakeUniqueFileName()
{
return "C:\\windows\\temp\\" + new Random(Uniqueness(DateTime.Now)).NextDouble() + ".tmp";
}
}

You're calling DateTime.Now.ToString(), which doesn't give you one of the strings you're checking for... so you're recursing, calling it with the same string... which still isn't one of the strings you're looking for.
You don't need to use Random to demonstrate the problem. This will do it very easily:
Uniqueness(""); // Tick, tick, tick... stack overflow
What did you expect it to be doing? It's entirely unclear what your code is meant to be doing, but I suggest you ditch the Uniqueness method completely. In fact, I suggest you get rid of the whole class, and use Path.GetTempFileName instead.

In short:
It should say
switch (randomObj.GetType().ToString())
instead of
switch (randomObj.ToString())
But even then this isn't very clever.

You are passing a DateTime instance to your Uniqueness method.
This falls through and calls itself with ToString - on a DateTime instance this will be a formatted DateTime string (such as "21/01/2011 13:13:01").
Since this string doesn't match any of your switch cases (again), the method calls itself again, but the result of calling ToString on a string is the same string.
You have caused an infinite call stack that results in the StackOverflowException.
There is no need to call Uniquness - when creating a Random instance, it will be based on the current time anyways.
I suggest reading Random numbers from the C# in depth website.

The parameter-less constructor of Random already uses the current time as seed value. It uses the time ticks, used internally to represent a DateTime.
A problem with this approach, however, is that the time clock ticks very slowly compared to the CPU clock frequency. If you create a new instance of Random each time you need a random value, it may be, that the clock did not tick between two calls, thus generating the same random number twice.
You can simply solve this problem by creating a single instance of Random.
public class TempUtil {
private static readonly Random random = new Random();
public string MakeUniqueFileName()
{
return #"C:\windows\temp\" + random.NextDouble() + ".tmp";
}
}
This will generate very good random numbers.
By the way
System.IO.Path.GetTempFileName()
automatically creates an empty temporary file with a unique name and returns the full path of that file.

Where to begin.
1. There is already a string compare. Use it. It has been debugged.
2. Your Unique function is illogical. The first two case items return a 'S' perhaps cast to an int. You have neglected the break on the first case.
Your third case is like this:
if (x =="System.Int32") return int.Parse("System.Int32");
That may return 32, or a parse error.
Your fourth case is like this:
if (x == "System.Boolean") return strcmp("System.Boolean", "True");
Your default case is called recursevly (sp) causing the stack overflow (see comment above)
In order fix this program, I recommend you read at least one good book on C#, then rethink your program, then write it. Perhaps Javascript would be a better fit.

Related

Random String generation - avoiding duplicates

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.

Function does not return negative value

I am doing a small project on 4x4 tic-tac-toe game. I am using Alpha Beta Search for finding the next best move. In the alpha beta search, I am using a cutoff evaluation function that is being called in "utility" function of the following algorithm
I implemented everything successfully, but the problem is the utility function doesn't return a negative value and I really don't know why! Following is the function
private static int utility(GameTreeNode gtn, bool isMin = false)
{
int nodeValue = 0;
switch (gtn.NodeBoard.getBoardStatus())
{
case Status.Success:
nodeValue = 50;
if (isMin) nodeValue = -50; /// here
break;
case Status.Incomplete:
if (isMin)
nodeValue = gtn.evaluate(State.X);
else
nodeValue = gtn.evaluate(State.O);
break;
}
// case Status.Draw:
return nodeValue;
}
isMin is set to true, when it is called from MinValue function
isMin is the move of O and the AI's move is X. If O wins the utility is supposed to return -50. But it returns only 0. I debugged the program and it actually assigns -50 to nodeValue (nodeValue changes in the debugger to -50), but when I receive in the Min or Max function, it is zero.
Note: All the int used in the entire project is signed int. No unsigned keyword is used, if you are thinking the function-caller is unsigned
The full code of alpha-beta search is here: http://pastie.org/8538015
Please friends, help as soon as possible.
Since you're using an optional parameter in your method signature, I'd caution you to pay attention to what your code is actually running when entering your function. You said you debugged it and the value gets assigned, but I don't have enough context to know if it only happens in one of many cases or not. Anyway, just be careful with those!
I would rewrite your function like this:
private static int utility(GameTreeNode gtn, bool isMin)
{
switch (gtn.NodeBoard.getBoardStatus())
{
case Status.Success:
return isMin
? -50
: 50;
case Status.Incomplete:
return isMin
? gtn.evaluate(State.X)
: gtn.evaluate(State.O);
default:
throw new NotImplementedException("The status is not implemented.");
}
}
A few improvements I see with this approach:
You don't need to store a value and return it at the end. In your case, you're always storing 50 into nodeValue when you take the Status.Success path, and then sometimes assigning -50 to it. Unless you're adamant about one return in your function, I think this approach is more clear. Might just be my opinion though.
There's a default in the switch statement so that you'll explicitly throw an exception in the case where you have a status that isn't implemented.
There is no optional parameter to your function. I don't see the benefit of making this parameter optional. In my opinion, it only looks like it's adding room to make things harder to debug.
EDIT:
Based on the code at:http://pastie.org/8538015#33,43
It looks like the only time you can ever get utility to return a negative value is when if (gtn.Nodes.Count == 0) return utility(gtn, true); is hit in the private static int MinValue(GameTreeNode gtn, int alpha, int beta) function. Otherwise, unless there's more code which you haven't posted, no other call to the utility function will hit the logical path your going for. You've mentioned when you step into there, you can see the value for nodeValue get properly assigned.
I'm suggesting you change:
// if Terminal-test(state) then return utitly(state)
if (gtn.Nodes.Count == 0) return utility(gtn, true);
gtn.Value = Globals.MAXINT;
To
// if Terminal-test(state) then return utitly(state)
if (gtn.Nodes.Count == 0)
{
int retVal = utility(gtn, true);
return retVal;
}
gtn.Value = Globals.MAXINT;
At least temporarily, and then put a breakpoint on return retVal. If your utility function is actually setting the value you expect like you say, there's no way that it could magically go away when it returns it to the MinValue function. I have a feeling something fishy is happening and the code isn't actually executing the path you expect.

A problem with using System.Collections.Specialized.BitVector32: a bug?

I'm trying to do a short simulation where i needed a small bit array, and I chose System.Collections.Specialized.BitVector32.
I'm running it inside a single-threaded object, in a single-threaded loop about 1,000,000 times, each time for indexes {0,1,2}.
Here is the code:
private System.Collections.Specialized.BitVector32 currentCalc
= new System.Collections.Specialized.BitVector32();
private void storeInCurrent(int idx, bool val)
{
currentCalc[idx] = val;
if (currentCalc[idx] != val)
{
throw new Exception("Inconceivable!");
}
}
To my understanding, the exception should not be thrown, but sometimes it does! An exception is not thrown every time, but in a fair percent - a CONSTANT 1/6 of the time! (which is even stranger)
What am I doing wrong?
Look at MSDN; the indexer takes the mask, not the index. So that is:
int mask = 1 << idx;
then use currentCalc[mask]
This is odd though; if you are happy enough to use masks - why would one be using BitVector32, rather than just an int. I also assumed the indexer would take the index. VERY odd design decision.

What string concatenation method to use for N number of iterations?

If I want to concatenate a string N number of times, which method should i prefer?
Take this code as an example:
public static string Repeat(this string instance, int times)
{
var result = string.Empty;
for (int i = 0; i < times; i++)
result += instance;
return result;
}
This method may be invoked with "times" set to 5, or 5000. What method should I prefer to use?
string.Join? Stringbuilder? Just standard string.Concat?
A similar function is going to be implemented in a commercial library so I really need the "optimal" way to do this.
public static string Repeat(this string instance, int times)
{
if (times == 1 || string.IsNullOrEmpty(instance)) return instance;
if (times == 0) return "";
if (times < 0) throw new ArgumentOutOfRangeException("times");
StringBuilder sb = new StringBuilder(instance.Length * times);
for (int i = 0; i < times; i++)
sb.Append(instance);
return sb.ToString();
}
Stringbuilder ofcourse. It is meant for fast string join operations, because it won't create new object each time you want to join a string.
For details see here.
StringBuilder.
"result += result;"
creates a new string each and every time you do the assignment, and assign that new string to your variable, since strings are immutable.
Go with StringBuilder, definitely.
Never make an assumption that one method is faster than another -- you must alway measure the performance of both and then decide.
Surprisingly, for smaller numbers of iterations, just a standard string concatenation (result += string) is often faster than using a string builder.
If you know that the number of iterations will always be the same (e.g. it will always be 50 iterations), then I would suggest that you make some performance measurements using different methods.
If you really want to get clever, make performance measurements against number of iterations and you can find the 'crossover point' where one method is faster than another and hard-code that threshold into the method:
if(iterations < 30)
{
CopyWithConcatenation();
}
else
{
CopyWithStringBuilder();
}
The exact performance crossover point will depend on the specific detail of your code and you'll never be able to find out what they are without making performance measurements.
To complicate things a little more, StringBuilder has 'neater' memory management that string concatenation (which creates more temporary instances) so this might also have an impact on overall performance outside of your string loop (like the next time the Garbage Collector runs).
Let us know how you got on.

Recursive woes - reducing an input string

I'm working on a portion of code that is essentially trying to reduce a list of strings down to a single string recursively.
I have an internal database built up of matching string arrays of varying length (say array lengths of 2-4).
An example input string array would be:
{"The", "dog", "ran", "away"}
And for further example, my database could be made up of string arrays in this manner:
(length 2) {{"The", "dog"},{"dog", "ran"}, {"ran", "away"}}
(length 3) {{"The", "dog", "ran"}.... and so on
So, what I am attempting to do is recursively reduce my input string array down to a single token. So ideally it would parse something like this:
1) {"The", "dog", "ran", "away"}
Say that (seq1) = {"The", "dog"} and (seq2) = {"ran", "away"}
2) { (seq1), "ran", "away"}
3) { (seq1), (seq2)}
In my sequence database I know that, for instance, seq3 = {(seq1), (seq2)}
4) { (seq3) }
So, when it is down to a single token, I'm happy and the function would end.
Here is an outline of my current program logic:
public void Tokenize(Arraylist<T> string_array, int current_size)
{
// retrieve all known sequences of length [current_size] (from global list array)
loc_sequences_by_length = sequences_by_length[current_size-min_size]; // sequences of length 2 are stored in position 0 and so on
// escape cases
if (string_array.Count == 1)
{
// finished successfully
return;
}
else if (string_array.Count < current_size)
{
// checking sequences of greater length than input string, bail
return;
}
else
{
// split input string into chunks of size [current_size] and compare to local database
// of known sequences
// (splitting code works fine)
foreach (comparison)
{
if (match_found)
{
// update input string and recall function to find other matches
string_array[found_array_position] = new_sequence;
string_array.Removerange[found_array_position+1, new_sequence.Length-1];
Tokenize(string_array, current_size)
}
}
}
// ran through unsuccessfully, increment length and try again for new sequence group
current_size++;
if (current_size > MAX_SIZE)
return;
else
Tokenize(string_array, current_size);
}
I thought it was straightforward enough, but have been getting some strange results.
Generally it appears to work, but upon further review of my output data I'm seeing some issues. Mainly, it appears to work up to a certain point...and at that point my 'curr_size' counter resets to the minimum value.
So it is called with a size of 2, then 3, then 4, then resets to 2.
My assumption was that it would run up to my predetermined max size, and then bail completely.
I tried to simplify my code as much as possible, so there are probably some simple syntax errors in transcribing. If there is any other detail that may help an eagle-eyed SO user, please let me know and I'll edit.
Thanks in advance
One bug is:
string_array[found_array_position] = new_sequence;
I don't know where this is defined, and as far as I can tell if it was defined, it is never changed.
In your if statement, when if match_found ever set to true?
Also, it appears you have an extra close brace here, but you may want the last block of code to be outside of the function:
}
}
}
It would help if you cleaned up the code, to make it easier to read. Once we get past the syntactic errors it will be easier to see what is going on, I think.
Not sure what all the issues are, but the first thing I'd do is have your "catch-all" exit block right at the beginning of your method.
public void Tokenize(Arraylist<T> string_array, int current_size)
{
if (current_size > MAX_SIZE)
return;
// Guts go here
Tokenize(string_array, ++current_size);
}
A couple things:
Your tokens are not clearly separated from your input string values. This makes it more difficult to handle, and to see what's going on.
It looks like you're writing pseudo-code:
loc_sequences_by_length is not used
found_array_position is not defined
Arraylist should be ArrayList.
etc.
Overall I agree with James' statement:
It would help if you cleaned up the
code, to make it easier to read.
-Doug

Categories

Resources