Beispiel #1
0
        /// <summary>
        ///     Осуществляет решение линейного сравнения.
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="m"></param>
        /// <param name="Result"></param>
        /// <param name="GCD"></param>
        /// <returns></returns>
        public static bool Solve(BigInteger a, BigInteger b, BigInteger m, out LinearComparison Result,
                                 BigInteger[] GCD = null)
        {
            //ax=b(mod m)

            Result = null;
            if (GCD == null)
            {
                GCD = AdvancedEuclidsalgorithm.GCD(a, m);
            }
            if (GCD == null)
            {
                return(false);
            }
            if (b % GCD[0] != 0)
            {
                return(false);
            }
            //a*x0=d(mod m)
            BigInteger x_ = GCD[1] * (b / GCD[0]);

            while (x_ >= m / GCD[0])
            {
                x_ -= m / GCD[0];
            }
            while (x_ < 0)
            {
                x_ += m / GCD[0];
            }
            Result = new LinearComparison(x_, m / GCD[0]);
            return(true);
        }
            /// <summary>
            ///     Тест Соловея-Штрассена. Имеет числа КарлМайкла
            /// </summary>
            /// <param name="source">Число, которое необходмио протестировать</param>
            /// <param name="count">Число прогонов теста</param>
            /// <returns></returns>
            public static PrimalityTestResult SSPT(BigInteger source, BigInteger count)
            {
                if (count >= source)
                {
                    throw new InvalidOperationException("Число прогонов теста не должно быть меньше тестируемого числа.");
                }
                if (source == 0)
                {
                    return(PrimalityTestResult.Composite);
                }
                if (source == 1)
                {
                    return(PrimalityTestResult.Unknown);
                }

                if (source < 0 || count <= 0)
                {
                    throw new InvalidOperationException(
                              "Тестируемое число и число его прогонов должны быть положительными числами!");
                }

                //нам необходимо, чтобы число было нечетным, поэтому мы отсеиваем все четные числа.
                if (source % 2 == 0)
                {
                    return(PrimalityTestResult.Composite);
                }
                BigInteger[] RestVariants = RD.UniformDistribution(2, source - 1, count);
                //отрезок [2,n-1]
                for (int i = 0; i < count; i++)
                {
                    BigInteger CurrentValue = RestVariants[i];
                    if (AdvancedEuclidsalgorithm.GCDResult(CurrentValue, source) != 1)
                    {
                        return(PrimalityTestResult.Composite);
                    }
                    //значение символа якоби
                    BigInteger jacobi = JacobiSymbol.Get(CurrentValue, source);
                    Comparison.LinearComparison comparison = new Comparison.LinearComparison(CurrentValue, source);
                    if (Comparison.MultiplicativeInverse.BinaryPowLinearComparison(comparison, (source - 1) / 2).LeastModulo != jacobi)
                    {
                        return(PrimalityTestResult.Composite);
                    }
                }

                return(PrimalityTestResult.Unknown);
            }
        /// <summary>
        ///     Метод, осуществляющий попытку решить Диофантово уравнение первой степени.
        /// </summary>
        /// <param name="Source"></param>
        /// <param name="Resultx"></param>
        /// <param name="Resulty"></param>
        /// <param name="GCD"></param>
        /// <returns></returns>
        public static bool TrySolve(BigInteger[] Source, out BigInteger[] Resultx, out BigInteger[] Resulty,
                                    BigInteger[] GCD = null)
        {
            BigInteger First  = Source[0];
            BigInteger Second = Source[1];
            BigInteger Res    = Source[2];


            Resultx = new BigInteger[2];
            Resulty = new BigInteger[2];
            if (GCD == null)
            {
                GCD = AdvancedEuclidsalgorithm.GCD(First, Second);
            }
            if (GCD == null)
            {
                return(false);
            }
            if (Res % GCD[0] != 0)
            {
                return(false);
            }

            Resultx = new[] { GCD[1] * (Res / GCD[0]), Second / GCD[0] };
            Resulty = new[] { GCD[2] * (Res / GCD[0]), -(First / GCD[0]) };
            //Надо сделать решение наименьшим по модулю, но
            //Это возможно только когда оба свободных члена уменьшаются
            //по модулю при свободном t

            while (BigInteger.Abs(Resultx[0] + Resultx[1]) < BigInteger.Abs(Resultx[0]) &&
                   BigInteger.Abs(Resulty[0] + Resulty[1]) < BigInteger.Abs(Resulty[0]))
            {
                Resultx[0] += Resultx[1];
                Resulty[0] += Resulty[1];
            }

            while (BigInteger.Abs(Resultx[0] - Resultx[1]) < BigInteger.Abs(Resultx[0]) &&
                   BigInteger.Abs(Resulty[0] - Resulty[1]) < BigInteger.Abs(Resulty[0]))
            {
                Resultx[0] -= Resultx[1];
                Resulty[0] -= Resulty[1];
            }

            return(true);
        }
            /// <summary>
            ///     Fermat Primality Test - тест на основе теоремы Ферма. Имеет псевдопростые числа
            /// </summary>
            /// <param name="source">Число, которое необходимо проверить на простотоу</param>
            /// ///
            /// <param name="count">Число прогонов теста. Чем больше, тем точнее ответ.</param>
            /// <returns></returns>
            /// <exception cref="InvalidOperationException"></exception>
            public static PrimalityTestResult FPT(int source, int count)
            {
                if (count >= source)
                {
                    throw new InvalidOperationException("Число прогонов теста должно быть меньше тестируемого числа.");
                }
                switch (source)
                {
                case 0:
                    return(PrimalityTestResult.Composite);

                case 1:
                    throw new InvalidOperationException("Единица не является ни простым, ни составным числом.");
                }

                if (source < 0 || count <= 0)
                {
                    throw new InvalidOperationException(
                              "Тестируемое число и количество прогонов должны быть положительными числами!");
                }

                BigInteger[] RestVariants = RD.UniformDistribution(2, source - 1, count);
                //отрезок [2,n-1]
                for (int i = 1; i <= count; i++)
                {
                    BigInteger CurrentValue = RestVariants[i - 1];
                    if (AdvancedEuclidsalgorithm.GCDResult(CurrentValue, source) != 1)
                    {
                        return(PrimalityTestResult.Composite);
                    }
                    Comparison.LinearComparison comparison = new Comparison.LinearComparison(CurrentValue, source);
                    if (Comparison.MultiplicativeInverse.BinaryPowLinearComparison(comparison, source - 1).A != 1)
                    {
                        return(PrimalityTestResult.Composite);
                    }
                }

                return(PrimalityTestResult.Unknown);
            }
            /// <summary>
            ///     Тест Рабина Миллера. Имеет сильно псевдопростые числа
            /// </summary>
            /// <param name="source"></param>
            /// <param name="count"></param>
            /// <returns></returns>
            public static PrimalityTestResult MRPT(int source, int count)
            {
                if (count >= source)
                {
                    throw new InvalidOperationException("Число прогонов теста не должно быть меньше тестируемого числа.");
                }
                switch (source)
                {
                case 0:
                    return(PrimalityTestResult.Composite);

                case 1:
                    throw new InvalidOperationException("Единица не является ни простым, ни составным числом.");
                }

                if (source < 0 || count <= 0)
                {
                    throw new InvalidOperationException(
                              "Тестируемое число и число его прогонов должны быть положительными числами!");
                }

                //нам необходимо, чтобы число было нечетным, поэтому мы отсеиваем все четные числа.
                if (source % 2 == 0)
                {
                    return(PrimalityTestResult.Composite);
                }
                int t = source - 1;
                int s = 0;

                while (t % 2 == 0)
                {
                    t /= 2;
                    s++;
                }
                //n-1 = (2^s) * t


                BigInteger[] RestVariants = RD.UniformDistribution(2, source - 1, count);
                //отрезок [2,n-1]
                for (int i = 0; i < count; i++)
                {
                    BigInteger CurrentValue = RestVariants[i];
                    if (AdvancedEuclidsalgorithm.GCDResult(CurrentValue, source) != 1)
                    {
                        return(PrimalityTestResult.Composite);
                    }
                    //значение символа якоби
                    Comparison.LinearComparison comparison = new Comparison.LinearComparison(CurrentValue, source);
                    if (BigInteger.Abs((comparison = Comparison.MultiplicativeInverse.BinaryPowLinearComparison(comparison, t))
                                       .LeastModulo) == 1)
                    {
                        continue;
                    }

                    while (s != 1)
                    {
                        comparison = Comparison.MultiplicativeInverse.BinaryPowLinearComparison(comparison, 2);
                        if (comparison.LeastModulo == -1)
                        {
                            break;
                        }
                        if (--s == 0)
                        {
                            return(PrimalityTestResult.Composite);
                        }
                    }
                }

                return(PrimalityTestResult.Unknown);
            }