Загрузка данных


using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace BethPiperStopAndGo
{
    /// <summary>
    /// Класс сдвигового регистра с линейной обратной связью (LFSR)
    /// </summary>
    public class Lfsr
    {
        private readonly int _length;
        private readonly int[] _taps; // Отводы (индексы от 1 до N)
        private ulong _state;

        public Lfsr(int length, int[] taps, ulong initialState = 0b1)
        {
            _length = length;
            _taps = taps;
            // Состояние не должно быть нулевым
            _state = initialState == 0 ? 1 : initialState;
        }

        /// <summary>
        /// Возвращает текущий младший (выходной) бит
        /// </summary>
        public byte OutputBit => (byte)(_state & 1);

        /// <summary>
        /// Выполняет один шаг сдвига регистра
        /// </summary>
        public byte Step()
        {
            byte outBit = (byte)(_state & 1);

            // Вычисление бита обратной связи (XOR отводов)
            ulong feedback = 0;
            foreach (int tap in _taps)
            {
                if (tap > 0) // tap == 0 соответствует константе 1 в примитивном многочлене
                {
                    feedback ^= (_state >> (_length - tap)) & 1;
                }
            }

            // Сдвиг вправо и занесение обратной связи в старший бит
            _state = (_state >> 1) | (feedback << (_length - 1));

            return outBit;
        }
    }

    /// <summary>
    /// Генератор «стоп-пошел» Бетта-Пайпера (Вариант 4)
    /// </summary>
    public class BethPiperGenerator
    {
        private readonly Lfsr _lfsr1; // (32, 7, 5, 3, 2, 1, 0)
        private readonly Lfsr _lfsr2; // (12, 6, 4, 1, 0)
        private readonly Lfsr _lfsr3; // (28, 3, 0)

        public BethPiperGenerator(ulong seed1 = 0xACE1, ulong seed2 = 0b101, ulong seed3 = 0x12345)
        {
            // Задание регистров по отводам из методички
            _lfsr1 = new Lfsr(32, new[] { 32, 7, 5, 3, 2, 1, 0 }, seed1);
            _lfsr2 = new Lfsr(12, new[] { 12, 6, 4, 1, 0 }, seed2);
            _lfsr3 = new Lfsr(28, new[] { 28, 3, 0 }, seed3);
        }

        public byte Step()
        {
            // 1. Управляющий LFSR1 сделает шаг и выдаст управление a(t)
            byte controlBit = _lfsr1.Step();

            // 2. В зависимости от a(t) тактуется либо LFSR2, либо LFSR3
            if (controlBit == 1)
            {
                _lfsr2.Step();
            }
            else
            {
                _lfsr3.Step();
            }

            // 3. Выход = XOR текущих выходов LFSR2 и LFSR3
            return (byte)(_lfsr2.OutputBit ^ _lfsr3.OutputBit);
        }

        public byte[] GenerateBits(long count)
        {
            byte[] bits = new byte[count];
            for (long i = 0; i < count; i++)
            {
                bits[i] = Step();
            }
            return bits;
        }
    }

    /// <summary>
    /// Пять основных статистических тестов на случайность
    /// </summary>
    public static class StatisticalTests
    {
        // 1. Частотный тест (одноразрядный)
        public static double FrequencyTest(byte[] s)
        {
            long n0 = s.Count(b => b == 0);
            long n1 = s.Count(b => b == 1);
            long n = s.Length;

            return Math.Pow(n0 - n1, 2) / n;
        }

        // 2. Тест на серии (двухразрядный)
        public static double SerialTest(byte[] s)
        {
            long n = s.Length;
            long n0 = s.Count(b => b == 0);
            long n1 = s.Count(b => b == 1);

            long n00 = 0, n01 = 0, n10 = 0, n11 = 0;

            for (int i = 0; i < n - 1; i++)
            {
                if (s[i] == 0 && s[i + 1] == 0) n00++;
                else if (s[i] == 0 && s[i + 1] == 1) n01++;
                else if (s[i] == 1 && s[i + 1] == 0) n10++;
                else if (s[i] == 1 && s[i + 1] == 1) n11++;
            }

            double p1 = (4.0 / (n - 1)) * (n00 * n00 + n01 * n01 + n10 * n10 + n11 * n11);
            double p2 = (2.0 / n) * (n0 * n0 + n1 * n1);

            return p1 - p2 + 1.0;
        }

        // 3. Обобщенный тест (m-разрядные блоки)
        public static double GeneralizedTest(byte[] s, int m = 3)
        {
            int n = s.Length;
            int k = n / m;
            int numPatterns = 1 << m;
            int[] counts = new int[numPatterns];

            for (int i = 0; i < k; i++)
            {
                int pattern = 0;
                for (int j = 0; j < m; j++)
                {
                    pattern = (pattern << 1) | s[i * m + j];
                }
                counts[pattern]++;
            }

            double sumSquares = counts.Sum(c => (double)c * c);
            return (numPatterns / (double)k) * sumSquares - k;
        }

        // 4. Тест на последовательности (длинные блоки/промежутки)
        public static double RunsTest(byte[] s, int k = 3)
        {
            int n = s.Length;
            int[] B = new int[k + 1]; // Блоки единиц
            int[] G = new int[k + 1]; // Промежутки нулей

            int currentType = s[0];
            int currentLen = 1;

            for (int i = 1; i < n; i++)
            {
                if (s[i] == currentType)
                {
                    currentLen++;
                }
                else
                {
                    int index = Math.Min(currentLen, k);
                    if (currentType == 1) B[index]++;
                    else G[index]++;

                    currentType = s[i];
                    currentLen = 1;
                }
            }

            double x4 = 0;
            for (int i = 1; i <= k; i++)
            {
                double e_i = (n - i + 3) / Math.Pow(2, i + 2);
                x4 += Math.Pow(B[i] - e_i, 2) / e_i;
                x4 += Math.Pow(G[i] - e_i, 2) / e_i;
            }

            return x4;
        }

        // 5. Автокорреляционный тест
        public static double AutocorrelationTest(byte[] s, int d = 8)
        {
            int n = s.Length;
            int A = 0;

            for (int i = 0; i < n - d; i++)
            {
                A += (s[i] ^ s[i + d]);
            }

            return 2.0 * (A - (n - d) / 2.0) / Math.Sqrt(n - d);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("=== Лабораторная работа №1 (Вариант 4: Бетта-Пайпера) ===");

            // Для лабораторной работы берем представительную выборку (например, N = 100 000 битов)
            int sampleSize = 100000;
            BethPiperGenerator generator = new BethPiperGenerator();

            Console.WriteLine($"Генерация последовательности из {sampleSize} битов...");
            byte[] sequence = generator.GenerateBits(sampleSize);

            // 1. Запись последовательности в файл
            string filename = "output_sequence.txt";
            File.WriteAllText(filename, string.Join("", sequence));
            Console.WriteLine($"Последовательность успешно записана в файл: {filename}");

            // 2. Расчет статистических тестов (alpha = 0.05)
            Console.WriteLine("\n=== Результаты статистического тестирования ===");

            double x1 = StatisticalTests.FrequencyTest(sequence);
            Console.WriteLine($"1. Частотный тест: X1 = {x1:F4} (Порог = 3.8415) -> {(x1 < 3.8415 ? "ПРОЙДЕН" : "ПРОВАЛЕН")}");

            double x2 = StatisticalTests.SerialTest(sequence);
            Console.WriteLine($"2. Тест на серии: X2 = {x2:F4} (Порог = 5.9915) -> {(x2 < 5.9915 ? "ПРОЙДЕН" : "ПРОВАЛЕН")}");

            double x3 = StatisticalTests.GeneralizedTest(sequence, m: 3);
            Console.WriteLine($"3. Обобщенный тест (m=3): X3 = {x3:F4} (Порог = 14.0671) -> {(x3 < 14.0671 ? "ПРОЙДЕН" : "ПРОВАЛЕН")}");

            double x4 = StatisticalTests.RunsTest(sequence, k: 3);
            Console.WriteLine($"4. Тест на последовательности: X4 = {x4:F4} (Порог = 9.4877) -> {(x4 < 9.4877 ? "ПРОЙДЕН" : "ПРОВАЛЕН")}");

            double x5 = StatisticalTests.AutocorrelationTest(sequence, d: 8);
            Console.WriteLine($"5. Автокорреляционный тест (d=8): X5 = {Math.Abs(x5):F4} (Порог = 1.9600) -> {(Math.Abs(x5) < 1.9600 ? "ПРОЙДЕН" : "ПРОВАЛЕН")}");
        }
    }
}