দ্রুততম সেমিপ্রাইম ফ্যাক্টরীকরণ


28

স্বল্পতম সময়ের মধ্যে একটি আধা-মৌলিক সংখ্যার গুণক তৈরি করার জন্য একটি প্রোগ্রাম লিখুন।

পরীক্ষার উদ্দেশ্যে, এটি ব্যবহার করুন: 38! +1 (523022617466601111760007224100074291200000001)

এটি সমান: 14029308060317546154181 × 37280713718589679646221


2
যদিও আমি "দ্রুততম" বিটটি পছন্দ করি, যেহেতু এটি সি এর মতো ভাষাগুলি টিপিকাল কোডগল্ফিংয়ের ভাষাগুলির চেয়ে বেশি সুবিধা দেয় তবে আমি অবাক হই যে আপনি ফলাফলগুলি কীভাবে পরীক্ষা করবেন?
মিস্টার লিস্টার

1
যদি আপনি বোঝাতে চান যে 12259243প্রোগ্রামগুলি কত দ্রুত হয় তা পরীক্ষা করতে ব্যবহার করা হবে, ফলাফলগুলি এত ছোট হবে যে আপনি কোনও পরিসংখ্যানগতভাবে গুরুত্বপূর্ণ পার্থক্য পাবেন না।
পিটার টেলর

আমি একটি বড় সংখ্যা যোগ করেছি, মাথা আপ জন্য thx।
সোহম চৌধুরী

@ মিস্টার লিস্টার, আমি এটি নিজের পিসিতে পরীক্ষা করব।
সোহম চৌধুরী

5
ইনবি 4 কেউ 400 অ্যাকাবাইট লুক টেবিল লিখতে প্রিপ্রসেসর অপব্যবহার ব্যবহার করে।
ওয়াগ

উত্তর:


59

পাইথন (ডাব্লু / পাইপাই জেআইটি ভি 1 .9) ~ 1.9 এস

একাধিক বহুবর্ষীয় চতুর্ভুজ চালনী ব্যবহার করা । আমি এটিকে কোড চ্যালেঞ্জ হিসাবে গ্রহণ করেছি, সুতরাং আমি কোনও বাহ্যিক লাইব্রেরি (মানক logফাংশন ব্যতীত, আমি মনে করি) ব্যবহার না করার পছন্দ করেছিলাম। সময় নির্ধারণের সময় পাইপাই জেআইটি ব্যবহার করা উচিত, কারণ সিপিথনের চেয়ে 4-5 গুণ বেশি সময় নির্ধারিত হয়

আপডেট (২০১৩-০7-২৯):
মূলত পোস্টিং করার পরে, আমি বেশ কয়েকটি ছোটখাটো, তবে উল্লেখযোগ্য পরিবর্তন করেছি যা সামগ্রিক গতি প্রায় 2.5x এর একটি ফ্যাক্টর দ্বারা বৃদ্ধি করে।

আপডেট (2014-08-27):
এই পোস্টটি এখনও মনোযোগ পাচ্ছে my_math.py, যে কেউ এটি ব্যবহার করছে তার জন্য আমি দুটি ত্রুটি সংশোধন করে আপডেট করেছি :

  • isqrtত্রুটিযুক্ত ছিল, কখনও কখনও একটি নিখুঁত বর্গের খুব কাছাকাছি মানের জন্য ভুল আউটপুট উত্পাদন করে। এটি সংশোধন করা হয়েছে, এবং আরও ভাল বীজ ব্যবহার করে কর্মক্ষমতা বৃদ্ধি পেয়েছে।
  • is_primeআপডেট করা হয়েছে. নিখুঁত বর্গক্ষেত্র 2-স্প্রিংস সরিয়ে দেওয়ার আমার পূর্ববর্তী প্রচেষ্টাটি অর্ধ-হৃদয়যুক্ত ছিল, সর্বোত্তম। পরীক্ষিত মানটি বর্গামুক্ত কিনা তা নিশ্চিত করতে আমি ম্যাথমেটিকার ব্যবহৃত একটি প্রযুক্তি - একটি থ্রি-স্প্রিপ চেক যুক্ত করেছি।

আপডেট (২০১৪-১১-২৪):
গণনা শেষে যদি অ-তুচ্ছ সমাহার খুঁজে পাওয়া যায় না, তবে প্রোগ্রাম এখন অতিরিক্ত বহুত্ববৃত্তিকে গ্রাস করবে। এটি আগে কোড হিসাবে চিহ্নিত ছিল TODO


mpqs.py

from my_math import *
from math import log
from time import clock
from argparse import ArgumentParser

