Почему этот код с использованием случайных строк выводит "hello world"?
Заголовок: Объясните вывод программы с использованием метода randomString()
Я столкнулся с проблемой, связанной с выводом в Java. У меня есть следующая строка для печати:
System.out.println(randomString(-229985452) + " " + randomString(-147909649));
Я не могу понять, почему этот код выводит "hello world".
Вот как выглядит метод randomString()
:
public static String randomString(int i) {
Random ran = new Random(i);
StringBuilder sb = new StringBuilder();
while (true) {
int k = ran.nextInt(27);
if (k == 0)
break;
sb.append((char) ('`' + k));
}
return sb.toString();
}
Не могли бы вы объяснить, как работает этот код и каким образом он приводит к такому выводу? Заранее благодарю за помощь!
5 ответ(ов)
Другие ответы объясняют, почему это происходит, но вот как это сделать.
Предположим, у вас есть экземпляр Random
:
Random r = new Random(-229985452);
Первые 6 чисел, которые генерирует r.nextInt(27)
, следующие:
8
5
12
12
15
0
Если же вы создадите другой экземпляр Random
:
Random r = new Random(-147909649);
первые 6 чисел, которые он сгенерирует, будут:
23
15
18
12
4
0
Теперь просто добавьте эти числа к целочисленному представлению символа ``` (который равен 96):
8 + 96 = 104 --> h
5 + 96 = 101 --> e
12 + 96 = 108 --> l
12 + 96 = 108 --> l
15 + 96 = 111 --> o
23 + 96 = 119 --> w
15 + 96 = 111 --> o
18 + 96 = 114 --> r
12 + 96 = 108 --> l
4 + 96 = 100 --> d
Таким образом, вы получите строку "hello world".
Когда java.util.Random
создается с определенным значением семени (в данном случае -229985452
или -147909649
), он использует алгоритм генерации случайных чисел, начиная с этого значения семени.
Каждый объект Random
, созданный с одинаковым семенем, будет генерировать одинаковую последовательность чисел каждый раз.
Каждый здесь хорошо объяснил, как работает код, и показал, как можно создать собственные примеры. Однако, вот ответ с точки зрения информационной теории, который показывает, почему мы можем с разумной вероятностью ожидать существования решения, которое переборный поиск в конечном итоге найдет.
26 различных строчных букв составляют наш алфавит Σ
. Для того чтобы иметь возможность генерировать слова различной длины, мы добавляем символ терминации ⊥
, что дает нам расширенный алфавит Σ' := Σ ∪ {⊥}
.
Обозначим α
как символ, а X как равномерно распределенную случайную величину по Σ'
. Вероятность получения этого символа P(X = α)
и его информационное содержание I(α)
определяются следующими формулами:
P(X = α) = 1/|Σ'| = 1/27
I(α) = -log₂[P(X = α)] = -log₂(1/27) = log₂(27)
Для слова ω ∈ Σ*
и его терминированной версии ω' := ω · ⊥ ∈ (Σ')*
мы имеем:
I(ω) := I(ω') = |ω'| * log₂(27) = (|ω| + 1) * log₂(27)
Поскольку Генератор Псевдослучайных Чисел (PRNG) инициализируется 32-битным семенем, мы можем с ожиданием предполагать, что большинство слов длиной до
λ = floor[32/log₂(27)] - 1 = 5
будет сгенерировано хотя бы одним семенем. Даже если мы будем искать слово из 6 символов, у нас по-прежнему будет 41.06% шансов на успех. Неплохо.
Для слов из 7 букв мы имеем вероятность, близкую к 1.52%, но я не осознавал этого, пока не попробовал сделать следующее:
#include <iostream>
#include <random>
int main()
{
std::mt19937 rng(631647094);
std::uniform_int_distribution<char> dist('a', 'z' + 1);
char alpha;
while ((alpha = dist(rng)) != 'z' + 1)
{
std::cout << alpha;
}
}
Посмотрите на результат: http://ideone.com/JRGb3l
Я был заинтригован этим, поэтому запустил генератор случайных слов на списке слов из словаря. Диапазон: Integer.MIN_VALUE до Integer.MAX_VALUE.
В результате я получил 15131 совпадение.
int[] arrInt = {-2146926310, -1885533740, -274140519,
-2145247212, -1845077092, -2143584283,
-2147483454, -2138225126, -2147375969};
for(int seed : arrInt){
System.out.print(randomString(seed) + " ");
}
Результат:
the quick browny fox jumps over a lazy dog
В данном примере массив arrInt
содержит целые числа, которые используются в качестве зерен для генерации случайных строк. Функция randomString(seed)
принимает каждое зерно и возвращает соответствующую случайную строку, которая в этом случае формирует известное предложение "the quick browny fox jumps over a lazy dog". Если у вас есть дополнительные вопросы о том, как это работает или как можно адаптировать его, пожалуйста, дайте знать!
Большинство генераторов случайных чисел на самом деле являются "псевдослучайными". Они часто реализуются в виде линейных конгруэнтных генераторов (ЛКГ) (http://en.wikipedia.org/wiki/Linear_congruential_generator).
ЛКГ достаточно предсказуемы при фиксированном начальном значении (seed). В общем случае, задайте начальное значение, которое даст вам первую букву, затем напишите приложение, которое будет продолжать генерировать следующие целые числа (символы), пока не получите следующую букву из вашей целевой строки, при этом записывая, сколько раз вам пришлось вызывать ЛКГ. Продолжайте, пока не сгенерируете каждую букву.
Как сгенерировать случайную алфавитно-цифровую строку
Генерация случайной строки/символов в JavaScript
Как преобразовать строку в int в Java?
Как разделить строку в Java?
Как преобразовать int в String?