Αλγόριθμος για την παραγωγή ενός τυχαίου αριθμού

ψήφοι
7

Ψάχνω να δημιουργήσει ένα τυχαίο αριθμό και να εκδώσει το σε έναν πίνακα σε μια βάση δεδομένων για ένα συγκεκριμένο user_id. Τα αλιεύματα είναι, ο ίδιος αριθμός δεν μπορεί να χρησιμοποιηθεί δύο φορές. Υπάρχουν ένα εκατομμύριο τρόποι να γίνει αυτό, αλλά ελπίζω κάποιος πολύ έντονος για αλγόριθμους έχει έναν έξυπνο τρόπο για την επίλυση του προβλήματος σε μια κομψή λύση από το γεγονός ότι τα ακόλουθα κριτήρια:

1) Το ελάχιστο ποσό των ερωτημάτων στη βάση δεδομένων γίνονται. 2) Το ελάχιστο ποσό των ερπόντων μέσω μιας δομής δεδομένων στη μνήμη γίνεται.

Ουσιαστικά η ιδέα είναι να κάνετε τα εξής

1) Δημιουργία τυχαίων αριθμών 0 έως 9999999
2) Ελέγξτε τη βάση δεδομένων για να δούμε αν υπάρχει ο αριθμός
Ή
2) Ρωτήστε τη βάση δεδομένων για όλους τους αριθμούς
3) Δείτε αν οι επέστρεψε αγώνες αποτέλεσμα ό, τι ήρθε από την db
4) Αν ταιριάζει, επαναλάβετε βήμα 1, αν όχι, το πρόβλημα έχει λυθεί.

Ευχαριστώ.

Δημοσιεύθηκε 26/11/2008 στις 02:44
πηγή χρήστη
Σε άλλες γλώσσες...                            


17 απαντήσεις

ψήφοι
1

Νομίζω ότι θα βρείτε ότι πραγματικά δεν θέλετε να το κάνετε αυτό. Δεδομένου ότι οι αριθμοί στην αύξηση της βάσης δεδομένων, μπορείτε να περάσετε πάρα πολύ χρόνο στο «βεβαιωθείτε ότι ο αριθμός αυτός δεν έχει ληφθεί» βρόχο.

Προσωπικά, είχα την τύχη με hashes ως εναλλακτική λύση, αλλά να καταλήξουμε σε μια καλύτερη λύση, θα ήθελα πραγματικά να ξέρω γιατί θέλετε να το κάνετε με αυτόν τον τρόπο.

Απαντήθηκε 26/11/2008 στις 02:51
πηγή χρήστη

ψήφοι
1

Η εμπειρία μου ήταν απλά χρησιμοποιώντας το RNG σε PHP. Βρήκα ότι χρησιμοποιώντας ένα συγκεκριμένο μέγεθος του αριθμού (είμαι χρησιμοποιώντας έναν int, έτσι έχω ένα μέγιστο των 4G). Έτρεξα κάποιες δοκιμές και διαπίστωσε ότι, κατά μέσο όρο, σε 500.000 επαναλήψεις, πήρα 120 και μόνο εις διπλούν. Ποτέ δεν πήρα μια τριπλούν μετά την εκτέλεση του βρόχου ένα σωρό φορές. «Λύση» μου ήταν τότε απλά εισάγετε και να ελέγξετε αν αποτύχει, τότε να δημιουργήσει μια νέα ταυτότητα και να πάει πάλι.

Η συμβουλή μου είναι να κάνουν το ίδιο και να δούμε τι ποσοστό σύγκρουση σας είναι και γ και να δούμε αν αυτό είναι αποδεκτό για την περίπτωσή σας.

Αυτή δεν είναι η βέλτιστη, οπότε αν κάποιος έχει προτάσεις ψάχνω πάρα πολύ :)

EDIT: Ι περιορίστηκε σε 5 ψηφίων ID ([a-ΖΑ-Z0-9] {5,5}), όσο μεγαλύτερη είναι η id (πάνω συνδυασμός, οι λίγες συγκρούσεις). Η MD5 του ηλεκτρονικού ταχυδρομείου θα σχεδόν ποτέ δεν έρχονται σε αντίθεση, για παράδειγμα.