# Multiple Polynomial Quadratic Sieve
def mpqs(n, verbose=False):
  if verbose:
    time1 = clock()

  root_n = isqrt(n)
  root_2n = isqrt(n+n)

  # formula chosen by experimentation
  # seems to be close to optimal for n < 10^50
  bound = int(5 * log(n, 10)**2)

  prime = []
  mod_root = []
  log_p = []
  num_prime = 0

  # find a number of small primes for which n is a quadratic residue
  p = 2
  while p < bound or num_prime < 3:

    # legendre (n|p) is only defined for odd p
    if p > 2:
      leg = legendre(n, p)
    else:
      leg = n & 1

    if leg == 1:
      prime += [p]
      mod_root += [int(mod_sqrt(n, p))]
      log_p += [log(p, 10)]
      num_prime += 1
    elif leg == 0:
      if verbose:
        print 'trial division found factors:'
        print p, 'x', n/p
      return p

    p = next_prime(p)

  # size of the sieve
  x_max = len(prime)*60

  # maximum value on the sieved range
  m_val = (x_max * root_2n) >> 1

  # fudging the threshold down a bit makes it easier to find powers of primes as factors
  # as well as partial-partial relationships, but it also makes the smoothness check slower.
  # there's a happy medium somewhere, depending on how efficient the smoothness check is
  thresh = log(m_val, 10) * 0.735

  # skip small primes. they contribute very little to the log sum
  # and add a lot of unnecessary entries to the table
  # instead, fudge the threshold down a bit, assuming ~1/4 of them pass
  min_prime = int(thresh*3)
  fudge = sum(log_p[i] for i,p in enumerate(prime) if p < min_prime)/4
  thresh -= fudge

  if verbose:
    print 'smoothness bound:', bound
    print 'sieve size:', x_max
    print 'log threshold:', thresh
    print 'skipping primes less than:', min_prime

  smooth = []
  used_prime = set()
  partial = {}
  num_smooth = 0
  num_used_prime = 0
  num_partial = 0
  num_poly = 0
  root_A = isqrt(root_2n / x_max)

  if verbose:
    print 'sieving for smooths...'
  while True:
    # find an integer value A such that:
    # A is =~ sqrt(2*n) / x_max
    # A is a perfect square
    # sqrt(A) is prime, and n is a quadratic residue mod sqrt(A)
    while True:
      root_A = next_prime(root_A)
      leg = legendre(n, root_A)
      if leg == 1:
        break
      elif leg == 0:
        if verbose:
          print 'dumb luck found factors:'
          print root_A, 'x', n/root_A
        return root_A

    A = root_A * root_A

    # solve for an adequate B
    # B*B is a quadratic residue mod n, such that B*B-A*C = n
    # this is unsolvable if n is not a quadratic residue mod sqrt(A)
    b = mod_sqrt(n, root_A)
    B = (b + (n - b*b) * mod_inv(b + b, root_A))%A

    # B*B-A*C = n <=> C = (B*B-n)/A
    C = (B*B - n) / A

    num_poly += 1

    # sieve for prime factors
    sums = [0.0]*(2*x_max)
    i = 0
    for p in prime:
      if p < min_prime:
        i += 1
        continue
      logp = log_p[i]

      inv_A = mod_inv(A, p)
      # modular root of the quadratic
      a = int(((mod_root[i] - B) * inv_A)%p)
      b = int(((p - mod_root[i] - B) * inv_A)%p)

      k = 0
      while k < x_max:
        if k+a < x_max:
          sums[k+a] += logp
        if k+b < x_max:
          sums[k+b] += logp
        if k:
          sums[k-a+x_max] += logp
          sums[k-b+x_max] += logp

        k += p
      i += 1

    # check for smooths
    i = 0
    for v in sums:
      if v > thresh:
        x = x_max-i if i > x_max else i
        vec = set()
        sqr = []
        # because B*B-n = A*C
        # (A*x+B)^2 - n = A*A*x*x+2*A*B*x + B*B - n
        #               = A*(A*x*x+2*B*x+C)
        # gives the congruency
        # (A*x+B)^2 = A*(A*x*x+2*B*x+C) (mod n)
        # because A is chosen to be square, it doesn't need to be sieved
        val = sieve_val = A*x*x + 2*B*x + C

        if sieve_val < 0:
          vec = set([-1])
          sieve_val = -sieve_val

        for p in prime:
          while sieve_val%p == 0:
            if p in vec:
              # keep track of perfect square factors
              # to avoid taking the sqrt of a gigantic number at the end
              sqr += [p]
            vec ^= set([p])
            sieve_val = int(sieve_val / p)

        if sieve_val == 1:
          # smooth
          smooth += [(vec, (sqr, (A*x+B), root_A))]
          used_prime |= vec
        elif sieve_val in partial:
          # combine two partials to make a (xor) smooth
          # that is, every prime factor with an odd power is in our factor base
          pair_vec, pair_vals = partial[sieve_val]
          sqr += list(vec & pair_vec) + [sieve_val]
          vec ^= pair_vec
          smooth += [(vec, (sqr + pair_vals[0], (A*x+B)*pair_vals[1], root_A*pair_vals[2]))]
          used_prime |= vec
          num_partial += 1
        else:
          # save partial for later pairing
          partial[sieve_val] = (vec, (sqr, A*x+B, root_A))
      i += 1

    num_smooth = len(smooth)
    num_used_prime = len(used_prime)

    if verbose:
      print 100 * num_smooth / num_prime, 'percent complete\r',

    if num_smooth > num_used_prime:
      if verbose:
        print '%d polynomials sieved (%d values)'%(num_poly, num_poly*x_max*2)
        print 'found %d smooths (%d from partials) in %f seconds'%(num_smooth, num_partial, clock()-time1)
        print 'solving for non-trivial congruencies...'

      used_prime_list = sorted(list(used_prime))

      # set up bit fields for gaussian elimination
      masks = []
      mask = 1
      bit_fields = [0]*num_used_prime
      for vec, vals in smooth:
        masks += [mask]
        i = 0
        for p in used_prime_list:
          if p in vec: bit_fields[i] |= mask
          i += 1
        mask <<= 1

      # row echelon form
      col_offset = 0
      null_cols = []
      for col in xrange(num_smooth):
        pivot = col-col_offset == num_used_prime or bit_fields[col-col_offset] & masks[col] == 0
        for row in xrange(col+1-col_offset, num_used_prime):
          if bit_fields[row] & masks[col]:
            if pivot:
              bit_fields[col-col_offset], bit_fields[row] = bit_fields[row], bit_fields[col-col_offset]
              pivot = False
            else:
              bit_fields[row] ^= bit_fields[col-col_offset]
        if pivot:
          null_cols += [col]
          col_offset += 1

      # reduced row echelon form
      for row in xrange(num_used_prime):
        # lowest set bit
        mask = bit_fields[row] & -bit_fields[row]
        for up_row in xrange(row):
          if bit_fields[up_row] & mask:
            bit_fields[up_row] ^= bit_fields[row]

      # check for non-trivial congruencies
      for col in null_cols:
        all_vec, (lh, rh, rA) = smooth[col]
        lhs = lh   # sieved values (left hand side)
        rhs = [rh] # sieved values - n (right hand side)
        rAs = [rA] # root_As (cofactor of lhs)
        i = 0
        for field in bit_fields:
          if field & masks[col]:
            vec, (lh, rh, rA) = smooth[i]
            lhs += list(all_vec & vec) + lh
            all_vec ^= vec
            rhs += [rh]
            rAs += [rA]
          i += 1

        factor = gcd(list_prod(rAs)*list_prod(lhs) - list_prod(rhs), n)
        if factor != 1 and factor != n:
          break
      else:
        if verbose:
          print 'none found.'
        continue
      break

  if verbose:
    print 'factors found:'
    print factor, 'x', n/factor
    print 'time elapsed: %f seconds'%(clock()-time1)
  return factor

