libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
factoring.hpp
Go to the documentation of this file.
1 #ifndef LIBJMMCG_CORE_FACTORING_HPP
2 #define LIBJMMCG_CORE_FACTORING_HPP
3 
4 /******************************************************************************
5 ** Copyright © 1993 by J.M.McGuiness, coder@hussar.me.uk
6 **
7 ** This library is free software; you can redistribute it and/or
8 ** modify it under the terms of the GNU Lesser General Public
9 ** License as published by the Free Software Foundation; either
10 ** version 2.1 of the License, or (at your option) any later version.
11 **
12 ** This library is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 ** Lesser General Public License for more details.
16 **
17 ** You should have received a copy of the GNU Lesser General Public
18 ** License along with this library; if not, write to the Free Software
19 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21 
22 #include "gcd.hpp"
24 
25 #include <set>
26 #include <vector>
27 
28 namespace jmmcg { namespace LIBJMMCG_VER_NAMESPACE { namespace factoring {
29 
30 using collection_type=std::vector<unsigned long>;
31 
32 /// Factoring by division.
33 /**
34  * \param x The number to be factored. Must be greater than zero.
35  * \return The array that has the factors placed in it.
36  *
37  * Thanks to Knuth, et al for this routine. See his book "Seminumerical Algorithms. Vol 2".
38  *
39  * \see factoring::monte_carlo()
40  */
41 inline collection_type __fastcall
42 division(const collection_type::value_type x) noexcept(false) {
43  assert(x>collection_type::value_type{});
44  std::set<collection_type::value_type> factors;
45  collection_type::value_type count=1lu, tst_divs=2lu, n=x;
46  while (n!=1) {
47  if (n%tst_divs) {
48  if (n>1) {
49  if (count==1) {
50  ++tst_divs;
51  ++count;
52  } else if (count<3) {
53  tst_divs+=2;
54  ++count;
55  } else {
56  count++&1 ? (tst_divs+=2) : (tst_divs+=4);
57  if ((count>8) && (!(tst_divs%5) || !(tst_divs%7))) {
58  count++&1 ? (tst_divs+=2) : (tst_divs+=4);
59  }
60  }
61  } else {
62  factors.insert(n);
63  return collection_type{factors.begin(), factors.end()};
64  }
65  } else {
66  factors.insert(tst_divs);
67  n/=tst_divs;
68  }
69  }
70  return collection_type{factors.begin(), factors.end()};
71 }
72 
73 /// Monte Carlo factorisation.
74 /**
75  * \todo FIXME
76  *
77  * \param y The number to be factored.
78  * \return The array that has the factors placed in it.
79  *
80  * Thanks to Knuth, et al for this routine. See his book "Seminumerical Algorithms. Vol 2".
81  *
82  * \see factoring::division()
83  */
84 inline collection_type __fastcall
85 monte_carlo(const collection_type::value_type y) noexcept(false) {
86  collection_type factors;
87  collection_type::value_type x=5, x_=2, k=1, l=1, n=y, g;
88 b2:
89  if (n&1) {
90  factors.emplace_back(n);
91  return factors;
92  }
93 b3:
94  if ((g=euclid::gcd((x_-x),n))==1) {
95  goto b4;
96  } else if ((g=n)!=0) {
97  return factors;
98  } else {
99  n/=g;
100  x%=n;
101  x_%=n;
102  goto b2;
103  }
104 b4:
105  if (!--k) {
106  x_=x;
107  l<<=1;
108  k=l;
109  }
110  x=(x*x+1)%n;
111  goto b3;
112 }
113 
114 } } }
115 
116 #endif