[java] لماذا يطبع هذا الرمز باستخدام سلاسل عشوائية "hello world"؟


6 Answers

تشرح الإجابات الأخرى السبب ، ولكن هنا كيف.

نظرا لمثل Random :

Random r = new Random(-229985452)

الأرقام 6 الأولى التي r.nextInt(27) :

8
5
12
12
15
0

والأرقام الستة الأولى التي r.nextInt(27) المعطى Random r = new Random(-147909649) هي:

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
Question

طباعة البيان التالي طباعة "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();
}



من Java docs ، هذه ميزة مقصودة عند تحديد قيمة seed لفئة Random.

إذا تم إنشاء حالتين عشوائيتين باستخدام نفس البذرة ، ويتم إجراء نفس تسلسل استدعاءات الأسلوب لكل منهما ، فسوف ينتجان ويعيدان تسلسلات متشابهة للأرقام. من أجل ضمان هذه الخاصية ، يتم تحديد خوارزميات معينة للفئة عشوائية. يجب أن تستخدم تطبيقات Java جميع الخوارزميات الموضحة هنا للفئة Random ، من أجل قابلية شفرة Java البرمجية المطلقة.

http://docs.oracle.com/javase/1.4.2/docs/api/java/util/Random.html

على الرغم من الغريب ، قد تعتقد أن هناك مشاكل أمنية ضمنية في وجود أرقام "عشوائية" يمكن التنبؤ بها.




كنت مفتون بذلك ، ركضت هذا مولد كلمة عشوائية على قائمة الكلمات القاموس. النطاق: 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 



مستمد من جواب دينيس تولسكي ، هذه الطريقة تولد البذور.

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 :/");
}



هنا هو تحسين طفيف لإجابة دنيس 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 :/");
}



دائمًا ما يعيد العائد التسلسل نفسه. يتم استخدامه لخلط المصفوفات والعمليات الأخرى كبديلة.

للحصول على تسلسلات مختلفة ، من الضروري تهيئة التسلسل في موضع ما ، يسمى "seed".

يحصل randomSting على الرقم العشوائي في الموضع i (البذور = -229985452) للتسلسل "العشوائي". ثم يستخدم رمز ASCII للحرف 27 التالي في التسلسل بعد موضع البذور حتى تساوي هذه القيمة إلى 0. هذا إرجاع "hello". نفس العملية تتم لـ "العالم".

أعتقد أن الكود لم يعمل لأي كلمات أخرى. الرجل المبرمج الذي يعرف التسلسل العشوائي بشكل جيد.

إنه رمز مهيب عظيم جدًا!




لقد قام الجميع هنا بعمل رائع لشرح كيفية عمل الشفرة وإظهار كيفية بناء الأمثلة الخاصة بك ، ولكن إليك هنا معلومات نظرية توضح السبب الذي يجعلنا نتوقع بشكل معقول وجود حل موجود في نهاية المطاف والذي سيجده البحث عن القوة الغاشمة في نهاية المطاف.

تشكل الأحرف الصغيرة المختلفة البالغ عددها 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 بت ، يمكننا أن نتوقع معظم كلمات الطول تصل إلى

λ = الكلمة [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




Related