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


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ConsoleApplication3
{
    class Program
    {
        // Функция LFSR: возвращает [выходной_бит, новое_состояние]
        static uint[] LFSR(uint reg, int[] shift)
        {
            uint xor = reg & 1;
            uint o = xor;
            for (int i = shift.Length - 2; i >= 0; i--)
            {
                xor ^= (reg >> shift[i]) & 1;
            }
            reg = (reg >> 1) | (xor << shift[0]);
            return new uint[] { o, reg };
        }

        // Функция большинства для генератора Геффа
        static bool Geffe(uint b1, uint b2, uint b3)
        {
            bool x1 = (b1 & 1) == 1;
            bool x2 = (b2 & 1) == 1;
            bool x3 = (b3 & 1) == 1;
            return (x1 & x2) ^ (x1 & x3) ^ (x2 & x3);
        }

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

            // Инициализация регистров (вариант 1)
            uint reg1 = 43949;          // 16-битный
            uint reg2 = 181;            // 8-битный
            uint reg3 = 3613104981;     // 32-битный

            // Отводные последовательности
            int[] shifts1 = new int[5] { 15, 5, 3, 2, 0 };   // (16,5,3,2,0)
            int[] shifts2 = new int[4] { 7, 4, 3, 2, 0 };    // (8,4,3,2,0)
            int[] shifts3 = new int[5] { 31, 7, 6, 2, 0 };   // (32,7,6,2,0)

            // Периоды LFSR
            long period1 = (1L << 16) - 1;  // 65535
            long period2 = (1L << 8) - 1;   // 255
            long period3 = (1L << 32) - 1;  // 4294967295
            
            // Период генератора Геффа = НОК(period1, period2, period3)
            long totalPeriod = Lcm(Lcm(period1, period2), period3);
            Console.WriteLine("Теоретический период: " + totalPeriod + " бит");

            // Генерируем 1 000 000 бит (или меньше, если период меньше)
            int n = (int)Math.Min(totalPeriod, 1000000);
            Console.WriteLine("Генерируем " + n + " бит...");

            bool[] seq = new bool[n];
            for (int i = 0; i < n; i++)
            {
                // Получаем выходные биты
                uint[] rez1 = LFSR(reg1, shifts1);
                uint[] rez2 = LFSR(reg2, shifts2);
                uint[] rez3 = LFSR(reg3, shifts3);
                
                reg1 = rez1[1];
                reg2 = rez2[1];
                reg3 = rez3[1];

                // Выход генератора Геффа
                seq[i] = Geffe(rez1[0], rez2[0], rez3[0]);
            }

            Console.WriteLine("Генерация завершена. Запуск тестов...\n");

            // ============ СТАТИСТИЧЕСКИЕ ТЕСТЫ ============

            Console.WriteLine("=== СТАТИСТИЧЕСКИЕ ТЕСТЫ (α=0.05) ===\n");

            // 1. Частотный тест
            int n0 = seq.Count(x => !x);
            int n1 = n - n0;
            double X1 = (double)((n0 - n1) * (n0 - n1)) / n;
            double chi1 = 3.8415;
            Console.WriteLine("1. Частотный тест:");
            Console.WriteLine("   X1 = " + X1.ToString("F4") + ", порог = " + chi1);
            Console.WriteLine("   Результат: " + (X1 <= chi1 ? "ПРОЙДЕН ✓" : "НЕ ПРОЙДЕН ✗") + "\n");

            // 2. Тест на серии (двухразрядный)
            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 X2 = 4.0 / (n - 1) * (n00 * n00 + n01 * n01 + n10 * n10 + n11 * n11) 
                        - 2.0 / n * (n0 * n0 + n1 * n1) + 1;
            double chi2 = 5.9915;
            Console.WriteLine("2. Тест на серии:");
            Console.WriteLine("   X2 = " + X2.ToString("F4") + ", порог = " + chi2);
            Console.WriteLine("   Результат: " + (X2 <= chi2 ? "ПРОЙДЕН ✓" : "НЕ ПРОЙДЕН ✗") + "\n");

            // 3. Обобщенный тест (m=3)
            int m = 3;
            int k = n / m;
            if (k < 5 * (1 << m))
            {
                Console.WriteLine("3. Обобщенный тест: недостаточно данных\n");
            }
            else
            {
                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];
                double X3 = (double)patterns / k * sum - k;
                double chi3 = 14.0671;
                Console.WriteLine("3. Обобщенный тест (m=3):");
                Console.WriteLine("   X3 = " + X3.ToString("F4") + ", порог = " + chi3);
                Console.WriteLine("   Результат: " + (X3 <= chi3 ? "ПРОЙДЕН ✓" : "НЕ ПРОЙДЕН ✗") + "\n");
            }

            // 4. Тест на последовательности
            int K = 0;
            for (int i = 1; ; i++)
            {
                double e = (n - i + 3) / Math.Pow(2, i + 2);
                if (e < 5) break;
                K = i;
            }
            K = Math.Min(K, 10);
            
            double X4 = 0;
            for (int i = 1; i <= K; i++)
            {
                double e = (n - i + 3) / Math.Pow(2, i + 2);
                
                // Блоки (единицы)
                int blocks = 0, runLen = 0;
                for (int j = 0; j < n; j++)
                {
                    if (seq[j]) runLen++;
                    else { if (runLen == i) blocks++; runLen = 0; }
                }
                if (runLen == i) blocks++;
                
                // Промежутки (нули)
                int gaps = 0;
                runLen = 0;
                for (int j = 0; j < n; j++)
                {
                    if (!seq[j]) runLen++;
                    else { if (runLen == i) gaps++; runLen = 0; }
                }
                if (runLen == i) gaps++;
                
                X4 += (blocks - e) * (blocks - e) / e;
                X4 += (gaps - e) * (gaps - e) / e;
            }
            double chi4 = 9.4877;
            Console.WriteLine("4. Тест на последовательности:");
            Console.WriteLine("   X4 = " + X4.ToString("F4") + ", порог = " + chi4);
            Console.WriteLine("   Результат: " + (X4 <= chi4 ? "ПРОЙДЕН ✓" : "НЕ ПРОЙДЕН ✗") + "\n");

            // 5. Автокорреляционный тест
            int d = n / 4;
            if (d < 1) d = 1;
            if (n - d >= 10)
            {
                int A = 0;
                for (int i = 0; i < n - d; i++)
                {
                    if (seq[i] != seq[i + d]) A++;
                }
                double X5 = 2 * (A - (double)(n - d) / 2) / Math.Sqrt(n - d);
                double threshold = 1.96;
                Console.WriteLine("5. Автокорреляционный тест (d=" + d + "):");
                Console.WriteLine("   X5 = " + X5.ToString("F4") + ", порог = " + threshold);
                Console.WriteLine("   Результат: " + (Math.Abs(X5) <= threshold ? "ПРОЙДЕН ✓" : "НЕ ПРОЙДЕН ✗") + "\n");
            }
            else
            {
                Console.WriteLine("5. Автокорреляционный тест: n-d < 10, не применим\n");
            }

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

        // НОД
        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;
        }
    }
}