Advertisement
dikun

The Largest Semiprime Palindrome

Apr 20th, 2017
586
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Julia 7.62 KB | None | 0 0
  1. # Problem:
  2. #
  3. # nnnnn * mmmmm = P
  4. # nnnnn, mmmmm - five-digit primes
  5. # P - the maximum palindrome
  6. # (P - the largest semiprime palindrome)
  7. # P - ?
  8.  
  9.  
  10. # If the palindrome contains 10 digits, then it is divided by 11. That won't pass!
  11. typealias TNumber_9   UInt32 # nine-digit unsigned numbers
  12. typealias TNumber_5   UInt32 # five-digit ...
  13.  
  14. typealias TIndex      TNumber_5
  15. typealias TIteration  TNumber_9
  16.  
  17. # signed version of numbers (for type casting)
  18. typealias TINumber_5  Int32
  19. typealias TINumber_9  Int32
  20.  
  21. typealias TIIteration Int32
  22.  
  23. type TProduct
  24.     value::TNumber_9 # nnnnn * mmmmm
  25.     index::TIndex
  26. end
  27.  
  28. type TBitSet
  29.     # BitArrays are space-efficient "packed" boolean arrays, which store one bit per boolean value.
  30.     # One bit - one number (optimization)
  31.     data::BitArray
  32.     k::TIndex
  33. end
  34.  
  35. const MAX_5  = 99989     # the largest five-digit prime number, but 99997 is good too
  36. const MIN_5  = 10007     # the smallest ...,                    but 10001 is good too
  37. const MAX_9  = 999999997 # 999,999,999 and 999,999,998 are not primes
  38.  
  39. SQRT_I = 2171            # primes[2171] == 31607 ~ sqrt(MAX_9) and isPrime(31607)==true
  40.                          # (use eratosthenesSieve())
  41.  
  42.  
  43. function eratosthenesSieve() ::Array{TNumber_5}
  44.     # In cryptography we use sieve of Atkin, but this algorithm is the best for big numbers
  45.     # The idea:
  46.     # 1. sift composit numbers on 1..sqrt(MAX_5)
  47.     # 2. sift numbers on MIN_5..MAX_5 that are divisible by primes on 1..sqrt(MAX_5)
  48.    
  49.     bitSet ::TBitSet = TBitSet(trues(MAX_5), 0) # bitSet.k == 0
  50.     _end   ::TIndex  = MAX_5
  51.     start  ::TIndex  = MIN_5
  52.    
  53.     # sift even numbers to the square root only (optimization)
  54.     primaryEnd ::TIndex = TIndex(floor(sqrt(_end)))
  55.     for i::TIndex= 4 : 2 : primaryEnd
  56.         bitSet.data[i]= false
  57.     end
  58.    
  59.     # sift even five-digit only (optimization)
  60.     for i::TIndex= div(start, 2) * 2 : 2 : _end
  61.         bitSet.data[i]=false
  62.     end
  63.    
  64.     # sift odd five-digit
  65.     for i::TIndex= 3 : 2 : primaryEnd # to the primaryEnd, not to the _end!
  66.         if bitSet.data[i] # isPrime?
  67.             # optimization: preliminary small sieve (from sqr(prime))
  68.             for j::TIndex= i*i : i : primaryEnd
  69.                 bitSet.data[j]= false
  70.             end
  71.             # basic large sieve (from sqr(prime))
  72.             for m::TIndex= div(start, i) * i : i : _end
  73.                 bitSet.data[m]= false
  74.             end
  75.         end
  76.     end
  77.    
  78.     bitSet.data[1]= false # not a prime!
  79.     bitSet.data[2]= true  # prime!
  80.    
  81.     # ñalculate the number of all five-digit primes
  82.     # bitSet.k == 0
  83.     oddStart ::TIndex = start + (mod(start, 2) == 0)
  84.     for i= oddStart : 2 : _end
  85.         if bitSet.data[i]      # isPrime?
  86.             bitSet.k += 1      # the number of all five-digit primes
  87.         end
  88.     end
  89.    
  90.     # form primes into Array (for quick access)
  91.     primes ::Array{TNumber_5} = zeros(Int, bitSet.k)
  92.     m= 1
  93.     for i= oddStart : 2 : _end
  94.         if bitSet.data[i]      # isPrime?
  95.             primes[m]= i
  96.             m += 1
  97.         end
  98.     end
  99.    
  100.     return primes
  101.    
  102. end #eratosthenesSieve
  103.  
  104.  
  105. function isPalindrome(number::TNumber_9) ::Bool
  106.    
  107.     tempNumber ::TNumber_9 = number;
  108.     reversedNumber ::TNumber_9 = 0;
  109.     rest::TNumber_9 = 0;
  110.    
  111.     # accumulate the reverse number
  112.     while tempNumber != 0
  113.         rest= mod(tempNumber, 10)
  114.         tempNumber = div(tempNumber, 10)
  115.         reversedNumber = reversedNumber*10 + rest
  116.     end
  117.    
  118.     return (number == reversedNumber) # really a palindrome?
  119.    
  120. end #isPalindrome
  121.  
  122.  
  123. function getProduct(primes::Array{TNumber_5}, diagram::Array{TIndex}, i::TIndex) ::TNumber_9
  124.     return (primes[i] * primes[diagram[i]]) # nnnnn * mmmmm = PPPPPPPPP
  125. end
  126.  
  127.  
  128. function initDiagram(primes::Array{TNumber_5}) ::Array{TIndex}
  129.     # nnnnn * mmmmm = PPPPPPPPP
  130.     # form the structure (diagram) for searching for factors (nnnnn * mmmmm; MIN_5 <= nnnnn, mmmmm <= MAX_5)
  131.    
  132.     # nnnnn >= mmmmm
  133.     # mmmmm <= sqrt(MAX_9), because: mmmmm > sqrt(MAX_9) => mmmmm > nnnnn
  134.     # (optimization)
  135.     diagram ::Array{TIndex} = zeros(Int, SQRT_I)
  136.     j::TIndex= length(primes)
  137.     for i::TIndex= 1:SQRT_I
  138.         _max ::TNumber_5 = div(MAX_9, primes[i]) # mmmmm <= MAX_9 / nnnnn
  139.         while j >= i
  140.             if primes[j] <= _max
  141.                 diagram[i]= j
  142.                 break
  143.             end
  144.         j -= 1
  145.         end
  146.     end
  147.    
  148.     return diagram
  149.    
  150. end #initDiagram
  151.  
  152.  
  153. function initSorted(primes::Array{TNumber_5}, diagram::Array{TIndex}) ::Array{TProduct}
  154.     # transform diagram into the sorted structure (sorted::Array{TProduct})
  155.     # (optimization)
  156.    
  157.     # initialization
  158.     sorted ::Array{TProduct} = Array(TProduct, SQRT_I)
  159.     for i::TIndex= 1:SQRT_I      # the system function fill() have problems with references:
  160.                                  # https://github.com/JuliaLang/julia/issues/17796
  161.         sorted[i]= TProduct(0,0)
  162.     end
  163.     for i::TIndex= 1:SQRT_I
  164.         sorted[i].value= getProduct(primes, diagram, i)
  165.         sorted[i].index= i
  166.     end
  167.    
  168.     sort!(sorted; alg= QuickSort, lt= (x, y) -> x.value > y.value)
  169.    
  170.     return sorted
  171.    
  172. end #initSorted
  173.  
  174.  
  175. function _sort!(sorted::Array{TProduct}, border::TIndex)
  176.     # Insertion sort (one iteration) for Array.
  177.     # Array is not good for optimization, but...
  178.     # ...Julia does not support full-value pointers, full-value recursive data types and full-value references.
  179.     # ...IntSet (sorted set; implemented as a bit string) have the problem with big numbers:
  180.     #    https://docs.julialang.org/en/stable/stdlib/collections/?highlight=intset#Base.IntSet
  181.    
  182.     j::TIndex= 2
  183.     key::TProduct= sorted[1]
  184.     while (j <= border) && (key.value < sorted[j].value)
  185.         sorted[j-1]= sorted[j] # shift all of sorted[j], where sorted[j].value < key.value (for all j)
  186.         j += 1
  187.     end
  188.     sorted[j-1]= key
  189.    
  190.     return
  191.    
  192. end # _sort
  193.  
  194.  
  195. function findPalindrome(N::TIteration) ::Dict{String, TINumber_9}    
  196.    
  197.     # cascade inicialization
  198.     primes  ::Array{TNumber_5} = eratosthenesSieve(                  ) # primes on MIN_5...MAX_5
  199.     diagram ::Array{TIndex}    = initDiagram(        primes          ) # the structure for searching for factors
  200.     sorted  ::Array{TProduct}  = initSorted(         primes, diagram ) # sorted diagram
  201.    
  202.     # main ñycle
  203.     border ::TIndex = SQRT_I
  204.     i::TIteration= 1
  205.     while ((N == 0) && (border >= 1)) || (i <= N) # N iterations or to the end (N == 0)
  206.        
  207.         if isPalindrome(sorted[1].value)
  208.             return (Dict([ # found!
  209.                 ("product"   , TINumber_9( sorted[1].value)),
  210.                 ("factor-1"  , TINumber_5( primes[sorted[1].index])),
  211.                 ("factor-2"  , TINumber_5( primes[diagram[sorted[1].index]])),
  212.                 ("iterations", TIIteration(i)) # numbers of iterations
  213.             ]))
  214.         end
  215.        
  216.         # delete the pair (nnnnn, mmmmm) from sorted (and diagram)
  217.         # nnnnn * mmmmm == sorted[1].value == maximum at this iteration
  218.         diagram[sorted[1].index] -= 1
  219.         sorted[1].value= getProduct(primes, diagram, sorted[1].index)
  220.        
  221.         _sort!(sorted, border) # sort in place!
  222.        
  223.         # correct border (optimization)
  224.         if primes[border] > primes[diagram[border]]
  225.             border -= 1
  226.             # println("border: ", border)
  227.         end
  228.        
  229.         i += 1 # next iteration
  230.    
  231.     end # main ñycle
  232.    
  233.     return Dict()
  234.    
  235. end #findPalindrome
  236.  
  237.  
  238. findPalindrome()= findPalindrome(TIteration(0)) # N == 0
  239.  
  240.  
  241. @time result= findPalindrome()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement