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


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

namespace Lab1_LFSR_Geffa
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.OutputEncoding = Encoding.UTF8;

            // Параметры для генератора Геффа (вариант 1)
            // LFSR1: (16,5,3,2,0)
            // LFSR2: (8,4,3,2,0)  
            // LFSR3: (32,7,6,2,0)

            var taps1 = new int[] { 16, 5, 3, 2, 0 };
            var taps2 = new int[] { 8, 4, 3, 2, 0 };
            var taps3 = new int[] { 32, 7, 6, 2, 0 };

            LFSR lfsr1 = new LFSR(taps1);
            LFSR lfsr2 = new LFSR(taps2);
            LFSR lfsr3 = new LFSR(taps3);

            GeffaGenerator geffa = new GeffaGenerator(lfsr1, lfsr2, lfsr3);

            // Определяем период = LCM(периодов LFSR)
            long period1 = (1L << taps1[0]) - 1; // 2^16 - 1
            long period2 = (1L << taps2[0]) - 1; // 2^8 - 1
            long period3 = (1L << taps3[0]) - 1; // 2^32 - 1
            long totalPeriod = Lcm(Lcm(period1, period2), period3);
            Console.WriteLine($"Теоретический период генератора: {totalPeriod} бит");
            Console.WriteLine($"Практически будет сгенерировано: {Math.Min(totalPeriod, 1000000)} бит (для тестов)");

            // Генерируем последовательность (для тестов берем 1 000 000 бит или период, если меньше)
            int n = (int)Math.Min(totalPeriod, 1000000);
            bool[] sequence = new bool[n];
            for (int i = 0; i < n; i++)
            {
                sequence[i] = geffa.NextBit();
            }

            // Запись в файл (бинарный)
            string fileName = "sequence_geffa.bin";
            using (FileStream fs = new FileStream(fileName, FileMode.Create))
            {
                byte[] bytes = new byte[(n + 7) / 8];
                for (int i = 0; i < n; i++)
                {
                    if (sequence[i])
                    {
                        bytes[i / 8] |= (byte)(1 << (7 - (i % 8)));
                    }
                }
                fs.Write(bytes, 0, bytes.Length);
            }
            Console.WriteLine($"Последовательность записана в файл {fileName}");

            // Статистические тесты
            Console.WriteLine("\n=== РЕЗУЛЬТАТЫ СТАТИСТИЧЕСКИХ ТЕСТОВ ===");
            Console.WriteLine($"Уровень значимости α = 0.05");

            // 1. Частотный тест
            double X1 = FrequencyTest(sequence);
            double chi1 = 3.8415; // χ²(1, 0.95)
            Console.WriteLine($"1. Частотный тест: X1 = {X1:F4}, порог = {chi1:F4} => {(X1 <= chi1 ? "ПРОЙДЕН" : "НЕ ПРОЙДЕН")}");

            // 2. Тест на серии
            double X2 = SeriesTest(sequence);
            double chi2 = 5.9915; // χ²(2, 0.95)
            Console.WriteLine($"2. Тест на серии: X2 = {X2:F4}, порог = {chi2:F4} => {(X2 <= chi2 ? "ПРОЙДЕН" : "НЕ ПРОЙДЕН")}");

            // 3. Обобщенный тест (m=3)
            double X3 = GeneralizedTest(sequence, 3);
            double chi3 = 14.0671; // χ²(7, 0.95)
            Console.WriteLine($"3. Обобщенный тест (m=3): X3 = {X3:F4}, порог = {chi3:F4} => {(X3 <= chi3 ? "ПРОЙДЕН" : "НЕ ПРОЙДЕН")}");

            // 4. Тест на последовательности
            double X4 = RunsTest(sequence);
            double chi4 = 9.4877; // χ²(4, 0.95)
            Console.WriteLine($"4. Тест на последовательности: X4 = {X4:F4}, порог = {chi4:F4} => {(X4 <= chi4 ? "ПРОЙДЕН" : "НЕ ПРОЙДЕН")}");

            // 5. Автокорреляционный тест (d = n/4)
            int d = n / 4;
            if (d < 1) d = 1;
            if (n - d >= 10)
            {
                double X5 = AutocorrelationTest(sequence, d);
                double threshold = 1.96; // N(0,1) при α=0.05
                Console.WriteLine($"5. Автокорреляционный тест (d={d}): X5 = {X5:F4}, порог = {threshold:F4} => {(Math.Abs(X5) <= threshold ? "ПРОЙДЕН" : "НЕ ПРОЙДЕН")}");
            }
            else
            {
                Console.WriteLine($"5. Автокорреляционный тест: n-d = {n-d} < 10, тест не применим");
            }

            Console.WriteLine("\nНажмите любую клавишу для выхода...");
            Console.ReadKey();
        }

        // LFSR класс
        class LFSR
        {
            private uint state;
            private int n;
            private int[] taps;

            public LFSR(int[] tapPositions)
            {
                taps = tapPositions;
                n = taps[0];
                state = 1; // инициализация
                // Убедимся, что состояние не нулевое
                if (n >= 32) state = 0xAAAAAAAA;
            }

            public bool NextBit()
            {
                uint newBit = 0;
                // XOR всех отводных битов
                foreach (int tap in taps)
                {
                    if (tap != n) // последний элемент всегда 0 (выходной бит)
                    {
                        newBit ^= (state >> (tap - 1)) & 1;
                    }
                }
                // Сдвиг вправо, новый бит становится старшим
                state = (state >> 1) | (newBit << (n - 1));
                // Возвращаем младший бит (выход)
                return (state & 1) == 1;
            }

            public void Reset()
            {
                state = 1;
            }
        }

        // Генератор Геффа
        class GeffaGenerator
        {
            private LFSR lfsr1, lfsr2, lfsr3;

            public GeffaGenerator(LFSR a, LFSR b, LFSR c)
            {
                lfsr1 = a;
                lfsr2 = b;
                lfsr3 = c;
            }

            public bool NextBit()
            {
                bool x1 = lfsr1.NextBit();
                bool x2 = lfsr2.NextBit();
                bool x3 = lfsr3.NextBit();
                // Функция большинства
                return (x1 & x2) ^ (x1 & x3) ^ (x2 & x3);
            }

            public void Reset()
            {
                lfsr1.Reset();
                lfsr2.Reset();
                lfsr3.Reset();
            }
        }

        // Вспомогательные функции для тестов

        // НОД
        static long Gcd(long a, long b)
        {
            while (b != 0)
            {
                long temp = b;
                b = a % b;
                a = temp;
            }
            return a;
        }

        // НОК
        static long Lcm(long a, long b)
        {
            return a / Gcd(a, b) * b;
        }

        // 1. Частотный тест
        static double FrequencyTest(bool[] seq)
        {
            int n = seq.Length;
            int n0 = seq.Count(b => !b);
            int n1 = n - n0;
            return (double)((n0 - n1) * (n0 - n1)) / n;
        }

        // 2. Тест на серии (двухразрядный)
        static double SeriesTest(bool[] seq)
        {
            int n = seq.Length;
            if (n < 21) return 0;

            int n0 = seq.Count(b => !b);
            int n1 = n - n0;

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

            double sum = n00 * n00 + n01 * n01 + n10 * n10 + n11 * n11;
            double val = (4.0 / (n - 1)) * sum - (2.0 / n) * (n0 * n0 + n1 * n1) + 1;
            return val;
        }

        // 3. Обобщенный тест (m=3)
        static double GeneralizedTest(bool[] seq, int m)
        {
            int n = seq.Length;
            int k = n / m;
            if (k < 5 * (1 << m)) return 0;

            int patterns = 1 << m;
            int[] counts = new int[patterns];
            for (int i = 0; i < k; i++)
            {
                int idx = 0;
                for (int j = 0; j < m; j++)
                {
                    idx = (idx << 1) | (seq[i * m + j] ? 1 : 0);
                }
                counts[idx]++;
            }

            double sum = 0;
            for (int i = 0; i < patterns; i++)
            {
                sum += counts[i] * counts[i];
            }
            return (double)(patterns) / k * sum - k;
        }

        // 4. Тест на последовательности (Runs test)
        static double RunsTest(bool[] seq)
        {
            int n = seq.Length;
            // Определяем k - максимальное i, для которого e_i >= 5
            int k = 1;
            while (true)
            {
                double e = (n - k + 3) / Math.Pow(2, k + 2);
                if (e < 5) break;
                k++;
            }
            k = Math.Min(k, 10); // ограничим для производительности

            double result = 0;
            for (int i = 1; i <= k; i++)
            {
                double e = (n - i + 3) / Math.Pow(2, i + 2);
                int blocks = 0, gaps = 0;

                // Подсчет блоков (единиц) длины i
                int runLen = 0;
                for (int j = 0; j < n; j++)
                {
                    if (seq[j])
                    {
                        runLen++;
                    }
                    else
                    {
                        if (runLen == i) blocks++;
                        runLen = 0;
                    }
                }
                if (runLen == i) blocks++;

                // Подсчет промежутков (нулей) длины i
                runLen = 0;
                for (int j = 0; j < n; j++)
                {
                    if (!seq[j])
                    {
                        runLen++;
                    }
                    else
                    {
                        if (runLen == i) gaps++;
                        runLen = 0;
                    }
                }
                if (runLen == i) gaps++;

                result += (blocks - e) * (blocks - e) / e;
                result += (gaps - e) * (gaps - e) / e;
            }
            return result;
        }

        // 5. Автокорреляционный тест
        static double AutocorrelationTest(bool[] seq, int d)
        {
            int n = seq.Length;
            if (n - d < 10) return 0;

            int A = 0;
            for (int i = 0; i < n - d; i++)
            {
                if (seq[i] != seq[i + d]) A++;
            }
            return 2 * (A - (double)(n - d) / 2) / Math.Sqrt(n - d);
        }
    }
}