if __name__ == "__main__":
  parser =ArgumentParser(description='Uses a MPQS to factor a composite number')
  parser.add_argument('composite', metavar='number_to_factor', type=long,
      help='the composite number to factor')
  parser.add_argument('--verbose', dest='verbose', action='store_true',
      help="enable verbose output")
  args = parser.parse_args()

  if args.verbose:
    mpqs(args.composite, args.verbose)
  else:
    time1 = clock()
    print mpqs(args.composite)
    print 'time elapsed: %f seconds'%(clock()-time1)

my_math.py

# divide and conquer list product
def list_prod(a):
  size = len(a)
  if size == 1:
    return a[0]
  return list_prod(a[:size>>1]) * list_prod(a[size>>1:])

# greatest common divisor of a and b
def gcd(a, b):
  while b:
    a, b = b, a%b
  return a

# modular inverse of a mod m
def mod_inv(a, m):
  a = int(a%m)
  x, u = 0, 1
  while a:
    x, u = u, x - (m/a)*u
    m, a = a, m%a
  return x

# legendre symbol (a|m)
# note: returns m-1 if a is a non-residue, instead of -1
def legendre(a, m):
  return pow(a, (m-1) >> 1, m)

# modular sqrt(n) mod p
# p must be prime
def mod_sqrt(n, p):
  a = n%p
  if p%4 == 3:
    return pow(a, (p+1) >> 2, p)
  elif p%8 == 5:
    v = pow(a << 1, (p-5) >> 3, p)
    i = ((a*v*v << 1) % p) - 1
    return (a*v*i)%p
  elif p%8 == 1:
    # Shank's method
    q = p-1
    e = 0
    while q&1 == 0:
      e += 1
      q >>= 1

    n = 2
    while legendre(n, p) != p-1:
      n += 1

    w = pow(a, q, p)
    x = pow(a, (q+1) >> 1, p)
    y = pow(n, q, p)
    r = e
    while True:
      if w == 1:
        return x

      v = w
      k = 0
      while v != 1 and k+1 < r:
        v = (v*v)%p
        k += 1

      if k == 0:
        return x

      d = pow(y, 1 << (r-k-1), p)
      x = (x*d)%p
      y = (d*d)%p
      w = (w*y)%p
      r = k
  else: # p == 2
    return a

#integer sqrt of n
def isqrt(n):
  c = n*4/3
  d = c.bit_length()

  a = d>>1
  if d&1:
    x = 1 << a
    y = (x + (n >> a)) >> 1
  else:
    x = (3 << a) >> 2
    y = (x + (c >> a)) >> 1

  if x != y:
    x = y
    y = (x + n/x) >> 1
    while y < x:
      x = y
      y = (x + n/x) >> 1
  return x

# strong probable prime
def is_sprp(n, b=2):
  if n < 2: return False
  d = n-1
  s = 0
  while d&1 == 0:
    s += 1
    d >>= 1

  x = pow(b, d, n)
  if x == 1 or x == n-1:
    return True

  for r in xrange(1, s):
    x = (x * x)%n
    if x == 1:
      return False
    elif x == n-1:
      return True

  return False

# lucas probable prime
# assumes D = 1 (mod 4), (D|n) = -1
def is_lucas_prp(n, D):
  P = 1
  Q = (1-D) >> 2

  # n+1 = 2**r*s where s is odd
  s = n+1
  r = 0
  while s&1 == 0:
    r += 1
    s >>= 1

  # calculate the bit reversal of (odd) s
  # e.g. 19 (10011) <=> 25 (11001)
  t = 0
  while s:
    if s&1:
      t += 1
      s -= 1
    else:
      t <<= 1
      s >>= 1

  # use the same bit reversal process to calculate the sth Lucas number
  # keep track of q = Q**n as we go
  U = 0
  V = 2
  q = 1
  # mod_inv(2, n)
  inv_2 = (n+1) >> 1
  while t:
    if t&1:
      # U, V of n+1
      U, V = ((U + V) * inv_2)%n, ((D*U + V) * inv_2)%n
      q = (q * Q)%n
      t -= 1
    else:
      # U, V of n*2
      U, V = (U * V)%n, (V * V - 2 * q)%n
      q = (q * q)%n
      t >>= 1

  # double s until we have the 2**r*sth Lucas number
  while r:
    U, V = (U * V)%n, (V * V - 2 * q)%n
    q = (q * q)%n
    r -= 1

  # primality check
  # if n is prime, n divides the n+1st Lucas number, given the assumptions
  return U == 0

