Факторизація цілих чисел - Блог ITVDN
ITVDN: курси програмування
Відеокурси з
програмування

    Обери свою IT спеціальність

    Підписка

    Обери свою IT спеціальність

    Підписка

      Факторизація цілих чисел

      advertisement advertisement

      Введение

      Факторизация целых чисел позволяет раскладывать на множители (факторинг) большие числа (Int64) и проверять простоту целых чисел [1,2].


      Приведем пример больших (14 ... 18-ти значных) простых чисел, которые можно использовать для тестирования или оценки.

      biggest 18-digit primes

      • 999999999999999989
      • 999999999999999967
      • 999999999999999877

      biggest 17-digit primes 

      • 99999999999999997
      • 99999999999999977
      • 99999999999999961

      biggest 16-digit primes

      • 9999999999999937
      • 9999999999999917
      • 9999999999999887

      biggest 15-digit primes

      • 999999999999989
      • 999999999999947
      • 999999999999883

      biggest 14-digit primes

      • 99999999999973
      • 99999999999971
      • 99999999999959

      Кодовый модуль демонстрирует практическое использование алгоритма, написанного в C# (4.0).

      using System;

      using System.Collections.Generic;

      namespace Infosoft.MathShared

      {

             ///

      Integers: Properties and Operations

             public  static partial class Integers

             {

      #region Prime Numbers <100

                   private static readonly int[] Primes =

                   new int[] { 2, 3, 5, 7, 11, 13, 17, 19, 23,

                   29, 31, 37, 41, 43, 47, 53, 59,

                   61, 67, 71, 73, 79, 83, 89, 97 };

      #endregion

                   // starting number for iterative factorization

                   private const int _startNum = 101;

      #region IsPrime : primality Check

                   ///

                   /// Check if the number is Prime

                   ///

                   /// Int64

                   /// bool

                   public static bool IsPrime(Int64 Num){

                          int j;

                          bool ret;

                          Int64 _upMargin = (Int64)Math.Sqrt(Num) + 1;;

                          // Check if number is in Prime Array

                          for (int i = 0; i < Primes.Length; i++){

                                 if (Num == Primes[i]) { return true; }

                          }

                          // Check divisibility w/Prime Array

                          for (int i = 0; i < Primes.Length; i++) {

                                 if (Num % Primes[i] == 0) return false;

                          }

                          // Main iteration for Primality check

                          _upMargin = (Int64)Math.Sqrt(Num) + 1;

                          j = _startNum;

                          ret = true;

                          while (j <= _upMargin)

                          {

                                 if (Num % j == 0) { ret = false; break; }

                                 else { j = j + 2; }

                          }

                          return ret;

                   }

                   ///

                   /// Check if number-string is Prime

                   ///

                   /// string

                   /// bool

                   public static bool IsPrime(string StringNum) {

                          return IsPrime(Int64.Parse(StringNum));

                   }

      #endregion

      #region Fast Factorization

                   ///

                   /// Factorize string converted to long integers

                   ///

                   /// string

                   /// Int64[]

                   public static Int64[] FactorizeFast(string StringNum) {

                          return FactorizeFast(Int64.Parse(StringNum));

                   }

                   ///

                   /// Factorize long integers: speed optimized

                   ///

                   /// Int64

                   /// Int64[]

                   public static Int64[] FactorizeFast(Int64 Num)

                   {

      #region vars

                          // list of Factors

                          List _arrFactors = new List();

                          // temp variable

                          Int64 _num = Num;

      #endregion

      #region Check if the number is Prime(<100)

                          for (int k = 0; k < Primes.Length; k++)

                          {

                                 if (_num == Primes[k])

                                 {

                                        _arrFactors.Add(Primes[k]);

                                        return _arrFactors.ToArray();

                                 }

                          }

      #endregion

      #region Try to factorize using Primes Array

                          for (int k = 0; k < Primes.Length; k++)

                          {

                                 int m = Primes[k];

                                 if (_num < m) break;

                                 while (_num % m == 0)

                                 {

                                        _arrFactors.Add(m);

                                        _num = (Int64)_num / m;

                                 }

                          }

                          if (_num < _startNum)

                          {

                                 _arrFactors.Sort();

                                 return _arrFactors.ToArray();

                          }

      #endregion

      #region Main Factorization Algorithm

                          Int64 _upMargin = (Int64)Math.Sqrt(_num) + 1;

                          Int64 i = _startNum;

                          while (i <= _upMargin)

                          {

                                 if (_num % i == 0)

                                 {

                                        _arrFactors.Add(i);

                                        _num = _num / i;

                                        _upMargin = (Int64)Math.Sqrt(_num) + 1;

                                        i = _startNum;

                                 }

                                 else { i = i + 2; }

                          }

                          _arrFactors.Add(_num);

                          _arrFactors.Sort();

                          return _arrFactors.ToArray();

      #endregion

                   }

      #endregion

             }

      }

      Точки обзора

      Тест на проверку простоты 18-ти значного числа (999999999999999989), т.е. процедура, которая определяет, являются ли целые числа простыми, это лучший способ проверки факторинга программного обеспечения. Если вычисления занимают слишком много времени (например, когда используется мобильная платформа с низким уровнем обработки большого количества численных данных), возьмите меньшее число, но тоже 18-ти значное: 324632623645234523.

      Чтобы получить не такую тривиальную запись, как i = i + 2, или i + = 2, необходимо исходный код увеличить в два раза.

      i ++; i ++;

      Даный фрагмент кода был использован для сравнения производительности трех методов возрастания целых чисел: 

      using System;

      using System.Diagnostics;

      namespace IncrementEfficiencyTest

      {

             class Program

             {

                   private const Int64 _max = 1000000000; // 1 billion

                   private const int _cycles = 5;

                   static void Main(string[] args)

                   {

                          Stopwatch sw = new Stopwatch();

                          Console.Write("{0} on {1}", "i++;i++:", String.Concat(_cycles, " cycles with ", _max, " max: "));

                          sw.Restart();

                          for (int count = 0; count < _cycles; count++)

                          {

                                 Int64 i = 0;

                                 while (i < _max) { i++; i++; }

                          }

                          sw.Stop();

                          Console.WriteLine("{0} elapsed.", sw.Elapsed);

                          Console.Write("{0} on {1}", "i=i+2", String.Concat(_cycles, " cycles with ", _max, " max: "));

                          sw.Restart();

                          for (int count = 0; count < _cycles; count++)

                          {

                                 Int64 i = 0;

                                 while (i < _max) { i = i + 2; }

                          }

                          sw.Stop();

                          Console.WriteLine("{0} elapsed.", sw.Elapsed);

                          Console.Write("{0} on {1}", "i+=2", String.Concat(_cycles, " cycles with ", _max, " max: "));

                          sw.Restart();

                          for (int count = 0; count < _cycles; count++)

                          {

                                 Int64 i = 0;

                                 while (i < _max)  { i += 2; }

                          }

                          sw.Stop();

                          Console.WriteLine("{0} elapsed.", sw.Elapsed);

                          Console.ReadKey();

                   }

             }

      Чтобы минимизировать потенциальные побочные эффекты теста, следует работать в нескольких циклах (5 циклов) с последующей апроксимацией нескольких результатов тестирования и не нужно реализовывать вызовы функций , потому что оценка синхронизации может искажаться. Основываясь на статистических данных, самый быстрый способ увеличения числа Int64 в 2 раза можно достичь через составленное уравнение: i = i + 2 (5,589 сек для всей процедуры тестирования), вместе с i + = 2 (5,625 сек) и удвоением и ++; i ++;  "leading from behind" с оценкой производительности в 11,907 сек. Соответствующая поправка была сделана в факторизации первичных чисел (теперь выводится i = i + 2).

      Параллельный алгоритм для факторинг-теста

      При использовании параллельных алгоритмов факторизации можно значительно увеличить производительность теста.

      Параллельне алгоритмы факторизации

      region GetFirstFactorParallel(Int64 Num) algorithm

      internal static Int64 GetFirstFactorParallel(Int64 Num)

      {

             // use concurrent stack to store non-trivial factor if found

             ConcurrentStack _stack = new ConcurrentStack();

             // object to specify degrees of parallelism

             ParallelOptions _po = new ParallelOptions();

             try

             {

                   // return value initially set to 1

                   Int64 _ret = 1;

                   // step 1: try to factor on base 2, return if OK

                   if (Num % 2 == 0) return 2;

                   // step 2: try to factor on base 3, return if OK

                   if (Num % 3 == 0) return 3;

      #region parallel algo to find first non - trivial factor if exists

                   // set upper limit

                   Int64 _upMargin = (Int64)Math.Sqrt(Num) + 1;

                   // number of CPU cores

                   int _countCPU = System.Environment.ProcessorCount;

                   // max degree of parallelism set equal to _cpuCount

                   _po.MaxDegreeOfParallelism = _countCPU;

                   Parallel.For(0, 2, _po, (i, _plState) = >

                   {

                          // starting number for inner loops (5 and 7)

                          int _seed = 5 + 2 * i;

                          // inner loops running in parallel;

                          // notice that because input Num was already tested for factors 2 and 3,

                          // then increment of 6 is used to speed up the processing,

                          // thus in dual core CPU it looks like:

                          // 5, 11, 17, 23, 29, etc. in first thread

                          // 7, 13, 19, 25, 31, etc, in second thread

                          for (Int64 j = _seed; j < _upMargin; j += 6)

                          {

                                 // exit loop if stack contains value

                                 if (_stack.Count != 0) { break; }

                                 // check divisibility

                                 if (Num % j == 0)

                                 {

                                        // push non-trivial factor to ConcurrentStack and exit loop

                                        if (_stack.Count == 0) { _stack.Push(j); }

                                        break;

                                 }

                          }

                   });

      #endregion

                   // return the value in ConcurrentStack if exists, or 1

                   return (_stack.TryPop(out _ret)) ? _ret : 1;

             }

             catch { throw; }

             finally { _po = null; _stack = null; }

      }

      #endregion

      Источник: http://www.codeproject.com/Tips/155308/Fast-Prime-Factoring-Algorithm

      КОМЕНТАРІ ТА ОБГОВОРЕННЯ
      advertisement advertisement

      Купуй передплатуз доступом до всіх курсів та сервісів

      Бібліотека сучасних IT знань у зручному форматі

      Вибирай свій варіант підписки залежно від завдань, що стоять перед тобою. Але якщо потрібно пройти повне навчання з нуля до рівня фахівця, краще вибирати Базовий або Преміум. А для того, щоб вивчити 2-3 нові технології, або повторити знання, готуючись до співбесіди, підійде Пакет Стартовий.

      Стартовий
      • Усі відеокурси на 3 місяці
      • Тестування з 10 курсів
      • Перевірка 5 домашніх завдань
      • Консультація з тренером 30 хв
      59.99 $
      Придбати
      Базовий
      • Усі відеокурси на 6 місяців
      • Тестування з 16 курсів
      • Перевірка 10 домашніх завдань
      • Консультація з тренером 60 хв
      89.99 $
      Придбати
      Преміум
      • Усі відеокурси на 1 рік
      • Тестування з 24 курсів
      • Перевірка 20 домашніх завдань
      • Консультація з тренером 120 хв
      169.99 $
      Придбати
      Notification success
      Ми використовуємо cookie-файли, щоб зробити взаємодію з нашими веб-сайтами та послугами простою та значущою.