6
votes

Chaîne de randomisation Java

J'essaye de générer des mots sans signification sans utiliser de fonctions Random (). J'ai compris que je pouvais utiliser l'horloge actuelle ou les coordonnées de la souris. Et j'ai choisi d'utiliser l'horloge actuelle. Voici le code que j'ai écrit.

private final char[] charray = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z',
    'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};

private char getRandomCharacter(){
    return charray[random(charray.length)];
}

private int random(int value){
    value =(int) System.nanoTime()% 52;
    return value;
}

protected Randomizer(){
    boolean running = true;
    int count = 0;
    int max = 5;
    while(running){
        StringBuilder sb = new StringBuilder();
        int size = random(25) + random(25);
        for (int i = 0; i < size; i++) {
            sb.append(getRandomCharacter());
        }
        System.out.println("Random Line : " + sb.toString());

        if (count++ == max) {
            running = false;
            System.out.println("All of them are random.");
        }
    }
}

public static void main(String[] args) {
    new Randomizer();
}

J'attendais la sortie comme:

axdlMkjiIfjcmqQopv etc.

mais j'obtiens quelque chose comme ceci:

ZNNrrrUUUUxxxxbbbhhhLLLLoooRRRRRvvvYYYYBBBBfffI ou JmmmPPKKKKnnnnRRBeeHHHHlllllOOOOrrrVVVVV

Pourquoi il y a trop de continu. Est-ce que nanoTime est trop lent pour cela ou quoi? J'ai utilisé currentTimeMillis avant cela et c'était bien pire. Je ne pouvais pas comprendre et ne pouvais trouver aucune source sur la façon d'aléatoire avec l'horloge actuelle.


21 commentaires

J'attendais des sorties comme: axdlMkjiIfjcmqQopv etc. - Pourquoi exactement?


Est-ce que c'est une question d'un devoir? (Assez juste si c'est le cas, vous avez montré un effort décent jusqu'à présent.) Si ce n'est pas pour les devoirs, je vous suggère fortement de vous en tenir à l'utilisation de la classe Java Random intégrée. La génération de nombres pseudo-aléatoires est difficile à obtenir (même la méthode aléatoire originale en Java n'a pas fait un excellent travail), vous vous torturez donc si vous essayez de réinventer cette roue.


pourquoi passez-vous int value à random uniquement pour attribuer une nouvelle valeur et retourner? quel est le point de l'argument d'entrée?


De plus, je ne m'attendrais pas à ce que System.nanoTime ()% 52 soit uniformément stribué. Cela se résume essentiellement au jiffy de chaque CPU étant différent et donc pas de chaque CPU ayant la même granularité. précision du temps.


@NicholasK je ne sais pas en fait. Je pensais que la sortie de mon code serait exactement aléatoire.


@Bobulous Apprécié pour votre commentaire informatif. J'ai presque tout lu sur le générateur pseudo aléatoire mais je ne pense pas l'avoir compris. C'est en fait un petit projet de devoirs et j'essaye depuis 3 jours, il me reste 4 jours à faire .. Je suppose que nos assistants veulent que nous réinventions cette roue en 7 jours. merci encore, je vais travailler plus dur sur les générateurs pseudo aléatoires :)


@ Turing85 merci pour votre commentaire informatif. Je pensais que si j'utilisais la longueur de mon tableau, cela fonctionnerait correctement. et en fait cela ne fonctionne que 52 sinon il plante et obtient une erreur de limite dans certaines lignes.


Cela dépend probablement de la plate-forme. Sur Mac OS, j'obtiens par exemple "OaWoVbYVNHxqeWMICACBzxlhYPHAtjkYPKveTWUWUXRTrmZVNDqAttjgaWM‌ DAzWGEvpgcYLjSPHIENA‌ s". Quel système d'exploitation utilisez-vous?


@Eren. J'ai fait quelques tests. Le 52 n'est pas le problème, même avec % 10 , vous n'obtenez pas des valeurs uniformément réparties entre 0 et 9. Le problème est que System.nanoTime () < / code> n'est pas distribué uniformément.


@ThomasMueller je ne le savais pas, merci. J'utilise W10 et je n'ai pas la chance d'essayer différents OS


Le principal problème que je vois est que le temps mesuré entre deux appels de méthode est très probablement similaire à chaque fois (moins aléatoire que ce à quoi vous vous attendez). Donc, cela a une faible entropie. Mais oui, vous pouvez utiliser des données de synchronisation pour amorcer un générateur de nombres aléatoires - n'utilisez pas uniquement des données de synchronisation, c'est insuffisant.


Ce n'est pas lié au problème principal mais je pense que vous vouliez private int random (int value) {return (int) System.nanoTime ()% value; }


Pourquoi évitez-vous d'utiliser la classe intégrée Random ?


@Eren, je vous suggère d'imprimer la valeur System.nanoTime (), dans mon win 10 pc, toutes les valeurs se terminent par xxxxxxxx00, ce qui affecte grandement le caractère aléatoire.


@ c0der merci c'est beaucoup plus efficace je suppose. :)


@samabcde j'obtiens quelque chose comme ça, xxxxxxxx73 xxxxxxxx20 xxxxxxxx04 etc.


@Mureinik c'est juste un projet scolaire que "je dois réinventer l'aléatoire je suppose." :)