# primes less than 212
small_primes = set([
    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,101,103,107,109,113,
  127,131,137,139,149,151,157,163,167,173,
  179,181,191,193,197,199,211])

# pre-calced sieve of eratosthenes for n = 2, 3, 5, 7
indices = [
    1, 11, 13, 17, 19, 23, 29, 31, 37, 41,
   43, 47, 53, 59, 61, 67, 71, 73, 79, 83,
   89, 97,101,103,107,109,113,121,127,131,
  137,139,143,149,151,157,163,167,169,173,
  179,181,187,191,193,197,199,209]

# distances between sieve values
offsets = [
  10, 2, 4, 2, 4, 6, 2, 6, 4, 2, 4, 6,
   6, 2, 6, 4, 2, 6, 4, 6, 8, 4, 2, 4,
   2, 4, 8, 6, 4, 6, 2, 4, 6, 2, 6, 6,
   4, 2, 4, 6, 2, 6, 4, 2, 4, 2,10, 2]

max_int = 2147483647

# an 'almost certain' primality check
def is_prime(n):
  if n < 212:
    return n in small_primes

  for p in small_primes:
    if n%p == 0:
      return False

  # if n is a 32-bit integer, perform full trial division
  if n <= max_int:
    i = 211
    while i*i < n:
      for o in offsets:
        i += o
        if n%i == 0:
          return False
    return True

  # Baillie-PSW
  # this is technically a probabalistic test, but there are no known pseudoprimes
  if not is_sprp(n, 2): return False

  # idea shamelessly stolen from Mathmatica
  # if n is a 2-sprp and a 3-sprp, n is necessarily square-free
  if not is_sprp(n, 3): return False

  a = 5
  s = 2
  # if n is a perfect square, this will never terminate
  while legendre(a, n) != n-1:
    s = -s
    a = s-a
  return is_lucas_prp(n, a)

# next prime strictly larger than n
def next_prime(n):
  if n < 2:
    return 2
  # first odd larger than n
  n = (n + 1) | 1
  if n < 212:
    while True:
      if n in small_primes:
        return n
      n += 2

  # find our position in the sieve rotation via binary search
  x = int(n%210)
  s = 0
  e = 47
  m = 24
  while m != e:
    if indices[m] < x:
      s = m
      m = (s + e + 1) >> 1
    else:
      e = m
      m = (s + e) >> 1

  i = int(n + (indices[m] - x))
  # adjust offsets
  offs = offsets[m:] + offsets[:m]
  while True:
    for o in offs:
      if is_prime(i):
        return i
      i += o

নমুনা I / O:

$ pypy mpqs.py --verbose 94968915845307373740134800567566911
smoothness bound: 6117
sieve size: 24360
log threshold: 14.3081031579
skipping primes less than: 47
sieving for smooths...
144 polynomials sieved (7015680 values)
found 405 smooths (168 from partials) in 0.513794 seconds
solving for non-trivial congruencies...
factors found:
216366620575959221 x 438925910071081891
time elapsed: 0.685765 seconds

$ pypy mpqs.py --verbose 523022617466601111760007224100074291200000001
smoothness bound: 9998
sieve size: 37440
log threshold: 15.2376302725
skipping primes less than: 59
sieving for smooths...
428 polynomials sieved (32048640 values)
found 617 smooths (272 from partials) in 1.912131 seconds
solving for non-trivial congruencies...
factors found:
14029308060317546154181 x 37280713718589679646221
time elapsed: 2.064387 seconds

দ্রষ্টব্য: --verboseবিকল্পটি ব্যবহার না করা কিছুটা ভাল সময় দেবে:

$ pypy mpqs.py 94968915845307373740134800567566911
216366620575959221
time elapsed: 0.630235 seconds

$ pypy mpqs.py 523022617466601111760007224100074291200000001
14029308060317546154181
time elapsed: 1.886068 seconds

মৌলিক ধারণা

সাধারণভাবে, একটি চতুর্ভুজ ছাঁটাই নিম্নলিখিত পর্যবেক্ষণের উপর ভিত্তি করে: যে কোনও বিজোড় সংমিশ্রিত এন হিসাবে উপস্থাপিত হতে পারে:

এটি নিশ্চিত করা খুব কঠিন নয়। যেহেতু এন বিজোড় হয়, কোন দুই cofactors মধ্যে দূরত্ব এন এমনকি হতে হবে 2d , যেখানে এক্স তাদের মধ্যে মাঝামাঝি বিন্দু। অধিকন্তু, একই সম্পর্কটি এন এর যে কোনও একাধিকের জন্য ধারণ করে

মনে রাখবেন যদি কোন এক্স এবং পাওয়া যাবে, তা অবিলম্বে একটি (অগত্যা মৌলিক নয়) এর ফ্যাক্টর পরিণাম ডেকে আনবে এন , যেহেতু এক্স + D এবং এক্স - D উভয় ডিভাইড এন সংজ্ঞা দ্বারা। এই সম্পর্কটিকে আরও দুর্বল করা যেতে পারে - সম্ভাব্য তুচ্ছ সংস্থাগুলি - নিম্নলিখিত ফর্মটিতে অনুমতি দেওয়ার পরিণতিতে:

