Почему srand создает одинаковые числа?

Я написал программу на c, которая создает случайную матрицу. Он создает такую ​​строку (3,-6,2;5,2,-9;-8,20,7). ";" вырезает каждую строку и "," каждый столбец. Теперь я написал программу на ржавчине, которая делает сложение матриц или множителей. Я называю это так:
./matrix ./test 3 3 "*" ./test 3 3

./matrix вызывает мою программу на ржавчине, и я даю ей 3 аргумента. (Матрица 1, Оператор, Матрица2) Это работает, и расчет в порядке, но Матрица 1 и 2 всегда равны. Я думаю, это потому, что я использую srand в зависимости от времени и потому, что я вызываю его одновременно, он создает два раза одно и то же. Я также протестировал Matrixrandomizer, не включая его в вызов rust, и он всегда создает другую матрицу.

Здесь вы можете увидеть мой код c.

#include <stdlib.h>
#include <time.h>
#include <stdio.h>
#include <string.h>

int main (int argc, char* argv[]) {
    // Zufallszahlengenerator initialisieren
    srand(time(NULL));

    if(argc < 3) {
        printf("Es fehlen Argumente");
    }   
    char matrix[100] = "";

    int r, c;
    r = atoi(argv[1]);
    c = atoi(argv[2]);

    if(r > 0 && c > 0) {
        for(int i = 0; i < r; i++) {
            for(int j = 0; j < c; j++){
                if(j == c - 1) {
                    int test = (1+rand()%9);
                    char buffer[50];
                    sprintf(buffer, "%d", test);
                    strcat(matrix, buffer);
                    }
                if(j < c - 1){  
                    int test = (1+rand()%9);
                    char buffer[50];
                    sprintf(buffer, "%d", test);
                    strcat(matrix, buffer);
                    strcat(matrix, ",");    
                }

            }
            if(i != r - 1) {
                strcat(matrix, ";");
            }   
        }       
    }
    printf("%s", matrix);
}


person Jan Wolfram    schedule 27.10.2019    source источник
comment
Да, это причина. Вызов srand() с тем же значением приведет к тому же состоянию PRNG. Попробуйте srand(time(NULL) + getpid()) /* remember to #include <unistd.h> */;, если вы работаете в системе POSIX (или, может быть, srand(time(NULL) + GetCurrentProcessId()) для Windows).   -  person pmg    schedule 27.10.2019
comment
Что такое ./test 3 3? Случайная квадратная матрица третьего порядка?   -  person Javier Silva Ortíz    schedule 27.10.2019
comment
Спасибо :) Работает хорошо. getpid возвращает идентификатор процесса, верно? Итак, когда вы добавляете его в начальную переменную srand, у вас есть другое значение в зависимости от srand()?   -  person Jan Wolfram    schedule 27.10.2019
comment
./test 3 3 - это мой вызов программы c, а 3 3 - размеры матрицы :)   -  person Jan Wolfram    schedule 27.10.2019
comment
Правильно @JanWolfram: один процесс выдаст что-то вроде srand(1572191000 + 34902), а другой srand(1572191000 + 34927)   -  person pmg    schedule 27.10.2019
comment
github.com/jedisct1/libsodium   -  person Stargateur    schedule 27.10.2019
comment
Возможный дубликат rand() возвращает те же значения при вызове внутри одна функция   -  person S.S. Anne    schedule 27.10.2019


Ответы (2)


srand хочет получить семя в качестве аргумента. Для данного семени случайная последовательность будет равна. Таким образом, если вы вызовете srand дважды за очень короткое время с time(NULL) в качестве аргумента, высоки шансы, что вы дадите одно и то же начальное число.

Использование time(NULL) в качестве начального числа — это хороший способ обеспечить разные выходные данные каждый раз, когда вы запускаете программу в обычных условиях. Но в этом случае нужно добавить еще кое-что. Один из способов сделать это — добавить дополнительный аргумент для работы в качестве соли (терминология, заимствованная из хеширования) следующим образом:

int salt = atoi(argv[3]);
srand(time(NULL) + salt);

И затем обязательно вызовите программу с другими аргументами, например:

./test 3 3 546

Здесь 546 — это номер, который вы выбираете, и он должен быть разным для двух вызовов. И я бы рекомендовал сделать их очень разными. Если они отличаются всего на единицу, вы можете столкнуться с той же проблемой, если часы переведут секунды между двумя вызовами.

Другой способ сделать это — использовать getpid() в качестве соли. Это может быть предпочтительнее, если вы не хотите изменять количество аргументов, которые вы должны отправить программе.

person klutt    schedule 27.10.2019
comment
@Stargateur Что не так? Возможно, это не идеальное решение, но оно работает. - person klutt; 27.10.2019
comment
@stargateur Я отредактировал опечатку atoi(argv[3]) и, очевидно, убедился, что вызов функции с разными аргументами означает добавление третьего (начального) аргумента. - person LegendofPedro; 27.10.2019

Функция srand принимает в качестве аргумента seed. Для одного и того же начального числа генератор псевдослучайных чисел всегда будет выдавать одну и ту же выходную последовательность. Существует минимальный временной шаг, который можно распознать в любой дискретной системе, такой как компьютер. Следовательно, вызов /matrix ./test 3 3 "*" ./test 3 3 может происходить с меньшим временным шагом, что означает, что они происходят в одно и то же время, а time(NULL) возвращает одно и то же время, одно и то же начальное число, следовательно, одну и ту же случайную последовательность и, следовательно, одни и те же матрицы. Быстрое решение — попробовать srand(time(NULL) + getpid()) и #include <unistd.h> в системе POSIX или srand(time(NULL) + GetCurrentProcessId()) в системах Windows. Более сложное решение состоит в том, чтобы снабдить исходное семя солью. Соль — это, по сути, значение, которое добавляется к семени. Однако выбор значения соли — это совсем другая тема. Вы можете найти указатели на него здесь.

person Javier Silva Ortíz    schedule 27.10.2019