Απαντήθηκε 26/11/2008 στις 02:51
πηγή χρήστη

ψήφοι
17

Δεν αλγόριθμο σας δεν είναι επεκτάσιμη. Αυτό που έχω κάνει στο παρελθόν είναι να εκδίδει αριθμούς σε σειρά (+1 κάθε φορά) και στη συνέχεια να περάσει τους μέσω μιας πράξης XOR για να συνονθύλευμα τα κομμάτια έτσι που μου έδωσε ένα φαινομενικά τυχαίους αριθμούς. Φυσικά δεν είναι πραγματικά τυχαία, αλλά φαίνονται τόσο στα μάτια των χρηστών.


[Επεξεργασία] Συμπληρωματικές πληροφορίες

η λογική αυτού του αλγορίθμου πάει κάπως έτσι μπορείτε να χρησιμοποιήσετε μια γνωστή ακολουθία για τη δημιουργία μοναδικών αριθμών και, στη συνέχεια, μπορείτε νομοτελειακά τα χειριστείτε, έτσι ώστε να μην φαίνονται πια σειριακή. Η γενική λύση είναι να χρησιμοποιήσετε κάποια μορφή κρυπτογράφησης, το οποίο στην περίπτωσή μου ήταν ένας flipflop XOR, λόγω της όσο πιο γρήγορα μπορεί να πάρει, και πληροί την εγγύηση ότι οι αριθμοί δεν θα συγκρουστούν.

Ωστόσο, μπορείτε να χρησιμοποιήσετε άλλες μορφές κρυπτογράφησης, αν θέλετε προτιμούν ακόμα πιο τυχαίους αριθμούς που αναζητούν πάνω από την ταχύτητα (δηλαδή δεν χρειάζεται να δημιουργήσει πολλές ταυτότητες κάθε φορά). Τώρα το σημαντικό σημείο για την επιλογή ενός αλγορίθμου κρυπτογράφησης είναι «η εγγύηση ότι οι αριθμοί δεν θα συγκρούονται». Και ένας τρόπος για να αποδειχθεί εάν ένας αλγόριθμος κρυπτογράφησης μπορεί να εκπληρώσει αυτή την εγγύηση για να ελέγξετε αν τόσο ο αρχικός αριθμός και το αποτέλεσμα της κρυπτογράφησης έχουν τον ίδιο αριθμό των bits, και ότι η ο αλγόριθμος είναι αναστρέψιμη (bijection).

[Χάρη σε Adam Liss & CesarB για exapanding επί του διαλύματος]

Απαντήθηκε 26/11/2008 στις 02:51
πηγή χρήστη

ψήφοι
1

Το πρόβλημα είναι ότι αν παραγωγή τυχαίων αριθμών είναι η πολύ πιθανό να παράγουν αντίγραφα infinatly.

ωστόσο:

<?php
//Lets assume we already have a connection to the db
$sql = "SELECT randField FROM tableName";
$result = mysql_query($sql);
$array = array();
while($row = mysql_fetch_assoc($result))
 {
   $array[] = $row['randField'];
 }
while(True)
 {
   $rand = rand(0, 999999);
   if(!in_array($rand))
     {
       //This number is not in the db so use it!
       break;
     }
 }
?>

Αν και αυτό θα κάνει ό, τι θέλετε πάρα πολύ, είναι μια κακή ιδέα, καθώς αυτό δεν θα κλίμακα για πολύ, eventualy σειρά σας θα πάρει σε μεγάλες και θα χρειαστεί ένα πολύ μεγάλο χρονικό διάστημα για να δημιουργήσει ένα τυχαίο δεν είναι ήδη σε db σας .

Απαντήθηκε 26/11/2008 στις 02:55
πηγή χρήστη

ψήφοι
2

υποθέτοντας ότι:

  • Η τυχαιότητα είναι απαραίτητη για την μοναδικότητα, όχι για την ασφάλεια
  • user_id σας είναι 32 bit
  • όριο των 9999999 ήταν απλά ένα παράδειγμα