তাই সাধারণভাবে, আমরা দুই নিখুঁত স্কোয়ার যা হয় সমতুল্য জানতে পারেন গেলিক ভাষার এন , তাহলে এটি মোটামুটি সম্ভবত যে আমরা সরাসরি একটি গুণক তৈরী করতে পারে এর এন একটি লা GCD (এক্স ± ডি, ঢ) । বেশ সহজ মনে হচ্ছে, তাই না?

এটা না বাদে যদি আমরা সমস্ত সম্ভাব্য এক্স এর উপরে একটি বিস্তৃত অনুসন্ধান পরিচালনা করতে চাইতাম তবে আমাদের সম্পূর্ণ পরিধিটি [ n , √ ( 2n ) ] থেকে অনুসন্ধান করতে হবে যা সম্পূর্ণ ট্রায়াল বিভাগের চেয়ে সামান্য ছোট, তবে is_squareপ্রতিটি পুনরাবৃত্তির জন্য একটি ব্যয়বহুল ক্রিয়াকলাপও প্রয়োজন to ডি এর মান নিশ্চিত করুন । আগে থেকে জানা না গেলে যে n এর খুব বেশি ঘন ঘন উপাদান রয়েছে , n , ট্রায়াল বিভাগটি আরও দ্রুত হওয়ার সম্ভাবনা রয়েছে।

সম্ভবত আমরা এই সম্পর্কটিকে আরও বেশি দুর্বল করতে পারি। মনে করুন আমরা একটি এক্স বেছে নিয়েছি , এর জন্য

y এর একটি পূর্ণ প্রাথমিক গুণাবলী সহজেই জানা যায়। আমরা যদি যথেষ্ট যেমন সম্পর্ক ছিল, আমরা করতে সক্ষম হওয়া উচিত গঠন করা পর্যাপ্ত , যদি আমরা একটি সংখ্যা নির্বাচন করুন Y যেমন যে তাদের পণ্য একটি নিখুঁত বর্গক্ষেত্র হয়; অর্থাৎ সমস্ত মৌলিক উপাদানগুলি একটি বহু সংখ্যকবার ব্যবহৃত হয় used আসলে, আমরা বেশি আছে যদি Y অনন্য মৌলিক উত্পাদক তারা রয়েছে, একটি সমাধান অস্তিত্ব নিশ্চিত করা হয় মোট সংখ্যার চেয়ে; এটি রৈখিক সমীকরণের একটি সিস্টেমে পরিণত হয়। প্রশ্নটি এখন হয়ে যায়, আমরা এই জাতীয় এক্সকে কীভাবে বেছে নিই ? সেখানেই ছত্রভঙ্গ করা খেলায় আসে।

চালুনি

বহুপদী বিবেচনা করুন:

তারপরে যে কোনও প্রাইম পি এবং পূর্ণসংখ্যা কে এর জন্য নিম্নলিখিতটি সত্য:

এর অর্থ হল বহুবর্ষের শিকড়গুলির জন্য সমাধানের পরে মোড পি- যা আপনি একটি এক্স পেয়েছেন যেমন যে Y (x) এর ≡ 0 (গেলিক ভাষার P) , অতএব Y দিয়ে বিভাজ্য পি - তারপর আপনি অসীম সংখ্যা পাওয়া যায় যেমন এক্স । এইভাবে, আপনি y এর ছোট ছোট মৌলিক কারণগুলি চিহ্নিত করে, অনেকগুলি এক্সের পরিসীমা ধরে চালনা করতে পারেন , আশা করি এমন কয়েকটি সন্ধান করুন যার জন্য সমস্ত প্রাথমিক উপাদানগুলি ছোট। এই জাতীয় সংখ্যা কে-স্মুথ হিসাবে পরিচিত , যেখানে কে সর্বাধিক প্রাইম ফ্যাক্টর ব্যবহৃত হয়।

যদিও এই পদ্ধতির সাথে কয়েকটি সমস্যা রয়েছে। না সব মান এক্স চারপাশে কেন্দ্রীভূত পর্যাপ্ত পরিবেশ নেই, আসলে, সেখানে একমাত্র তাদের খুব অল্প, এন । ক্ষুদ্রতর মানগুলি মূলত নেতিবাচক হয়ে উঠবে ( -আর মেয়াদে) এবং বৃহত্তর মানগুলি খুব বড় হয়ে উঠবে, এগুলির সম্ভাবনা খুব কম নয় যে তাদের প্রধান কারণটি কেবলমাত্র ছোট প্রাইম দ্বারা গঠিত। এরকম অনেকগুলি এক্স থাকবে , তবে যদি আপনি যে সংমিশ্রণটি ফ্যাক্টর করছেন তা খুব কম নয়, আপনি কোনও কারণীকরণের ফলে যথেষ্ট মসৃণতা খুঁজে পাবেন না এটির সম্ভাবনা খুব কম। এবং তাই, বৃহত্তর এন এর জন্য , প্রদত্ত ফর্মের একাধিক বহুভুতির উপর ছাঁটাই করা প্রয়োজনীয় হয়ে পড়ে ।

একাধিক বহুবচন

সুতরাং আমরা চালনী আরও বহুভুজ প্রয়োজন? এটি সম্পর্কে:

কাজ করবে। নোট করুন যে A এবং B আক্ষরিক অর্থে যে কোনও পূর্ণসংখ্যার মান হতে পারে এবং গণিতটি এখনও ধারণ করে। আমাদের যা করার দরকার তা হ'ল কয়েকটি র্যান্ডম মান নির্বাচন করা, বহুবর্ষের মূলের জন্য সমাধান করা এবং মানগুলি শূন্যের নিকটে চালনা করা। এই মুহুর্তে আমরা কেবল এটি যথেষ্ট ভাল বলতে পারি: আপনি যদি এলোমেলো দিক দিয়ে পর্যাপ্ত পাথর নিক্ষেপ করেন তবে আপনি শীঘ্রই বা পরে একটি উইন্ডো ভাঙতে বাধ্য bound

