java - কেন এই কোডটি র্যান্ডম স্ট্রিংগুলি ব্যবহার করে "হ্যালো ওয়ার্ল্ড" মুদ্রণ করে?



string random (13)

নিম্নলিখিত মুদ্রণ বিবৃতি "হ্যালো বিশ্বের" মুদ্রণ করবে। কেউ এই ব্যাখ্যা করতে পারে?

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();
}

Answers

প্রধান বীজ একই বীজ দ্বারা নির্মিত র্যান্ডম ক্লাস প্রতি বার একই প্যাটার্ন উৎপন্ন করবে।


কোডটি কীভাবে কাজ করে এবং কীভাবে আপনি নিজের উদাহরণগুলি তৈরি করতে পারেন তা দেখানোর জন্য এখানে প্রত্যেকেরই একটি দুর্দান্ত কাজ হয়েছে, তবে এখানে একটি তথ্য তত্ত্বগত উত্তর রয়েছে যা আমরা দেখিয়েছি যে সমাধানটি আবিষ্কার করার পক্ষে আমরা কেন যুক্তিসঙ্গতভাবে আশা করতে পারি।

26 বিভিন্ন ছোট হাতের অক্ষর আমাদের বর্ণমালা Σ । বিভিন্ন দৈর্ঘ্যের শব্দ উৎপন্ন করার জন্য, আমরা একটি বর্ধিত বর্ণমালা Σ' := Σ ∪ {⊥} উত্পাদনের জন্য টার্মিনাটর প্রতীক যোগ করি।

α কে একটি প্রতীক হিসাবে এবং X Σ' উপর একটি সমানভাবে বিতরণ র্যান্ডম পরিবর্তনশীল হতে দিন। সেই প্রতীক প্রাপ্তির সম্ভাবনা, P(X = α) , এবং এর তথ্য বিষয়বস্তু, I(α) , দ্বারা প্রদত্ত:

পি (এক্স = α) = 1 / | Σ '| = 1/27

আমি (α) = -log₂ [P (x = α)] = -log₂ (1/27) = লগ₂ (27)

একটি শব্দ ω ∈ Σ* এবং এর ⊥- প্রতিপক্ষ ω' := ω · ⊥ ∈ (Σ')* , আমাদের আছে

আমি (ω): = আমি (ω ') = | ω' | * লগ (27) = (| ω | + 1) * লগ (27)

যেহেতু সিউডোরাম্যান্ড নাম্বার জেনারেটর (PRNG) 32-বিট বীজ দিয়ে শুরু করা হয়েছে, তাই আমরা দৈর্ঘ্যের সর্বাধিক শব্দগুলি আশা করতে পারি

λ = মেঝে [32 / log₂ (27)] - 1 = 5

অন্তত এক বীজ দ্বারা উত্পন্ন করা হবে। এমনকি যদি আমরা 6-অক্ষরের শব্দ অনুসন্ধান করতে থাকি, তবে আমরা এখনও 41.06% সফল হব। খুব বাজে না.

7 টি অক্ষরের জন্য আমরা 1.5২% কাছাকাছি দেখছি, কিন্তু আমি এটি উপলব্ধি করার আগে বুঝতে পারিনি:

#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


ডেনিস 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 :/");
}

যখন java.util.Random একটি উদাহরণ একটি নির্দিষ্ট বীজ পরামিতির সাথে তৈরি হয় (এই ক্ষেত্রে -229985452 বা -147909649 ), তখন এটি বীজ মানের সাথে শুরু হওয়া র্যান্ডম সংখ্যা প্রজন্মের অ্যালগরিদম অনুসরণ করে।

একই বীজের সাথে নির্মিত প্রতিটি Random প্রতিবার একই প্যাটার্ন তৈরি করবে।


সর্বাধিক র্যান্ডম সংখ্যা জেনারেটর, আসলে, "ছদ্মবেশ র্যান্ডম।" তারা লিনিয়ার কনঙ্গ্রুশিয়াল জেনারেটর, বা এলসিজি ( http://en.wikipedia.org/wiki/Linear_congruential_generator )

LCGs একটি নির্দিষ্ট বীজ দেওয়া বেশ predictable হয়। মূলত, এমন একটি বীজ ব্যবহার করুন যা আপনাকে আপনার প্রথম চিঠি দেয়, তারপরে এমন একটি অ্যাপ্লিকেশন লিখুন যা পরবর্তী লক্ষ্যটি (গৃহস্থালি) জেনারেট করে, যতক্ষণ না আপনি আপনার লক্ষ্য স্ট্রিংয়ে পরবর্তী অক্ষরটিকে আঘাত করেন এবং আপনি কত বার এলসিজি আহ্বান করতে চান তা লিখুন। আপনি প্রতিটি চিঠি উত্পন্ন না হওয়া পর্যন্ত চালিয়ে যান।


মাল্টি-থ্রেডিং জাভায়ের সাথে খুব সহজ, এখানে একটি বৈকল্পিক যা সমস্ত বীজের সাহায্যে বীজ অনুসন্ধান করে: 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); // make sure we do not block more important tasks
        result.setDaemon(false);
        return result;
      }
    });
    try {
      final Long result = executor.invokeAny(tasks);
      System.out.println("Seed for \"" + GOAL + "\" found: " + result);
    } catch (Exception ex) {
      System.err.println("Calculation failed: " + ex);
    } finally {
      executor.shutdownNow();
    }
  }
}

