/// <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); }