You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

133 lines
4.4KB

  1. import java.math.BigInteger;
  2. import java.util.LinkedList;
  3. import java.util.List;
  4. import java.util.Random;
  5. public class Prime {
  6. /**
  7. * Calculates the integer square root of a number.
  8. * Source: https://stackoverflow.com/questions/4407839/how-can-i-find-the-square-root-of-a-java-biginteger/13023513#13023513
  9. *
  10. * @param x the number
  11. * @return the square root
  12. */
  13. private static BigInteger sqrt(BigInteger x) {
  14. BigInteger div = BigInteger.ZERO.setBit(x.bitLength()/2);
  15. BigInteger div2 = div;
  16. // Loop until we hit the same value twice in a row, or wind
  17. // up alternating.
  18. for(;;) {
  19. BigInteger y = div.add(x.divide(div)).shiftRight(1);
  20. if (y.equals(div) || y.equals(div2))
  21. return y;
  22. div2 = div;
  23. div = y;
  24. }
  25. }
  26. /**
  27. * Checks, whether a number is a prime or not. Uses naive implementation accelerated by multithreading.
  28. *
  29. * @param candidate the number to check
  30. * @return the boolean
  31. */
  32. private static boolean isPrime(BigInteger candidate) {
  33. // Check special candidate values 0, 1, 2 and even
  34. if (candidate.compareTo(BigInteger.ZERO) == 0 // candidate == 0
  35. || candidate.compareTo(BigInteger.ONE) == 0) { // candidate == 1)
  36. return false;
  37. }
  38. if (candidate.compareTo(BigInteger.valueOf(2)) == 0) { // candidate == 2
  39. return true;
  40. } else if (candidate.mod(BigInteger.valueOf(2)).equals(BigInteger.ZERO)) { // candidate is even
  41. return false;
  42. }
  43. // Divide interval into segments, one for each cpu core
  44. int cores = Runtime.getRuntime().availableProcessors();
  45. BigInteger max = sqrt(candidate).add(BigInteger.ONE);
  46. BigInteger min = BigInteger.valueOf(3);
  47. BigInteger step = max.subtract(min).divide(BigInteger.valueOf(cores));
  48. BigInteger remainder = max.subtract(min).mod(BigInteger.valueOf(cores));
  49. int i = 0;
  50. List<Worker> workers = new LinkedList<>();
  51. while (i < cores) {
  52. BigInteger num = step;
  53. if (remainder.compareTo(BigInteger.ZERO) == 1) { // remainder > 0
  54. num = num.add(BigInteger.ONE);
  55. remainder = remainder.subtract(BigInteger.ONE);
  56. }
  57. num = num.subtract(BigInteger.ONE);
  58. if (num.compareTo(BigInteger.ZERO) >= 0) {
  59. workers.add(new Worker(candidate, min, min.add(num), "Thread " + i));
  60. workers.get(i).start();
  61. min = min.add(num).add(BigInteger.ONE);
  62. }
  63. i++;
  64. if (min.compareTo(max) > 0) {
  65. break;
  66. }
  67. }
  68. // Wait for workers to complete
  69. boolean stop = false;
  70. boolean isPrime = true;
  71. while (!stop) {
  72. i = 0;
  73. while (i < workers.size()) {
  74. Worker w = workers.get(i);
  75. try {
  76. w.join(500);
  77. } catch (InterruptedException ex) {
  78. ex.printStackTrace();
  79. }
  80. if (w.hasFinished()) {
  81. if (!w.isPrime()) {
  82. isPrime = false;
  83. stop = true;
  84. break;
  85. } else {
  86. // This worker is done, remove it from the list
  87. workers.remove(w);
  88. if (workers.isEmpty()) {
  89. stop = true;
  90. break;
  91. }
  92. }
  93. }
  94. i++;
  95. }
  96. }
  97. // Stop workers
  98. for (Worker w: workers) {
  99. w.interrupt();
  100. }
  101. return isPrime;
  102. }
  103. /**
  104. * Generates a guaranteed prime of the given length.
  105. *
  106. * @param bits binary length of the prime to generate
  107. * @return prime number
  108. */
  109. public static BigInteger generate(int bits) {
  110. Random rng = new Random();
  111. BigInteger candidate = new BigInteger(bits, rng);
  112. int i = 0;
  113. while (!isPrime(candidate)){
  114. //System.out.println("Not a prime: " + candidate);
  115. candidate = new BigInteger(bits, rng);
  116. i++;
  117. }
  118. //System.out.println("Found prime after " + i + " tries: " + candidate);
  119. return candidate;
  120. }
  121. }