র্যান্ডম সবসময় একই ক্রম ফিরে। এটি আবর্তন হিসাবে অ্যারে এবং অন্যান্য অপারেশন shuffling জন্য ব্যবহৃত হয়।

বিভিন্ন ক্রম পেতে, এটি "বীজ" নামে পরিচিত কিছু অবস্থানে ক্রম আরম্ভ করা প্রয়োজন।

র্যান্ডমসটিংটি "র্যান্ডম" অনুক্রমের আই অবস্থান (বীজ = -229985452) র র্যান্ডম সংখ্যা পায়। তারপরে পরবর্তী 27 ক্যারেক্টারের জন্য ASCII কোড ব্যবহার করে বীজের অবস্থান অনুসারে এই মানটি 0 পর্যন্ত সমান হবে। এটি "হ্যালো" প্রদান করে। একই অপারেশন "বিশ্বের" জন্য সম্পন্ন করা হয়।

আমি যে কোড অন্য কোন শব্দ জন্য কাজ করে না। লোক যে প্রোগ্রাম র্যান্ডম ক্রম খুব ভাল জানেন।

এটা খুব ভালো গাইক কোড!


এটি সম্পর্কে "বীজ"। একই বীজ একই ফলাফল দিতে।


এখানে ডেনিস Tulskiy answer জন্য একটি ছোটখাট উন্নতি। এটা অর্ধেক সময় কাটা

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

অন্যান্য উত্তর ব্যাখ্যা কেন, কিন্তু এখানে কিভাবে।

Random একটি উদাহরণ দেওয়া:

Random r = new Random(-229985452)

r.nextInt(27) তৈরি করে এমন প্রথম 6 নম্বরগুলি হল:

8
5
12
12
15
0

এবং প্রথম 6 সংখ্যা যা 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

আমি শুধু এখানে এটা ছেড়ে দেব। যার কাছে অনেক সময় (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

আমি এই বীজ খুঁজে পেতে একটি দ্রুত প্রোগ্রাম লিখেছেন:

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);
                }
            }
        }
    }
}

আমি এখন এটি পটভূমিতে চলমান আছে, কিন্তু এটি ইতিমধ্যে একটি ক্লাসিক pangram জন্য যথেষ্ট শব্দ পাওয়া গেছে:

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);
        }
    }
}

( আদর্শের উপর ডেমো। )

গীত। -727295876, -128911, -1611659, -235516779


এখানে doubletap এর চমৎকার উত্তর একটি উন্নতি। আসল দুটি ত্রুটি রয়েছে যা এখানে উল্লেখ করা হয়েছে:

প্রথমত, অন্যরা যেমন উল্লেখ করেছেন, ছোট শব্দের বা এমনকি একটি খালি স্ট্রিং (যদি র্যান্ডম সংখ্যা 0 হয়) তৈরি করার সামান্য সম্ভাবনা রয়েছে, যা আপনার অ্যাপ্লিকেশনটি ভাঙ্গতে পারে। এখানে একটি সমাধান:

(Math.random().toString(36)+'00000000000000000').slice(2, N+2)

দ্বিতীয়ত, মূল এবং সমাধান উভয়ই স্ট্রিং আকার N থেকে 16 অক্ষর সীমাবদ্ধ করে। নিম্নলিখিত কোন N এর জন্য আকার N এর একটি স্ট্রিং প্রদান করবে (তবে মনে রাখবেন যে N> 16 ব্যবহার করে এলোমেলোতা বা সংঘর্ষের সম্ভাবনা হ্রাস করবে না):

Array(N+1).join((Math.random().toString(36)+'00000000000000000').slice(2, 18)).slice(0, N)

ব্যাখ্যা:

  1. পরিসীমা [0,1], যা 0 (সমেত) এবং 1 (একচেটিয়া) মধ্যে একটি র্যান্ডম সংখ্যা বাছাই করুন।
  2. সংখ্যাটি বেস -36 স্ট্রিংতে রূপান্তর করুন, অর্থাৎ অক্ষরগুলি 0-9 এবং az ব্যবহার করে।
  3. Zeros সঙ্গে প্যাড (প্রথম সমস্যা সমাধান)।
  4. নেতৃস্থানীয় '0' বন্ধ স্লাইস। উপসর্গ এবং অতিরিক্ত প্যাডিং জিরো।
  5. কমপক্ষে N অক্ষরটির জন্য পর্যাপ্ত স্ট্রিংটি পুনরাবৃত্তি করুন (ডিলিমিটার হিসাবে ব্যবহৃত ছোট র্যান্ডম স্ট্রিং সহ খালি স্ট্রিংগুলিতে যোগদান করে)।
  6. স্ট্রিং থেকে ঠিক এন অক্ষর স্লাইস।