Θα μπορούσαμε να κάνουμε κάτι απλό όπως έχοντας τον τυχαίο αριθμό ως ακέραιος 64 bit, με τις άνω 32 bits που περιέχει τη χρονική σήμανση (στο ένθετο σειρά) και τα χαμηλότερα 32 bits η user_id. Αυτό θα ήταν το μοναδικό ακόμα και για πολλαπλές σειρές με τον ίδιο τον χρήστη, αρκεί να χρησιμοποιήσετε ένα κατάλληλο ψήφισμα σχετικά με timestamp σας ανάλογα με το πόσο συχνά μπορείτε να προσθέσετε νέες σειρές για τον ίδιο χρήστη. Συνδυάστε το με ένα μοναδικό εμπόδιο για την τυχαία στήλη και να πιάσει κανένα τέτοιο σφάλμα στη λογική σας και, στη συνέχεια, απλά προσπαθήστε ξανά.

Απαντήθηκε 26/11/2008 στις 03:00
πηγή χρήστη

ψήφοι
1

Είναι εύκολο να σχεδιάσει μια γεννήτρια ψευδοτυχαίων αριθμών με μια μακρά περίοδο nonrepetition? για παράδειγμα αυτό , το οποίο χρησιμοποιείται για το ίδιο πράγμα που θέλετε για.

BTW, γιατί να μην εκδίδει διαδοχικά το userid του;

Απαντήθηκε 26/11/2008 στις 03:02
πηγή χρήστη

ψήφοι
0

PHP έχει ήδη μια λειτουργία για το σκοπό αυτό, uniqid . Δημιουργεί ένα πρότυπο UUID που είναι μεγάλη, αν έχετε πρόσβαση στα δεδομένα από αλλού. Μην επανεφεύρουμε τον τροχό.

Απαντήθηκε 26/11/2008 στις 03:06
πηγή χρήστη

ψήφοι
6

Θέλετε μια λύση over-the-top;

Υποθέτω τυχαιότητα δεν προορίζεται να είναι κρυπτογράφησης ποιότητας, αλλά ίσα-ίσα για να αποθαρρύνουν μαντέψουν τη μακροζωία του χρήστη, από user_id.

Κατά τη διάρκεια της ανάπτυξης, να δημιουργήσει μια λίστα με όλα τα 10 εκατομμύρια αριθμούς σε μορφή συμβολοσειράς.

Προαιρετικά, εκτελέσει κάποια απλός μετασχηματισμός, όπως την προσθήκη μια σταθερή συμβολοσειρά στη μέση. (Αυτό είναι ακριβώς σε περίπτωση που το αποτέλεσμα είναι πολύ προβλέψιμη.)

Περάστε τους σε ένα εργαλείο που δημιουργεί τέλειο λειτουργίες Hash , όπως gperf .

Ο κώδικας που προκύπτει μπορεί να χρησιμοποιηθεί για να κωδικοποιήσει γρήγορα id του χρήστη κατά το χρόνο εκτέλεσης σε μια μοναδική τιμή κατακερματισμού που είναι εγγυημένη για να μην έρθουν σε σύγκρουση με τις άλλες τιμές κατακερματισμού.

Απαντήθηκε 26/11/2008 στις 03:16
πηγή χρήστη

ψήφοι
17

Γιατί δεν μπορείτε να χρησιμοποιήσετε μόνο ένα GUID; Οι περισσότερες γλώσσες θα πρέπει να έχει ένα ενσωματωμένο τρόπος για να γίνει αυτό. Είναι εγγυημένη για να είναι μοναδική (με πολύ λογικά όρια).

Απαντήθηκε 26/11/2008 στις 03:19
πηγή χρήστη

ψήφοι
1