ব্যতীত, এটির সাথেও একটি সমস্যা আছে। এক্স-ইন্টারসেপ্টে যদি বহুভেনীর theাল বড় হয়, এটি তুলনামূলকভাবে সমতল না হলে এটি হবে, বহুভুজের প্রতি চালনি করার জন্য কয়েকটি উপযুক্ত মান থাকবে। এটি কাজ করবে, তবে আপনার প্রয়োজনীয় জিনিসটি পাওয়ার আগে আপনি পুরো বহুভিত্তিক অংশটি ছিনিয়ে নেবেন। আমরা কি আরও ভাল করতে পারি?

আমরা আরও ভাল করতে পারি মন্টগোমেরির ফলস্বরূপ একটি পর্যবেক্ষণ নিম্নরূপ: যদি A এবং B এমনভাবে বেছে নেওয়া হয় যে সেখানে কিছু সি সন্তুষ্ট থাকে

তারপরে পুরো বহুপদীটি পুনরায় লেখা যেতে পারে

উপরন্তু, যদি একটি একটি নিখুঁত বর্গক্ষেত্র হতে নির্বাচিত শীর্ষস্থানীয় একজন শব্দ, যখন sieving অনেক ছোট মান ফলে উপেক্ষিত হতে পারে, এবং অনেক জপান বক্ররেখা। যেমন একটি সমাধান অস্তিত্ব জন্য, এন একটি হওয়া আবশ্যক দ্বিঘাত অবশিষ্টাংশ গেলিক ভাষারএকজন , যা কম্পিউটিং দ্বারা অবিলম্বে জানা যাবে লেজেন্ড্রে প্রতীক :
( এন | √A ) = 1 । নোট করুন যে বি এর সমাধান করার জন্য , ofA এর একটি সম্পূর্ণ মৌলিক ফ্যাক্টেরাইজেশন জানা দরকার (মডুলার স্কোয়ার রুট taken (মোড √এ) নিতে ), এজন্যই সাধারণত typically এটিকে প্রধান হিসাবে নির্বাচিত করা হয়।

তারপরে এটি প্রদর্শিত হবে যে যদি , তবে x ∈ [ -M, M ] এর সমস্ত মানের জন্য :

এবং এখন, অবশেষে, আমাদের চালনী বাস্তবায়নের জন্য প্রয়োজনীয় সমস্ত উপাদান রয়েছে। আমরা নাকি?

উপাদান হিসাবে পুরষ্কারের ক্ষমতা

উপরে বর্ণিত হিসাবে আমাদের চালনিতে একটি বড় ত্রুটি রয়েছে। এটা তোলে চিহ্নিত করতে পারেন যার মান এক্স একটি পরিণাম ডেকে আনবে Y দ্বারা বিভাজ্য পি , কিন্তু এটা কিনা বা এই সনাক্ত করতে পারে না Y বিভাজ্য একটি দ্বারা ক্ষমতা এর পি । যাতে নির্ধারণ করার জন্য, আমরা, মান বিচারের বিভাজন সম্পাদন করতে ছাঁকা করা প্রয়োজন হবে না হওয়া পর্যন্ত এটি দ্বারা আর বিভাজ্য হয় পি । আমরা একটি অচলাবস্থা পৌঁছেছেন করলো: চালনী সমগ্র বিন্দু তাই ছিল যে আমরা করা হয়নি যে করতে হবে। প্লেবুক চেক করার সময়।

এটি দেখতে বেশ দরকারী। যোগফল যদিসমস্ত ছোট ছোট মৌলিক উপাদানগুলির লেনেরহয় y ln (y) এর প্রত্যাশিত মানের কাছাকাছি হয়, তবে এটি প্রায় একটি প্রদত্ত যে y এর অন্য কোনও কারণ নেই। তদতিরিক্ত, আমরা যদি প্রত্যাশিত মানটিকে কিছুটা কম করে সামঞ্জস্য করি তবে আমরা মানগুলি মসৃণ হিসাবেও চিহ্নিত করতে পারি যার উপাদানগুলির হিসাবে প্রাইমের কয়েকটি ক্ষমতা রয়েছে। এইভাবে, আমরা চালুনিটিকে 'প্রাক-স্ক্রিনিং' প্রক্রিয়া হিসাবে ব্যবহার করতে পারি এবং সেই মানগুলিকে কেবল মসৃণ হওয়ার সম্ভাবনা রয়েছে factor

এর পাশাপাশি আরও কয়েকটি সুবিধা রয়েছে। মনে রাখবেন যে ছোট প্রাইমগুলি লন সমষ্টিতে খুব কম অবদান রাখে তবে তবুও তাদের সবচেয়ে চালনী সময় প্রয়োজন। মান 3 সন্ধান করতে 11, 13, 17, 19 এবং 23 টি মিলিয়ে বেশি সময় প্রয়োজন । পরিবর্তে, আমরা কেবল প্রথম কয়েকটি প্রাইমগুলি এড়িয়ে যেতে পারি এবং সেই অনুযায়ী প্রান্তিক স্তরটি সামঞ্জস্য করতে পারি, ধরে নিই যে তাদের একটি নির্দিষ্ট শতাংশ পেরিয়ে গেছে।

