Переполнение стека в генераторе случайных чисел - PullRequest
0 голосов
/ 31 января 2012

По какой-то причине этот код работает нормально, когда я не использую начальное число в классе Random, но если я пытаюсь использовать DateTime.Now для получения более случайного числа, я получаю исключение StackOverflowException!Мой класс действительно прост.Может кто-нибудь сказать мне, что я здесь делаю не так?См. 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";
    }
}

Ответы [ 5 ]

11 голосов
/ 31 января 2012

Вы звоните DateTime.Now.ToString(), что не дает вам одну из строк, которые вы проверяете ... поэтому вы повторяете, вызывая ее с той же строкой ... которая все еще не является одной из строк, которые вы ищете.

Вам не нужно использовать Random, чтобы продемонстрировать проблему. Это будет сделано очень легко:

Uniqueness(""); // Tick, tick, tick... stack overflow

Что вы ожидали , что это будет делать? Совершенно неясно, что ваш код означал для , но я предлагаю вам полностью отказаться от метода Uniqueness. На самом деле, я предлагаю вам избавиться от всего класса и использовать вместо него Path.GetTempFileName.

2 голосов
/ 31 января 2012

Короче:

Стоит сказать

    switch (randomObj.GetType().ToString())

вместо

    switch (randomObj.ToString())

Но даже тогда это не очень умно.

1 голос
/ 31 января 2012

С чего начать. 1. Уже есть строка сравнения. Используй это. Это было отлажено. 2. Ваша уникальная функция нелогична. Первые два элемента case возвращают букву 'S', возможно, приведенную к int. Вы пренебрегли разрывом в первом случае.

Ваш третий случай выглядит так: if (x == "System.Int32") return int.Parse ("System.Int32"); Это может вернуть 32 или ошибку синтаксического анализа.

Ваш четвертый случай выглядит так: if (x == "System.Boolean") return strcmp ("System.Boolean", "True"); Ваш случай по умолчанию называется recursevly (sp), вызывая переполнение стека (см. Комментарий выше)

Чтобы исправить эту программу, я рекомендую вам прочитать хотя бы одну хорошую книгу по C #, затем переосмыслить свою программу и написать. Возможно, Javascript подойдет лучше.

1 голос
/ 31 января 2012

Конструктор без параметров Random уже использует текущее время в качестве начального значения.В нем используются временные отметки, используемые внутри для представления DateTime.

. Проблема с этим подходом, однако, заключается в том, что тактовые часы работают очень медленно по сравнению с тактовой частотой процессора.Если вы создаете новый экземпляр Random каждый раз, когда вам нужно случайное значение, возможно, часы не тикают между двумя вызовами, создавая одно и то же случайное число дважды.

Вы можете просто решитьЭта проблема создается одним экземпляром Random.

public class TempUtil { 
    private static readonly Random random = new Random();

    public string MakeUniqueFileName()
    {
        return @"C:\windows\temp\" + random.NextDouble() + ".tmp";     
    } 
}

. Это приведет к созданию очень хороших случайных чисел.


Кстати

System.IO.Path.GetTempFileName()

автоматически создает пустой временный файл с уникальным именем и возвращает полный путь к этому файлу.

1 голос
/ 31 января 2012

Вы передаете экземпляр DateTime в ваш метод Uniqueness.

Это проваливается и вызывает себя с ToString - для экземпляра DateTime это будет отформатированная строка DateTime(например, "21/01/2011 13:13:01").

Поскольку эта строка не соответствует ни одному из ваших вариантов переключения (снова), метод вызывает себя снова, но результат вызова ToString для строки - та же самая строка.

Вы вызвали бесконечный стек вызовов, который приводит к StackOverflowException.

Нет необходимости вызывать Uniquness - при создании экземпляра Random он будет основан натекущее время в любом случае.

Предлагаю прочитать Случайные числа с сайта C # в глубине.

...