Μου αρέσει η ιδέα Oddthinking, αλλά αντί να επιλέξει το ισχυρότερο συνάρτηση κατακερματισμού στον κόσμο, θα μπορούσατε απλά:

  • Δημιουργήστε το MD5 είναι από τα πρώτα 10 εκατομμύρια των αριθμών (που εκφράζεται ως χορδές, + λίγο αλάτι)
  • Έλεγχος για διπλότυπα εκτός σύνδεσης , δηλαδή πριν πάει στην παραγωγή (υποθέτω ότι δεν θα υπάρξει οποιαδήποτε)
  • Αποθηκεύστε τα διπλότυπα σε μια σειρά κάπου
  • Όταν ξεκινήσει η εφαρμογή σας, τοποθετήστε τον πίνακα
  • Όταν θέλετε να εισάγετε ένα αναγνωριστικό, επιλέξτε τον επόμενο αριθμό, υπολογίζει το MD5 του, ελέγξτε αν είναι στη σειρά, και αν δεν το χρησιμοποιήσετε ως ταυτότητα στη βάση δεδομένων. Διαφορετικά, επιλέξτε επόμενο αριθμό

MD5 είναι γρήγορο, και ελέγχοντας αν ένα string ανήκει σε μια σειρά θα μπορείτε να αποφύγετε μια SELECT.

Απαντήθηκε 26/11/2008 στις 03:41
πηγή χρήστη

ψήφοι
3

Δοκιμάστε τη δήλωση στην mysql SELECT CAST (RAND () * 1000000 AS INT)

Απαντήθηκε 26/11/2008 στις 08:51
πηγή χρήστη

ψήφοι
1

Έχω πραγματικά ήδη γράψει ένα άρθρο για αυτό . Παίρνει την ίδια προσέγγιση όπως απάντηση Robert Gould, αλλά επιπλέον δείχνει πώς να συντομεύσει ένα μπλοκ κρυπτογράφησης σε ένα κατάλληλο μήκος χρησιμοποιώντας XOR αναδίπλωση, και στη συνέχεια πώς μπορούν να παράγουν τις παραλλαγές σε ένα εύρος που δεν είναι μια δύναμη του 2, ενώ θα διατηρήσει το μοναδικότητα ιδιοκτησίας.

Απαντήθηκε 26/11/2008 στις 11:13
πηγή χρήστη

ψήφοι
0

Μάλλον δεν είχε πιάσει το σημείο σας, αλλά τι γίνεται με auto_increments;

Απαντήθηκε 27/11/2008 στις 19:11
πηγή χρήστη

ψήφοι
1

Αν πραγματικά θέλετε να πάρετε «τυχαία» τους αριθμούς από 0 έως 9 999 999, τότε η λύση είναι να κάνουμε το «τυχαία» μια φορά, και στη συνέχεια να αποθηκεύσετε το αποτέλεσμα στο δίσκο σας.

Δεν είναι δύσκολο να πάρει το αποτέλεσμα που θέλετε, αλλά το σκέφτομαι περισσότερο σαν «κάνει μια μεγάλη λίστα με τους αριθμούς», από το «να πάρει έναν τυχαίο αριθμό».

$array = range(0, 9999999);
$numbers = shuffle($array);

Θα χρειαστείτε επίσης ένα δείκτη στην τρέχουσα θέση σε αριθμούς $ (το αποθηκεύσετε σε μια βάση δεδομένων)? ξεκινήσουμε με 0 και αυξάνει την κάθε φορά που θα χρειαστεί ένα νέο αριθμό. (Εναλλακτικά, μπορείτε να χρησιμοποιήσετε array_shift () ή array_pop (), αν δεν επιθυμείτε να χρησιμοποιήσετε δείκτες.)

Απαντήθηκε 27/11/2008 στις 23:41
πηγή χρήστη

ψήφοι
1

Ένας αλγόριθμος σωστή PRNG (Pseudo-Random Number Generator) θα έχει ένα χρόνο κύκλου κατά την οποία δεν θα είναι ποτέ στην ίδια κατάσταση. Αν σας εκθέσει ολόκληρη την πολιτεία της PRNG του αριθμού ανακτώνται από αυτό, θα πάρετε έναν αριθμό που εγγυάται μοναδική για την περίοδο της γεννήτριας.

Μια απλή PRNG που κάνει αυτό καλείται η « γραμμική συμβατική PRNG» η οποία επαναλαμβάνεται μια φόρμουλα:

X(i) = AX(i-1)|M