আরও চিন্তা:

  • এই সমাধান বড় হাতের অক্ষর ব্যবহার করে না, কিন্তু প্রায় সব ক্ষেত্রে (কোন pun intended) এটি কোন ব্যাপার না।
  • মূল উত্তরটিতে N = 16 এ সর্বোচ্চ স্ট্রিং দৈর্ঘ্য ক্রোমে পরিমাপ করা হয়। ফায়ারফক্সে এটি এন = 11. কিন্তু ব্যাখ্যা হিসাবে, দ্বিতীয় সমাধানটি কোনও অনুরোধকৃত স্ট্রিং দৈর্ঘ্যের সমর্থন করে, যেটি এলোমেলোতা যোগ না করে, তাই এটি কোনও পার্থক্য তৈরি করে না।
  • সমস্ত ফেরত স্ট্রিংগুলি ফিরে যাওয়ার সমান সম্ভাবনা রয়েছে, অন্তত যতদূর পর্যন্ত Math.random () দ্বারা ফলাফলগুলি সমানভাবে বিতরণ করা হয় (এটি কোনও ক্ষেত্রে ক্রিপ্টোগ্রাফিক-শক্তি র্যান্ডমনেস নয়)।
  • আকার N এর সমস্ত সম্ভাব্য স্ট্রিংগুলি ফেরত দেওয়া যাবে না। দ্বিতীয় সমাধানটিতে এটি সুস্পষ্ট (যেহেতু ছোট স্ট্রিংটি কেবল ডুপ্লিকেট করা হচ্ছে), তবে আসল উত্তরেও এটি সত্য যেহেতু বেস 36 তে রূপান্তরিত হওয়ার পরে শেষ কয়েকটি বিট আসল র্যান্ডম বিটগুলির অংশ হতে পারে না। বিশেষ করে, যদি আপনি Math.random ()। ToString (36) এর ফলাফলটি দেখেন, তবে আপনি শেষ চরিত্রটিকে সমানভাবে বিতরণ করবেন না তা লক্ষ্য করবেন। আবার, প্রায় সব ক্ষেত্রে এটি কোনও ব্যাপার নয়, তবে আমরা র্যান্ডম স্ট্রিংয়ের শেষের চেয়ে শুরু থেকে চূড়ান্ত স্ট্রিংটি টুকরো করি যাতে ছোট স্ট্রিংগুলি (যেমন এন = 1) প্রভাবিত হয় না।

হালনাগাদ:

এখানে একটি দম্পতি অন্যান্য কার্যকরী শৈলী এক liners আমি সঙ্গে এসেছিলেন। তারা উপরের সমাধান থেকে আলাদা:

  • তারা একটি স্পষ্ট ইচ্ছাকৃত বর্ণমালা ব্যবহার করে (আরো জেনেরিক, এবং মূল প্রশ্নে উপযুক্ত যা উচ্চতর এবং ছোট হাতের উভয় অক্ষরের জন্য বলা হয়)।
  • দৈর্ঘ্যের N এর সমস্ত স্ট্রিংগুলি ফিরে যাওয়ার সমান সম্ভাবনা রয়েছে (অর্থাত স্ট্রিংগুলিতে কোন পুনরাবৃত্তি নেই)।
  • তারা একটি স্ট্রিং (36) কৌশল ছাড়া একটি মানচিত্র ফাংশন উপর ভিত্তি করে, যা তাদের আরো সহজতর এবং বোঝার জন্য সহজ করে তোলে।

সুতরাং, পছন্দ আপনার বর্ণমালা বলুন

var s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

তারপর এই দুটি একে অপরকে সমান, তাই আপনি যে কোনটি আরও বেশি স্বজ্ঞাত চয়ন করতে পারেন:

Array(N).join().split(',').map(function() { return s.charAt(Math.floor(Math.random() * s.length)); }).join('');

এবং

Array.apply(null, Array(N)).map(function() { return s.charAt(Math.floor(Math.random() * s.length)); }).join('');

সম্পাদনা:

আমি qubyte মত মনে হয় এবং Martijn ডি মিলিয়ানো পরে সমাধান (KUDOS!) অনুরূপ সমাধান, যা আমি কোনভাবে মিস। যেহেতু তারা একটি নজরে সংক্ষিপ্ত হিসাবে দেখতে না, যেহেতু কেউ সত্যিই এখানে একটি মাছ ধরার নৌকা চায় :-)

এছাড়াও, কয়েকটি বাইট বন্ধ করার জন্য সমস্ত সমাধানগুলিতে 'অ্যারে' দিয়ে 'নতুন অ্যারে' প্রতিস্থাপিত হয়েছে।





java string random