অন্য একটি ফলাফলটি হ'ল বেশ কয়েকটি মানকে 'স্লিপ' করার অনুমতি দেওয়া হবে যা বেশিরভাগ মসৃণ তবে একক বৃহত কোফ্যাক্টর ধারণ করে। আমরা কেবল এই মানগুলি ফেলে দিতে পারি, তবে ধরুন আমরা ঠিক একই কোফ্যাক্টর সহ অন্য একটি বেশিরভাগ মসৃণ মান পেয়েছি। তারপরে আমরা ব্যবহারযোগ্য y নির্মানের জন্য এই দুটি মান ব্যবহার করতে পারি ; যেহেতু তাদের পণ্যতে এই বৃহত কোফ্যাক্টর স্কোয়ারটি থাকবে তাই এটি আর বিবেচনা করার দরকার নেই।

সবগুলোকে একত্রে রাখ

আমাদের শেষ কাজটি করতে হবে হ'ল y এর মানগুলি পর্যাপ্ত এক্স এবং ডি নির্মাণ করা । মনে করুন আমরা কেবল y এর অ-বর্গক্ষেত্র উপাদানগুলি বিবেচনা করি , এটি একটি বিজোড় শক্তির প্রধান কারণ। তারপরে, প্রতিটি y নিম্নলিখিত পদ্ধতিতে প্রকাশ করা যেতে পারে:

যা ম্যাট্রিক্স ফর্মে প্রকাশ করা যেতে পারে:

সমস্যাটি তখন ভেক্টর ভি যেমন VM =(Mod 2) সন্ধান করে , যেখানে নাল ভেক্টর। এটি হ'ল এম এর বাম নাল স্থানটির সমাধান করতে । এটি বেশ কয়েকটি উপায়ে করা যেতে পারে, যার মধ্যে সবচেয়ে সহজ হল এম তে গাউসিয়ান নির্মূলকরণ টিতে, সারি জোরের সাথে সারি সংযোজন অপারেশনটি প্রতিস্থাপন করা cing । এর ফলে নাল স্পেস ভিত্তিক ভেক্টরগুলির প্রচুর পরিমাণে ফলাফল আসবে, এর যে কোনও সংমিশ্রণের দ্বারা বৈধ সমাধান পাওয়া যাবে।

এক্স নির্মাণ মোটামুটি সোজা-সামনের দিকে। এটি প্রতিটি ব্যবহৃত y এর জন্য কেবলমাত্র Ax + B এর পণ্য । ডি নির্মাণ কিছুটা জটিল। যদি আমরা সমস্ত y এর পণ্য গ্রহণ করি তবে আমরা 10s সহ হাজারের মান সহ 100 এর সংখ্যা সহ 100s নয়, যার জন্য আমাদের বর্গমূলের সন্ধান করতে হবে। এই গণনা অবৈধভাবে ব্যয়বহুল। পরিবর্তে, আমরা sieving প্রক্রিয়া চলাকালীন এমনকি মৌলিক এমনকি ক্ষমতা ট্র্যাক রাখতে এবং ব্যবহার করতে পারেনবর্গমূলের পুনর্গঠন করতে অ-বর্গক্ষেত্রের ভেক্টরগুলিতে এবং এবং জোর ক্রিয়াকলাপটিকরতে পারি।

আমি 30000 চরিত্রের সীমাতে পৌঁছেছি বলে মনে হচ্ছে। আহ্, আমি মনে করি এটি যথেষ্ট ভাল।


5
ঠিক আছে, আমি কখনও উচ্চ বিদ্যালয়ে বীজগণিত পাস করি নি (আসলে নতুন বছরের প্রথম সেমিস্টারে বাদ পড়েছি), তবে আপনি প্রোগ্রামারের দৃষ্টিকোণ থেকে বুঝতে সহজ করেছেন। আমি এটিকে বাস্তবায়িত না করে এটি পুরোপুরি বোঝার ভান করব না তবে আমি আপনাকে সাধুবাদ জানাই। আপনার এই পোস্টটি অফ-সাইটটি প্রসারিত এবং গুরুত্ব সহকারে প্রকাশের কথা বিবেচনা করা উচিত!
jdstankosky

2
আমি রাজী. দুর্দান্ত ব্যাখ্যা সহ দুর্দান্ত উত্তর। +1
সোহম চৌধুরী

1
@ প্রিমো এখানে একাধিক প্রশ্নের আপনার উত্তরগুলি অবিশ্বাস্যভাবে সম্পূর্ণ এবং আকর্ষণীয় হয়েছে। অনেক প্রশংসিত!
পল ওয়ালস

4
সর্বশেষ মন্তব্য হিসাবে, আমি উইল নেসকে এই প্রশ্নের উপর +100 অনুগ্রহ প্রদানের জন্য কৃতজ্ঞতা জানাতে চাই । এটি ছিল আক্ষরিক অর্থে তাঁর পুরো খ্যাতি।
প্রিমো

2
@ স্টেপহেন এটি করেন। দুর্ভাগ্যক্রমে, এটি ২০১২ সালের আসল সংস্করণটি গতি উন্নতি ছাড়াই এবং গাউসিয়ান নির্মূলকরণে বাগের সাথে ব্যবহার করে (চূড়ান্ত কলামটি যখন পাইভট কলাম হয় তখন ত্রুটিগুলি) ব্যবহার করে। আমি কিছু সময় আগে লেখকের সাথে যোগাযোগ করার চেষ্টা করেছি, কিন্তু কোনও প্রতিক্রিয়া পাইনি।
primo

2

ভাল, আপনার 38! +1 আমার পিএইচপি স্ক্রিপ্টটি ভেঙেছে, কেন তা নিশ্চিত নয়। আসলে, 16 ডিজিটের বেশি কোনও আধা-প্রাইম আমার স্ক্রিপ্টটি ভেঙে দেয়।