Χρησιμοποιώντας το σωστό ζευγάρι των παραγόντων που μπορείτε να πάρετε μια περίοδο 2 ^ 30 (περίπου 1 δις) από ένα απλό PRNG με συσσωρευτή 32 bit. Σημειώστε ότι θα χρειαστείτε ένα κομμάτι 64 μακρά μακρά προσωρινή μεταβλητή για να κρατήσει το ενδιάμεσο τμήμα «AX» του υπολογισμού. Οι περισσότεροι, αν όχι όλοι οι μεταγλωττιστές C θα υποστηρίζει αυτόν τον τύπο δεδομένων. Θα πρέπει επίσης να είναι σε θέση να το κάνει με έναν αριθμητικό τύπο δεδομένων στις περισσότερες διαλέκτους SQL.

Με τις σωστές τιμές των Α και Μ μπορούμε να πάρουμε μια γεννήτρια τυχαίων αριθμών με καλές στατιστικές και γεωμετρικές ιδιότητες. Υπάρχει ένα διάσημο βιβλίο σχετικά με αυτό γράφτηκε από Fishman και Moore.

Για Μ = 2 ^ 31-1 παίρνουμε να χρησιμοποιήσετε τις τιμές των Α παρακάτω για να πάρετε μια PRNG με ένα ωραίο μακρά περίοδο (2 ^ 30 IIRC).

Καλή τιμές του Α:

742,938,285  
950,706,376  
1,226,874,159  
62,089,911  
1,343,714,438   

Σημειώστε ότι αυτό το είδος της γεννήτριας είναι (εξ ορισμού) δεν κρυπτογραφικά ασφαλής. Εάν γνωρίζετε τον τελευταίο αριθμό που παράγεται από αυτό μπορείτε να προβλέψει τι θα κάνουμε στη συνέχεια. Δυστυχώς πιστεύω ότι δεν μπορείτε να πάρετε κρυπτογραφική ασφάλεια και εγγυημένη μη επαναληψιμότητα, την ίδια στιγμή. Για μια PRNG να είναι ασφαλής από κρυπτογραφική άποψη (π.χ. Blum Blum Shub ) ότι μπορεί να μην εκθέτουν επαρκή κατάσταση σε ένα αριθμός που παράγεται για να επιτραπεί ο επόμενος αριθμός στην ακολουθία που πρόκειται να προβλεφθεί. Συνεπώς, η εσωτερική κατάσταση είναι ευρύτερη από την παραγόμενη αριθμό και (για να έχει καλή ασφάλεια) η περίοδος θα είναι μεγαλύτερη από τον αριθμό των πιθανών τιμών που μπορεί να δημιουργηθεί. Αυτό σημαίνει ότι το εκτεθειμένο αριθμός δεν θα είναι το μοναδικό εντός της περιόδου.

Για παρόμοιους λόγους, το ίδιο ισχύει και για τις γεννήτριες μακράς περιόδου, όπως ο Mersenne Twister.

Απαντήθηκε 27/11/2008 στις 23:59
πηγή χρήστη

ψήφοι
1

Υπάρχουν δύο τρόποι για να πάει για αυτό ένας τρόπος θα ήταν να κατασκευάσει έναν πίνακα με τους αριθμούς 0000000 έως 9999999 και στη συνέχεια να πάρει μια τυχαία επιλογή των αριθμών αυτών σε αυτήν την σειρά και να ανταλλάξουν τις πήρε τιμές αριθμούς με την υψηλότερη μέγιστη τιμή στη συνέχεια να μειώσει το μέγιστο από 1 και να πάρει ένα άλλο τυχαίο μέλος αυτού του πίνακα μέχρι το νέο ανώτατο

κάθε φορά μειώνοντας Max κατά ένα

για παράδειγμα (στα βασικά): (προς τα δεξιά είναι τα σχόλια που θα πρέπει να αφαιρεθεί το πραγματικό πρόγραμμα) Rndfunc είναι μια πρόσκληση για τη λειτουργία της γεννήτριας ό, τι τυχαίων αριθμών που χρησιμοποιείτε

dim array(0 to 9999999) as integer
for x% = 1 to 9999999
array(x%)=x%
next x%
maxPlus = 10000000
max =9999999
pickedrandom =int(Rndfunc*maxPlus)  picks a random indext of the array based on    
                                   how many numbers are left
