Главная страница
Навигация по странице:

  • Кафедра «Информационная безопасность компьютерных систем» ОТЧЕТ ПО ЛАБОРАТОРНОЙ РАБОТЕ № 1 «Линейный конгруэнтный генератор. Подбор и тест параметров»

  • 2. РЕЗУЛЬТАТЫ РАБОТЫ 2.1 Программа

  • 2.2 Подбор правильных параметров

  • Следствие

  • Частотный побитовый тест

  • Тест на одинаковые идущие подряд биты

  • 2.4 Виды параметров Подбираемые параметры можно разделить на 3 типа: Отличные, хорошие, плохие.Рассмотрим каждый тип:•Отличные

  • Отчет по лабораторной работе 1 Линейный конгруэнтный генератор. Подбор и тест параметров


    Скачать 385.76 Kb.
    НазваниеОтчет по лабораторной работе 1 Линейный конгруэнтный генератор. Подбор и тест параметров
    Дата27.03.2023
    Размер385.76 Kb.
    Формат файлаpdf
    Имя файла-1-_compress.pdf
    ТипОтчет
    #1019518

    Министерство образования и науки Российской Федерации
    Санкт-Петербургский государственный политехнический университет

    Институт информационных технологий и управления
    Кафедра «Информационная безопасность компьютерных систем»
    ОТЧЕТ
    ПО ЛАБОРАТОРНОЙ РАБОТЕ № 1
    «Линейный конгруэнтный генератор. Подбор и тест параметров»
    по дисциплине «Технологии программирования»
    Выполнил студент гр.
    Проверил преподаватель
    Демидов Р.А.
    Санкт-Петербург
    2015
    ФИО студента "группа"
    11
    1

    1. ФОРМУЛИРОВКА ЗАДАНИЯ
    1) Сгенерировать псевдослучайные последовательности ЛКГ. Выяснить, от чего зависит случайность последовательности. Подобрать параметры для генератора, при которых его эффективность максимальна.
    2) Написать программу — генератор случайных чисел. Реализовать в ней функции rand(), srand(seed), функции для подбора подходящих параметров и тестирования произвольных, которые можно ввести с клавиатуры. Программа также должна оценивать на случайность созданную последовательность с помощью побитовых тестов, определять её максимальную мощность и период.
    2. РЕЗУЛЬТАТЫ РАБОТЫ
    2.1 Программа
    Программа выполнена на языке программирования С. Исходный код программы представлен в приложении : Листинг 1.
    Краткое описание:
    функции:
    1.
    is_prime(x) - определяет, является ли число простым
    2.
    are_both_prime(a,b) — определяет, являются ли числа взаимно простыми
    3.
    srand(seed) — задаёт новый параметр x0 4.
    get_c() - проверка, подходит ли параметр с
    5.
    cr_parameter() - генерация всех параметров: a,c,m.
    6.
    Rand() - сгенерировать случайное число
    7.
    period_power() - найти мощность и период у последовательности
    8.
    first_test() - тест на распределение битов в последовательности
    9.
    second_test() - частотный побитовый тест
    10. third_test() - тест на одинаковые идущие подряд биты
    11. demo() - вывести последовательность, протестировать её
    12. enter() - ввод произвольных параметров, затем demo()
    Программа начинает работу в функции main(). Создаются enum параметры для меню.
    Запускается бесконечный цикл. Меню состоит из команд:
    1) 0-Выход из цикла и завершение работы программы
    2) 1-Сгенерировать подходящие параматры (cr_parameter())
    3) 2-Тест параметров (first_test(), second_test(), third_test())
    4) 3-Тест произвольных параметров (enter())
    5) 4-Найти максимальную мощность и период (period_power())
    6) 5-Вывести некоторое число эл-тов массива (vivod())
    При нажатии опр. цифры программа выполняет поставленную задачу и возвращается к меню.
    2.2 Подбор правильных параметров
    Случайная последовательность генерируется по закону
    ,
    Такая последовательность обязательно является периодической, так как число может иметь не более m различных значений, причём, длина периода не может быть больше m. Следовательно, m должен быть максимально большим.
    Теорема: Максимальный период последовательности равен m, если выполняются след. условия:
    1) число a-1 делится на все простые делители числа m;
    2) если m делится на 4, то и a-1 делится на 4;
    3) число c взаимно просто с m;
    Следствие: a mod 8 = 5 ; c – нечётное, простое; m = 2^k (k=16, 32, 64).
    x =( x * a + b) mod m
    11
    1

    2.3 Тесты на случайность
    Тест на идеальное распределение нулей и единиц в двоичной последовательности
    Производится подсчёт единичных и нулевых битов в последовательности. В идеальной последовательности соотношение единичных и нулевых битов к общему число равно 0.5. Если отклонение от идеального распределения слишком большое (>0.1), то тест не будет пройден.
    Частотный побитовый тест
    Вероятность ошибки первого рода называют уровнем статистической значимости и обозначают как α. Т.е. α — это вероятность отбраковать «хорошую» случайную последовательность.
    Это значение определяется областью применения. В криптографии принято α брать от 0.001 до 0.01.
    В каждом тесте вычисляется P-значение: это вероятность того, что подопытный генератор произведет последовательность не хуже, чем гипотетический истинный. Если P - значение = 1, то наша последовательность идеально случайна, а если оно = 0, то последовательность полностью предсказуема.
    В дальнейшем P-значение сравнивается с α, и если она больше α, то нулевая гипотеза принимается и последовательность признается случайной. В противном случае — отбраковывается.
    В тестах берется α = 0.01. Из этого следует, что: Если P-значение ≥ 0.01, то последовательность признается случайной с уровнем доверия 99%. Если P-значение < 0.01, то последовательность отбраковывается с уровнем доверия 99%. Очевидно, что чем более случайна последовательность, тем ближе это соотношение к 1. Данный тест оценивает, насколько P близко к 1.
    Тест на одинаковые идущие подряд биты
    В тесте ищутся все последовательности одинаковых битов, а затем анализируется, насколько количество и размеры этих последовательностей соответствуют количеству и размерам истинно случайной последовательности. Смысл в том, что если смена 0 на 1 (и обратно) происходит слишом редко, то такая последовательность «не тянет» на случайную.
    2.4 Виды параметров
    Подбираемые параметры можно разделить на 3 типа: Отличные, хорошие, плохие.
    Рассмотрим каждый тип:

    Отличные
    Это параметры, полностью удовлетворяющие условиям теоремы. Все битовые тесты проходят успешно, суммарное распределение битов близко к 0.5 в каждом из двоичных разрядов.
    Достигается максимальный период, мощность >=5. Все различные числа в последовательности встречаются ровно по одному разу.Всё вышеперечисленное свидетельствует о хорошем генераторе. Пример — a = 6645; c = 2543; m = 65536

    Хорошие
    Это параметры, частично удовлетворяющие условиям теоремы.
    Все битовые тесты проходят успешно, суммарное распределение битов близко к 0.4 на 0.6 или
    0.5 в большинстве или каждом из двоичных разрядов.
    Некоторые из таких параметров можно было бы определить, как отличные, но их отличие — невозможность существования максимального периода и частота встречаемости (число может встретиться более 1 раза, а может и вообще не встретиться).
    Пример — a = 91; c = 91; m = 65536 (настоящий период равен 32768)

    Плохие
    Данный тип параметров не удовлетворяет условиям теоремы, проваливает тесты. Имеет маленький период. Суммарное количество нулей и единиц в старших двоичных разрядах сильно отличается. Последовательность визуально не выглядит случайной или вообще вырождается.
    Пример — a = 28; c = 2; m = 45.
    11
    1

    3. ВЫВОДЫ
    Линейный конгруэнтный метод довольно продуктивен и используется во многих компиляторах.
    Он порождает статистически хорошую псевдослучайную последовательность чисел, если правильно выбрать параметры для генератора. Опыты показывают, что максимальную эффективность он показывает при параметрах, удовлетворяющих условиям теоремы о макс. периоде. Если же некоторые параметры не будут удовлетворять условиям, то оценка случайности генератора останется хорошей,
    однако макс. период в этом случае будет меньше ожидаемого. При плохих параметрах ясно видна периодичная зависимость между элементами последовательности.
    Приложение
    Листинг 1:
    #include
    #include
    #include
    #include
    #define RAND_MAX 65536
    // простое ли int is_prime(int x)
    {
    if (x != 0)
    {
    for (int i = 2; i <= x / 2; i++)
    if (x % i == 0)
    return 0;
    }
    return 1;
    }
    //взаимно простые int are_both_prime(int a, int b)
    {
    while (a && b)
    {
    if (a >= b)
    a %= b;
    else b %= a;
    }
    return (a | b) == 1 ? 1 : 0;
    }
    int m = RAND_MAX, a = 1537, c = 0, x = 5289, x0;
    int ar[RAND_MAX] = { 0 };
    int b[RAND_MAX] = { 0 };
    void srand(int seed)
    {
    x = seed;
    }
    // проверка условий с int get_c()
    {
    if (c % 2 == 0 || !are_both_prime(m, c))
    return 0;
    return 1;
    }//подобрать с
    // создать параметры void cr_parameter()
    {
    m = RAND_MAX;
    a = 1 + clock() % 32767;
    c = 1 + clock() % 4096;
    printf("Теорема о макс. периоде:\n");
    printf("По усл. теоремы параметры c,m должны быть взаимно простыми\n");
    printf("По усл. теоремы а-1 должен делиться нацело на любое простое р, на которое нацело делится m\n");
    printf("По усл. теоремы а-1 должен нацело делиться на 4, если m делится нацело на 4\n");
    printf("Следствие из теоремы: a mod 8 = 5\n");
    int good_parameter = 0;
    while (!good_parameter)
    {
    c++;
    good_parameter = get_c();
    }
    11
    1

    // c podobran good_parameter = 0;
    while (good_parameter!=1)
    {
    a++;
    if (a % 8 == 5)
    good_parameter = 1;
    }
    // a podobran printf("\nа = %d, m = %d, c = %d. Эти параметры удовлетворяют условиям теоремы\n", a, m, c);
    }// сгенерировать подходящие параметры
    //true int Rand()
    {
    x = (a*x + c) % m;
    return x;
    }
    // мощность и период void period_power()
    {
    x = x0;
    int i = 1;
    printf("Последовательность с параметрами а = %d, с = %d, m = %d\n", a, c, m);
    for (i = 0; i < RAND_MAX; i++)
    {
    if (i < 100)
    printf("%d ", ar[i] = Rand());
    else ar[i] = Rand();
    }
    printf("... и ещё 65435 эл-тов");
    int freq[RAND_MAX] = { 0 };
    int period_val = RAND_MAX;
    short found = 0;
    for (i = 0; i < RAND_MAX; i++)
    {
    freq[ar[i]]++;
    if (freq[ar[i]] > 1)
    {
    period_val = i;
    for (i = 0; i < period_val; i++)
    if (ar[period_val] == ar[i])
    {
    if (ar[i] == ar[i + 1] && ar[i] == ar[i + 2])
    {
    period_val = i;
    printf("\n\nПоследовательность вырождается. %d эл. до вырождения\n", period_val);
    found = 1; break;
    }
    else if (ar[period_val + 1] == ar[i + 1] && ar[period_val +
    2] == ar[i + 2])
    {
    period_val -= i;
    printf("\n\nМаксимальный период последовательности равен %d\n", period_val);
    found = 1; break;
    }
    else
    {
    period_val = RAND_MAX;
    i = period_val + 1;
    }
    }
    }
    if (found)
    break;
    }
    double got = 0;
    double power = 0;
    while (modf(pow(a - 1, power) / m, &got) && power < 30)
    power++;
    if (!found)
    printf("\n\nМаксимальный период последовательности равен %d\n", period_val);
    11
    1
    printf( (power>=29) ? "\nМаксимальная мощность последовательности не может быть точно вычислена \n" :
    "\nМаксимальная мощность последовательности = %d", (int)power);
    printf("\nБольшая мощность не гарантирует хорошей последовательности \n");
    }
    //тесты int first_test()
    {
    float n0 = 0, n1 = 0;
    int one[15] = { 0 }; // razryadi int null[15] = { 0 };
    for (int i = 0; i < m; i++)
    {
    for (int j = 0; j < 15; j++)
    {
    if (((1 << j) & ar[i]) == 0)
    {
    n0++;
    null[j]++;
    }
    else
    {
    n1++;
    one[j]++;
    }
    }
    }
    printf("\nСуммарное кол-во 0 и 1 в двоичных разрядах по %d числам:\n", m);
    for (int i = 0; i < 15; i++)
    printf("В разряде %d число единиц равно %d, число нулей равно %d\n", i, one[i], null[i]);
    printf("\n");
    printf("В последовательности распределение единичных битов равно %lf\n", n1/(n1+n0));
    printf("В последовательности распределение нулевых битов равно %lf\n", n0/(n1+n0));
    printf("Идеальное распределение должно содержать 0.5 бит каждого вида\n");
    if (fabs(n1 / (n1 + n0) - n0/(n1+n0)) < 0.1)
    {
    printf("\nТест 1 о допустимом распределении битов в последовательности пройден\n");
    return 1;
    }
    else
    {
    printf("\nТест 1 о допустимом распределении битов в последовательности провален\n");
    return 0;
    }
    }
    int second_test()
    {
    double s = 0;
    for (int i = 0; i < 100; i++)
    {
    for (int j = 0; j < 15; j++)
    {
    if (((1 << j) & ar[i]) == 0)
    s -= 1;
    else s += 1;
    }
    }
    s = fabs(s) / sqrt(100 * 15);
    if (erfc(s / sqrt(2)) > 0.01)
    {
    printf("\nЧастотный побитовый тест 2 пройден\n");
    return 1;
    }
    else
    {
    printf("\nЧастотный побитовый тест 2 провален\n");
    return 0;
    }
    }
    int third_test()
    {
    double p = 0;
    for (int i = 0; i < m; i++)
    {
    for (int j = 0; j < 15; j++)
    {
    11
    1
    if (((1 << j) & ar[i]) != 0)
    p += 1;
    }
    }
    p /= m * 16;
    if (fabs(p - 0.5) > 2 / sqrt(p))
    {
    printf("\nТест 3 на одинаковые идущие подряд биты провален\n");
    return 0;
    }
    else
    {
    int rk;
    int Vn = 0;
    for (int i = 0; i <50; i++)
    {
    for (int j = 1; j < 16; j++)
    {
    if (((1 << j - 1) & ar[i]) != 0 && ((1 << j) & ar[i]) != 0)
    rk = 0;
    else if (((1 << j) & ar[i]) == 0 && ((1 << j - 1) & ar[i]) == 0)
    rk = 0;
    else rk = 1;
    Vn += rk;
    }
    Vn++;
    if (erfc(fabs((Vn - (2 * p*(1 - p)*m)) / (2 * p*(1 - p)*sqrt(2 * m * 16))) / 100) <
    0.01)
    {
    printf("\nТест 3 на одинаковые идущие подряд биты провален\n");
    return 0;
    }
    Vn = 0;
    }
    printf("\nТест 3 на одинаковые идущие подряд биты пройден\n");
    return 1;
    }
    }
    // запустить тест последовательности void demo()
    {
    int freq[RAND_MAX] = { 0 };
    printf("Последовательность с параметрами а = %d, с = %d, m = %d\n", a, c, m);
    for (int i = 0; i < RAND_MAX; i++)
    {
    if (i < 100)
    printf("%d ", ar[i] = Rand());
    else ar[i] = Rand();
    freq[ar[i]]++;
    }
    printf("... и ещё 65435 эл-тов");
    printf("\nПохожа ли она на случайную?\n");
    //
    int min = ar[0], max = ar[0], freq_min=-1, freq_max=-1;
    for (int i = 0; i < RAND_MAX; i++)
    if (freq[ar[i]] > freq_max )
    {
    max = ar[i];
    freq_max = freq[ar[i]];
    }
    freq_min = freq_max;
    for (int i = 0; i < RAND_MAX; i++)
    if (freq[i] < freq_min)
    {
    min = i;
    freq_min = freq[i];
    }
    printf("\nМаксимум: число %d встречается %d раз\nМинимум: число %d встречается %d раз\n", max,
    freq_max, min, freq_min);
    //printf("\n %d %d \n", max, freq_max, min, freq_min);
    //
    if (first_test(ar) && second_test(ar) && third_test(ar))
    printf("\nХороший генератор\n");
    11
    1
    else printf("\nПлохой генератор\n");
    }//проверка с тестами
    // ввести свои параметры void enter()
    {
    do printf((printf("Параметр a= "), scanf("%d", &a), a < 0 || a>RAND_MAX) ? "Недопустимое число\n" : "");
    while (a < 0 || a>RAND_MAX);
    do printf((printf("Параметр c= "), scanf("%d", &c), c < 0 || c>RAND_MAX) ? "Недопустимое число\n" : "");
    while (c < 0 || c>RAND_MAX);
    do printf((printf("Параметр m= "), scanf("%d", &m), m <= 0 || m>RAND_MAX) ? "Недопустимое число\n" :
    "");
    while (m <= 0 || m>RAND_MAX);
    do printf((printf("Параметр x0= "), scanf("%d", &x), x < 0 || x>RAND_MAX) ? "Недопустимое число\n" :
    "");
    while (x < 0 || x>RAND_MAX);
    x0 = x;
    demo();
    }//свой ввод параметров
    //
    void vivod1()
    {
    int k=0;
    do
    {
    printf("Вывести элементов: ");
    scanf("%d", &k);
    } while (k < 0 || k>RAND_MAX);
    for (int i = 0; i < k; i++)
    printf("%d\t",ar[i]);
    printf("\n");
    }
    int main()
    {
    setlocale(LC_ALL, "rus");
    enum menu { out, create, test, vvod, pp , vivod };
    //printf("%d %d\n", out, vvod);
    printf("Вас приветствует программа - генератор случайных чисел\n");
    int err = 1;
    while (1)
    {
    printf("\n\n0-Выход\n1-Сгенерировать подходящие параматры\n2-Тест параметров\n3-Тест произвольных параметров\n4-Найти макс. мощность и период\n5-Вывести эл-ты массива\n\n");
    int choose;
    scanf("%d", &choose);
    switch (choose)
    {
    case out: { return 0; }
    case create: { cr_parameter(); err = 0; break; }
    case test: { (err == 0) ? demo() : printf("Сначала нужно создать параметры генератора или ввести их вручную\n"); break; }
    case vvod: { enter(); err = 0; break; }
    case pp: { (err == 0) ? period_power() : printf("Сначала нужно создать параметры генератора или ввести их вручную\n"); break; }
    case vivod: {vivod1(); break; }
    default: { printf("Такой команды не существует\n"); break; }
    }
    }
    getchar();
    return 0;
    }
    11
    1

    11
    1


    написать администратору сайта