তবে 8980935344490257 (86028157 * 104395301) ব্যবহার করে আমার স্ক্রিপ্টটি আমার হোম কম্পিউটারে (2.61GHz AMD ফেনোম 9950) 25.963 সেকেন্ডের একটি সময় পরিচালনা করে managed আমার ওয়ার্ক কম্পিউটারের চেয়ে অনেক দ্রুত যা প্রায় ২ সেকেন্ড @ ২.৯৩ গিগাহার্টজ কোর ২ ডুও ছিল।

পিএইচপি - 757 অক্ষর সহ। নতুন লাইন

<?php
function getTime() {
    $t = explode( ' ', microtime() );
    $t = $t[1] + $t[0];
    return $t;
}
function isDecimal($val){ return is_numeric($val) && floor($val) != $val;}
$start = getTime();
$semi_prime = 8980935344490257;
$slice      = round(strlen($semi_prime)/2);
$max        = (pow(10, ($slice))-1);
$i          = 3;
echo "\nFactoring the semi-prime:\n$semi_prime\n\n";

while ($i < $max) {
    $sec_factor = ($semi_prime/$i);
    if (isDecimal($sec_factor) != 1) {
        $mod_f = bcmod($i, 1);
        $mod_s = bcmod($sec_factor, 1);
        if ($mod_f == 0 && $mod_s == 0) {
            echo "First factor = $i\n";
            echo "Second factor = $sec_factor\n";
            $end=getTime();
            $xtime=round($end-$start,4).' seconds';
            echo "\n$xtime\n";
            exit();
        }
    }
    $i += 2;
}
?>

আমি সি বা অন্য কোনও সংকলিত ভাষায় এই একই অ্যালগরিদমটি দেখতে আগ্রহী।


পিএইচপি-র সংখ্যায় কেবল 53 বিট নির্ভুলতা রয়েছে, প্রায় 16 দশমিক সংখ্যা
অনুলিপি করুন

3
সি ++ তে একই অ্যালগরিদম প্রয়োগ করতে 64৪ বিট ইন্টিজার ব্যবহার করে আমার কম্পিউটারে চালাতে প্রায় 1.8 সেকেন্ড সময় লেগেছিল। যদিও এই পদ্ধতির সাথে বেশ কয়েকটি সমস্যা রয়েছে: ১. এটি যথেষ্ট পরিমাণে হ্যান্ডেল করতে পারে না। ২. এমনকি যদি এটি সমস্ত সংখ্যা ধরেও নিতে পারে, দৈর্ঘ্য নির্বিশেষে, পরীক্ষার বিভাগের জন্য একই পরিমাণ সময় ব্যবহার করে, প্রতিটি ক্রমবৃদ্ধি বৃদ্ধির ক্রম সময় সমান পরিমাণে বাড়বে। যেহেতু আপনার প্রথম ফ্যাক্টরটি প্রদত্ত প্রথম ফ্যাক্টরের তুলনায় প্রায় 14 টি মাত্রার ছোট আকারের, তাই এই অ্যালগরিদম প্রদত্ত সেমিপ্রাইমকে ফ্যাক্ট করতে 9 মিলিয়ন বছর ধরে সময় নিতে পারে।
ক্যাসাডরোবিসন

আমি গণিতে সেরা নই, স্বীকার করে নিই, তবে খুব বড় সংখ্যার জন্য, আধা-প্রাইম ফ্যাক্টরিংয়ের স্ট্যান্ডার্ড পদ্ধতিগুলি যতদূর জানি আমি কেবল (একটি এলিপস ইত্যাদি ব্যবহার করে) কাজ করতে পারি না। এই বিষয়টি মাথায় রেখে কীভাবে নিজেই অ্যালগরিদমকে উন্নত করা যায়?
jdstankosky

2
এরাটোস্থেনিস এর চালনী ইত্যাদি সংখ্যা একটি তালিকা দিয়ে শুরু হয় তারপর 2 সব গুণিতক সরিয়ে ফেলা হবে, এবং তারপর 3, এবং তারপর 5, এবং তারপর 7, কি পরে চালনী হয় সম্পূর্ণ শুধুমাত্র মৌলিক সংখ্যার আছে রয়ে যায়। এই চালনী নির্দিষ্ট সংখ্যক কারণের জন্য 'প্রাক-ক্যালসড' হতে পারে। কারণ lcm(2, 3, 5, 7) == 210, এই কারণগুলি দ্বারা মুছে ফেলা সংখ্যার প্যাটার্ন প্রতি 210 সংখ্যার পুনরাবৃত্তি করবে এবং কেবল 48 টি থাকবে। এইভাবে, আপনি কেবল প্রতিকূলতা গ্রহণ করে 50% এর পরিবর্তে পরীক্ষার বিভাগ থেকে সমস্ত সংখ্যার 77% মুছে ফেলতে পারেন।
primo

1
@ প্রিমো কৌতূহলের বাইরে আপনি কতটা সময় ব্যয় করেছেন? এই জিনিসগুলি ভাবতে আমার বয়স হতে হয়েছিল। আমি যখন এটি লিখেছিলাম, আমি কেবল তখনই ভাবছিলাম যে কীভাবে প্রাথমিক সংখ্যা সর্বদা বিজোড় হয়। আমি এর বাইরে যাওয়ার চেষ্টা করিনি এবং পাশাপাশি অ-প্রধান অদ্ভুততাও দূর করতে পারি নি। এটি পূর্ববর্তী ক্ষেত্রে খুব সহজ বলে মনে হচ্ছে।
jdstankosky
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.