maxplus = maxplus-1
swap array(pickedrandom) , array(max) swap this array value to the current end of the
                                     array 
max = max -1                   decrement the pointer of the max array value so it 
                              points to the next lowest place..

τότε συνεχίστε να κάνετε αυτό για κάθε αριθμό που θέλετε να επιλέξετε, αλλά θα πρέπει να έχουν τη δυνατότητα να χρησιμοποιούν πολύ μεγάλες συστοιχίες

η άλλη μέθοδος θα ήταν ως εξής: παράγει έναν αριθμό και να το αποθηκεύσετε σε μια σειρά που μπορούν να αναπτυχθούν δυναμικά στη συνέχεια, μετά από αυτό να πάρει ένα νέο αριθμό και συγκρίνετέ την με την τιμή που είναι στα μισά του δρόμου από το πρώτο έως το τελευταίο στοιχείο του πίνακα σε αυτήν την περίπτωση θα είναι ο πρώτος αριθμός πήρε αν ταιριάζει πάρει ένα άλλο τυχαίο αριθμό, να ταξινομήσετε τον πίνακα ανάλογα με το μέγεθος και αν δεν υπάρχει αντιστοιχία, στη συνέχεια, ανάλογα με τον καιρό να είναι μεγαλύτερος ή μικρότερος από τον αριθμό που είναι σε σχέση με πας προς τα πάνω ή προς τα κάτω στην ο κατάλογος μισό μισό της απόστασης, κάθε φορά που δεν ταιριάζει και είναι μεγαλύτερο ή μικρότερο από ό, τι είναι αυτό σύγκριση με.

κάθε φορά μείωση κατά το ήμισυ αυτό μέχρι να φτάσετε σε ένα μέγεθος κενού ενός συνέχεια να ελέγχετε μία φορά και να σταματήσει καθώς δεν υπάρχει αντιστοιχία, και στη συνέχεια ο αριθμός προστίθεται στη λίστα και ο κατάλογος ανακατεύεται με αύξουσα σειρά, ούτω καθεξής και ούτω καθεξής μέχρι να είναι γίνεται επιλέγοντας τυχαίους αριθμούς ... ελπίδα αυτό βοηθά ..

Απαντήθηκε 27/01/2012 στις 14:05
πηγή χρήστη

ψήφοι
0

Αν θέλετε να εξασφαλίσετε ότι οι τυχαίες, οι αριθμοί δεν είναι επαναλαμβανόμενες, θα πρέπει να έχετε ένα μη επαναλαμβανόμενο τυχαίων αριθμών-γεννήτρια (όπως περιγράφεται εδώ ).

Η βασική ιδέα είναι ότι ο ακόλουθος τύπος seed * seed & pθα παραχθεί μη-επαναλαμβανόμενες τυχαία-αριθμούς για κάθε είσοδο x such that 2x < pκαι p - x * x % pπαράγει όλες τις άλλες τυχαίος-αριθμού aswell μη επαναλαμβανόμενη, αλλά μόνο αν p = 3 mod 4. Έτσι, βασικά το μόνο που χρειάζεστε είναι ένα ενιαίο primnumber όσο πιο κοντά 9999999γίνεται. Με αυτό τον τρόπο η προσπάθεια μπορεί να μειωθεί σε μία μόνο ανάγνωση τομέα, αλλά με το μειονέκτημα ότι είτε πάρα πολύ τα μεγάλα αναγνωριστικά δημιουργούνται ή πολύ λίγα αναγνωριστικά θα δημιουργηθεί.

Αυτός ο αλγόριθμος δεν μεταθέτει πολύ καλά, γι 'αυτό ήθελα να συστήσω το συνδυασμό του είτε με XOR ή προσθήκη ή κάποια άλλη προσέγγιση για να αλλάξει την ακριβή τιμή, χωρίς να καταστρέφει την 1-προς-1-σχέση μεταξύ των σπόρων και παράγεται αξία τους.

Απαντήθηκε 04/10/2015 στις 22:49
πηγή χρήστη

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more