질문자 :0x56794E
다음 인쇄 문은 "hello world"를 인쇄합니다. 아무도 이것을 설명 할 수 있습니까?
System.out.println(randomString(-229985452) + " " + randomString(-147909649));
그리고 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(); }
다른 답변은 이유를 설명하지만 여기에 방법이 있습니다.
Random
인스턴스가 주어지면 :
Random r = new Random(-229985452)
r.nextInt(27)
생성하는 처음 6개의 숫자는 다음과 같습니다.
8 5 12 12 15 0
r.nextInt(27)
가 주어진 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
Eng.Fouadjava.util.Random
의 인스턴스가 특정 시드 매개변수(이 경우 -229985452
또는 -147909649
)로 구성되면 해당 시드 값으로 시작 하는 난수 생성 알고리즘을 따릅니다.
동일한 시드로 구성된 모든 Random
은 매번 동일한 패턴의 숫자를 생성합니다.
FThompson그냥 여기에 두겠습니다. (CPU) 시간이 많으신 분들은 자유롭게 실험해 보세요 :) 또한, 모든 CPU 코어를 태울 수 있는 포크-조인-푸를 마스터하셨다면 공유해주세요. 당신의 코드. 매우 감사하겠습니다.
public static void main(String[] args) { long time = System.currentTimeMillis(); generate("stack"); generate("over"); generate("flow"); generate("rulez"); System.out.println("Took " + (System.currentTimeMillis() - time) + " ms"); } private static void generate(String goal) { long[] seed = generateSeed(goal, Long.MIN_VALUE, Long.MAX_VALUE); System.out.println(seed[0]); System.out.println(randomString(seed[0], (char) seed[1])); } public static long[] generateSeed(String goal, long start, long finish) { char[] input = goal.toCharArray(); char[] pool = new char[input.length]; label: for (long seed = start; seed < finish; seed++) { Random random = new Random(seed); for (int i = 0; i < input.length; i++) pool[i] = (char) random.nextInt(27); if (random.nextInt(27) == 0) { int base = input[0] - pool[0]; for (int i = 1; i < input.length; i++) { if (input[i] - pool[i] != base) continue label; } return new long[]{seed, base}; } } throw new NoSuchElementException("Sorry :/"); } public static String randomString(long i, char base) { System.out.println("Using base: '" + base + "'"); Random ran = new Random(i); StringBuilder sb = new StringBuilder(); for (int n = 0; ; n++) { int k = ran.nextInt(27); if (k == 0) break; sb.append((char) (base + k)); } return sb.toString(); }
산출:
-9223372036808280701 Using base: 'Z' stack -9223372036853943469 Using base: 'b' over -9223372036852834412 Using base: 'e' flow -9223372036838149518 Using base: 'd' rulez Took 7087 ms
Denis Tulskiy여기 있는 모든 사람들은 코드가 어떻게 작동하는지 설명하고 자신의 예제를 구성하는 방법을 잘 보여주었습니다. 하지만 여기에는 무차별 대입 검색이 결국 찾을 수 있는 솔루션이 존재할 것으로 합리적으로 기대할 수 있는 이유를 보여주는 정보 이론적인 답변이 있습니다.
26개의 다른 소문자가 알파벳 Σ
형성합니다. 다른 길이의 단어를 생성할 수 있도록 종료 기호 ⊥
를 추가하여 확장 알파벳 Σ' := Σ ∪ {⊥}
합니다.
α
Σ'
대해 균일하게 분포된 확률 변수라고 합시다. P(X = α)
및 해당 정보 내용 I(α)
를 얻을 확률은 다음과 같습니다.
P(X = α) = 1/|Σ'| = 1/27
I(α) = -log₂[P(X = α)] = -log₂(1/27) = log₂(27)
단어 ω ∈ Σ*
및 ⊥-
끝나는 ω' := ω · ⊥ ∈ (Σ')*
경우
나(ω) := 나(ω') = |ω'| * log₂(27) = (|ω| + 1) * log₂(27)
Pseudorandom Number Generator(PRNG)는 32비트 시드로 초기화되므로 대부분의 단어 길이는 최대
λ = 바닥[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
xDD나는 이러한 씨앗을 찾기 위해 빠른 프로그램을 작성했습니다.
import java.lang.*; import java.util.*; import java.io.*; public class RandomWords { public static void main (String[] args) { Set<String> wordSet = new HashSet<String>(); String fileName = (args.length > 0 ? args[0] : "/usr/share/dict/words"); readWordMap(wordSet, fileName); System.err.println(wordSet.size() + " words read."); findRandomWords(wordSet); } private static void readWordMap (Set<String> wordSet, String fileName) { try { BufferedReader reader = new BufferedReader(new FileReader(fileName)); String line; while ((line = reader.readLine()) != null) { line = line.trim().toLowerCase(); if (isLowerAlpha(line)) wordSet.add(line); } } catch (IOException e) { System.err.println("Error reading from " + fileName + ": " + e); } } private static boolean isLowerAlpha (String word) { char[] c = word.toCharArray(); for (int i = 0; i < c.length; i++) { if (c[i] < 'a' || c[i] > 'z') return false; } return true; } private static void findRandomWords (Set<String> wordSet) { char[] c = new char[256]; Random r = new Random(); for (long seed0 = 0; seed0 >= 0; seed0++) { for (int sign = -1; sign <= 1; sign += 2) { long seed = seed0 * sign; r.setSeed(seed); int i; for (i = 0; i < c.length; i++) { int n = r.nextInt(27); if (n == 0) break; c[i] = (char)((int)'a' + n - 1); } String s = new String(c, 0, i); if (wordSet.contains(s)) { System.out.println(s + ": " + seed); wordSet.remove(s); } } } } }
지금은 백그라운드에서 실행하고 있지만 이미 클래식 팬그램에 대한 충분한 단어를 찾았습니다.
import java.lang.*; import java.util.*; public class RandomWordsTest { public static void main (String[] args) { long[] a = {-73, -157512326, -112386651, 71425, -104434815, -128911, -88019, -7691161, 1115727}; for (int i = 0; i < a.length; i++) { Random r = new Random(a[i]); StringBuilder sb = new StringBuilder(); int n; while ((n = r.nextInt(27)) > 0) sb.append((char)('`' + n)); System.out.println(sb); } } }
( ideone에 대한 데모. )
추신. -727295876, -128911, -1611659, -235516779
.
Ilmari Karonen나는 이것에 흥미를 느꼈고 사전 단어 목록에서 이 임의의 단어 생성기를 실행했습니다. 범위: 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
Puru--대부분의 난수 생성기는 사실 "의사 난수"입니다. 선형 합동 생성기 또는 LCG( http://en.wikipedia.org/wiki/Linear_congruential_generator )입니다.
LCG는 고정된 시드를 감안할 때 상당히 예측 가능합니다. 기본적으로 첫 번째 문자를 제공하는 시드를 사용한 다음 대상 문자열의 다음 문자에 도달할 때까지 다음 int(char)를 계속 생성하는 앱을 작성하고 LCG를 호출해야 했던 횟수를 기록합니다. 모든 문자를 생성할 때까지 계속하십시오.
Sinclair SchullerJava에서는 멀티 스레딩이 매우 쉽기 때문에 사용 가능한 모든 코어를 사용하여 시드를 검색하는 변형이 있습니다. http://ideone.com/ROhmTA
import java.util.ArrayList; import java.util.Random; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ThreadFactory; public class SeedFinder { static class SearchTask implements Callable<Long> { private final char[] goal; private final long start, step; public SearchTask(final String goal, final long offset, final long step) { final char[] goalAsArray = goal.toCharArray(); this.goal = new char[goalAsArray.length + 1]; System.arraycopy(goalAsArray, 0, this.goal, 0, goalAsArray.length); this.start = Long.MIN_VALUE + offset; this.step = step; } @Override public Long call() throws Exception { final long LIMIT = Long.MAX_VALUE - this.step; final Random random = new Random(); int position, rnd; long seed = this.start; while ((Thread.interrupted() == false) && (seed < LIMIT)) { random.setSeed(seed); position = 0; rnd = random.nextInt(27); while (((rnd == 0) && (this.goal[position] == 0)) || ((char) ('`' + rnd) == this.goal[position])) { ++position; if (position == this.goal.length) { return seed; } rnd = random.nextInt(27); } seed += this.step; } throw new Exception("No match found"); } } public static void main(String[] args) { final String GOAL = "hello".toLowerCase(); final int NUM_CORES = Runtime.getRuntime().availableProcessors(); final ArrayList<SearchTask> tasks = new ArrayList<>(NUM_CORES); for (int i = 0; i < NUM_CORES; ++i) { tasks.add(new SearchTask(GOAL, i, NUM_CORES)); } final ExecutorService executor = Executors.newFixedThreadPool(NUM_CORES, new ThreadFactory() { @Override public Thread newThread(Runnable r) { final Thread result = new Thread(r); result.setPriority(Thread.MIN_PRIORITY);
TwoTheRandom은 항상 동일한 시퀀스를 반환합니다. 순열로 배열 및 기타 작업을 섞는 데 사용됩니다.
다른 시퀀스를 얻으려면 "시드"라고 하는 특정 위치에서 시퀀스를 초기화해야 합니다.
randomSting은 "임의" 시퀀스의 i 위치(시드 = -229985452)에서 난수를 가져옵니다. 그런 다음 이 값이 0이 될 때까지 시드 위치 뒤의 시퀀스에서 다음 27자에 대해 ASCII 코드를 사용합니다. 그러면 "hello"가 반환됩니다. "world"에 대해서도 동일한 작업이 수행됩니다.
코드가 다른 단어에는 작동하지 않았다고 생각합니다. 무작위 순서를 아주 잘 아는 프로그램을 만든 사람입니다.
아주 훌륭한 괴짜 코드입니다!
Arnaldo Ignacio Gaspar Véjar원칙은 동일한 시드로 구성된 랜덤 클래스가 매번 동일한 패턴의 숫자를 생성한다는 것입니다.
tomj0101Denis Tulskiy 의 답변에서 파생된 이 방법은 시드를 생성합니다.
public static long generateSeed(String goal, long start, long finish) { char[] input = goal.toCharArray(); char[] pool = new char[input.length]; label: for (long seed = start; seed < finish; seed++) { Random random = new Random(seed); for (int i = 0; i < input.length; i++) pool[i] = (char) (random.nextInt(27)+'`'); if (random.nextInt(27) == 0) { for (int i = 0; i < input.length; i++) { if (input[i] != pool[i]) continue label; } return seed; } } throw new NoSuchElementException("Sorry :/"); }
sulaiJava 문서에서 이것은 Random 클래스에 대한 시드 값을 지정할 때 의도적인 기능입니다.
Random의 두 인스턴스가 동일한 시드로 생성되고 각각에 대해 동일한 메서드 호출 시퀀스가 만들어지면 동일한 시퀀스 번호를 생성하고 반환합니다. 이 속성을 보장하기 위해 Random 클래스에 대해 특정 알고리즘이 지정됩니다. Java 구현은 Java 코드의 절대 이식성을 위해 Random 클래스에 대해 여기에 표시된 모든 알고리즘을 사용해야 합니다.
http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Random.html
그러나 이상하게도 예측 가능한 '임의' 숫자를 갖는 데 내재된 보안 문제가 있다고 생각할 것입니다.
deed02392"씨앗"에 관한 것입니다. 같은 씨앗은 같은 결과를 낳습니다.
Burak Keceli다음은 Denis Tulskiy 답변에 대한 약간의 개선 사항입니다. 시간을 반으로 줄여준다
public static long[] generateSeed(String goal, long start, long finish) { char[] input = goal.toCharArray(); int[] dif = new int[input.length - 1]; for (int i = 1; i < input.length; i++) { dif[i - 1] = input[i] - input[i - 1]; } mainLoop: for (long seed = start; seed < finish; seed++) { Random random = new Random(seed); int lastChar = random.nextInt(27); int base = input[0] - lastChar; for (int d : dif) { int nextChar = random.nextInt(27); if (nextChar - lastChar != d) { continue mainLoop; } lastChar = nextChar; } if(random.nextInt(27) == 0){ return new long[]{seed, base}; } } throw new NoSuchElementException("Sorry :/"); }
Ilya Gazman그것은 모두 입력 시드 에 관한 것입니다. 같은 씨앗은 항상 같은 결과를 낳습니다. 프로그램을 몇 번이고 다시 실행해도 동일한 출력이 나옵니다.
public static void main(String[] args) { randomString(-229985452); System.out.println("------------"); randomString(-229985452); } private static void randomString(int i) { Random ran = new Random(i); System.out.println(ran.nextInt()); System.out.println(ran.nextInt()); System.out.println(ran.nextInt()); System.out.println(ran.nextInt()); System.out.println(ran.nextInt()); }
산출
-755142161 -1073255141 -369383326 1592674620 -1524828502 ------------ -755142161 -1073255141 -369383326 1592674620 -1524828502
nagendra547출처 : http:www.stackoverflow.com/questions/15182496/why-does-this-code-using-random-strings-print-hello-world