les temps nano () ne sont en effet pas uniformément répartis, je n'ai pas pris beaucoup de temps ni d'efforts pour y entrer, mais vous pouvez plonger dans uArchitecture et cpu uops pour comprendre ce qui se passe et écrire un article de blog ou deux sur ce sujet (je ' d envisager dev.to), les gens s'efforcent aujourd'hui de publier des articles de qualité comme celui-ci.


Le devoir a-t-il explicitement dit de ne pas utiliser Random , ou est-ce quelque chose que vous avez décidé de faire vous-même? Mon conseil est de ne pas essayer d'inventer le vôtre - c'est très difficile, et même des sommités telles que John von Neumann < / a>, largement considéré comme le mathématicien le plus brillant de sa génération, a réussi à se tromper royalement là-dessus.


Si vous n'êtes pas autorisé à utiliser Random , mais qu'il n'est pas interdit d'implémenter des algorithmes connus indépendamment, ceux-ci sont relativement faciles à coder.


Veuillez consulter: stackoverflow.com/help/someone-answers


3 Réponses :


2
votes

Vous pouvez utiliser des données de synchronisation (en plus d'autres données) pour amorcer un générateur de nombres aléatoires, mais uniquement l'utilisation de données de synchronisation pour le caractère aléatoire n'est pas facile. C'est possible, mais cela peut être très lent. Voir par exemple le code que j'ai écrit ici pour savoir comment utiliser d'autres données pour amorcer une instance aléatoire sécurisée (base de données H2, MathUtils.generateAlternativeSeed). Il utilise:

  • System.currentTimeMillis ()
  • System.nanoTime ()
  • nouvel Object (). hashCode ()
  • Runtime.freeMemory (), maxMemory (), totalMemory ()
  • System.getProperties (). toString ()
  • InetAddress
  • plus de données de synchronisation

Il s'agit de semer un générateur de nombres pseudo-aléatoires sécurisé. Cela garantit que vous obtenez suffisamment d'entropie même sur des systèmes qui n'ont rien d'autre en cours d'exécution, ne connaissent pas l'heure actuelle et n'ont pas d'interface utilisateur.

Mais seulement se fier aux données de synchronisation, comme vous le voyez, est difficile, car cela dépend du système d'exploitation, du temps entre les appels de méthode, du compilateur, du matériel.


1 commentaires

J'ai vraiment apprécié pour votre commentaire qu'il m'aidera plus que je ne le pense lorsque je les recherche tous. Merci encore.



2
votes

Vous pourriez obtenir de meilleurs résultats en définissant charray comme Character [] charray et en faire une liste: List chars = Arrays.asList ( charray);
Utilisez cette liste dans la méthode getRandomCharacter () :

private int random(int value){
    return (int) System.nanoTime()% value;
}

Et bien sûr, corrigez random:

 private char getRandomCharacter(){
     Collections.shuffle(chars); // shuffle before each use 
     return chars.get(random(chars.size()));
 }


4 commentaires

Comment est-ce la réponse acceptée alors que la question demande une solution "sans utiliser de fonctions Random ()"? Et aussi pourquoi utilisez-vous un index aléatoire après la lecture aléatoire? Il est déjà mélangé, pourquoi pas char.get (0)?


@Rad - le random n'est pas une méthode intégrée qui est probablement ce que l'OP voulait éviter - pas spécifiquement une méthode appelée random . Il pourrait être renommé en ghyusssqqq et la fonctionnalité resterait toujours.


Je ne suis pas. Si je comprends bien, le devoir est de réinventer la fonctionnalité aléatoire. Mais cette solution utilise la fonctionnalité intégrée aléatoire de Java.


@Rad vous avez raison sur get (0) . Cela devrait également fonctionner. L'avantage d'utiliser get (random) doit être testé. Pour ce qui est de répondre aux besoins du PO ou non, je lui laisse le soin.



1
votes

Utiliser uniquement le temps est problématique car cela limite la fréquence à laquelle vous pouvez demander un nombre aléatoire et dépend également beaucoup de l'implémentation.

Une meilleure approche serait d'utiliser le temps comme germe et puis utilisez un générateur pseudo-aléatoire, par exemple un générateur congruentiel linéaire . Vous avez plus d'informations dans cette réponse . Tenez compte du fait que cet algorithme de générateur de nombres aléatoires n'est pas sécurisé , et que, comme Thomas l'a souligné en utilisant seul le temps de départ peut ne pas suffire si vous voulez un RNG sécurisé dans tous les systèmes.

Votre code pourrait donc ressembler à ceci:

    private final char[] charray = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z'};

private long seed;

private char getRandomCharacter() {
    return charray[random(charray.length)];
}

private int random(int value) {
    seed = (1103515245L * seed + 12345L) % 2147483648L;
    return (int)seed%value;
}

protected Randomizer() {
    boolean running = true;
    int count = 0;
    int max = 5;
    seed = System.nanoTime();
    while (running) {
        StringBuilder sb = new StringBuilder();
        int size = random(25) + random(25);
        for (int i = 0; i < size; i++) {
            sb.append(getRandomCharacter());
        }
        System.out.println("Random Line : " + sb.toString());

        if (count++ == max) {
            running = false;
            System.out.println("All of them are random.");
        }
    }
}

public static void main(String[] args) {
    new Randomizer();
}


0 commentaires