|
OFF: быстрая генерация простых чисел | ☑ | ||
---|---|---|---|---|
0
viktorovichvadim
06.03.14
✎
17:32
|
В продолжение темы: быстрая генерация простых чисел
ОПИСАНИЕ КЛАССА НА ЯЗЫКЕ JAVA ДЛЯ ГЕНЕРАЦИИ ВСЕХ ПРОСТЫХ ЧИСЕЛ ДО N: public class manannikovsSieveNew { public static void main(String[]args) { long startTime=System.currentTimeMillis(); // 6 <= N <= 44710000 int N = 100000; int[] numbers = new int[N+1]; numbers[3] = 5; numbers[5] = 7; numbers[5-1] = 3; int limit = 0; int prime1 = 0; int prime2 = 0; int summand = 0; int leftNumber = 3; int leftPrimorial = 6; int rigtNumber = 0; int rightPrimorial = 0; int lastSegmentNumber = 5; int count1 = 3; int count2 = 0; int[] compositeNumbers = new int[(N+1)/10]; boolean tr = true; while (tr == true) { rigtNumber = numbers[leftNumber]; rightPrimorial = leftPrimorial*rigtNumber; if (rightPrimorial > N) { limit = N; } else limit = rightPrimorial; int step = 0; while (tr == true) { step = step + 1; if (step == 1) { summand = 1; prime1 = lastSegmentNumber; } else if (step == 2) { summand = rigtNumber; } else summand = numbers[summand]; prime2 = leftPrimorial + summand; if (prime2 > limit) { numbers[prime1] = 1; break; } numbers[prime2-1] = prime1; numbers[prime1] = prime2; count1 = count1 + 1; prime1 = prime2; lastSegmentNumber = prime2; } int index1 = rigtNumber; while (tr == true) { int factor1 = index1; int compositeNumber1 = factor1*factor1; if (compositeNumber1 > limit) { break; } int compositeNumbersCount = 0; int index2 = index1; while (tr == true) { int factor2 = index2; int compositeNumber2 = factor1*factor2; if (compositeNumber2 > limit) { break; } compositeNumbersCount = compositeNumbersCount + 1; compositeNumbers[compositeNumbersCount] = compositeNumber2; count2 = count2 + 1; index2 = numbers[index2]; } for (int n = 1; n <= compositeNumbersCount; n++) { int x = numbers[compositeNumbers[n]-1]; int у = numbers[compositeNumbers[n]]; numbers[x] = у; numbers[у-1] = x; } index1 = numbers[index1]; if (rightPrimorial <= N) { break; } } if (rightPrimorial > N) { break; } leftNumber = rigtNumber; leftPrimorial = rightPrimorial; } long finishTime=System.currentTimeMillis(); long countMS = finishTime - startTime; System.out.println(); System.out.print(countMS/1000 + " secunds"); System.out.println(); System.out.print(countMS + " millisecunds"); System.out.println(); int PrimesCount = 0; // number 2 and number 3 int a = 2; int b = 4; while (a > 1) { //here you can print primes //System.out.println(); //System.out.print(a); PrimesCount = PrimesCount + 1; a = numbers[b]; b = a; } System.out.println(); System.out.println(); System.out.print(PrimesCount + " primes to " + N); } } ОПИСАНИЕ ПРОЦЕДУР В МОДУЛЕ ФОРМЫ ОБРАБОТКИ В СРЕДЕ 1С:ПРЕДПРИЯТИЕ 8.2 ДЛЯ ГЕНЕРАЦИИ ВСЕХ ПРОСТЫХ ЧИСЕЛ ДО N: Процедура ОтметитьСоставные(Числа, ИндексНач, Гран, Единожды) Индекс1 = ИндексНач; Пока Истина Цикл Множитель1 = Индекс1; Если Множитель1*Множитель1 > Гран Тогда Прервать; КонецЕсли; Составные = Новый Массив; Индекс2 = Индекс1; Пока Истина Цикл Множитель2 = Индекс2; Составное = Множитель1*Множитель2; Если Составное > Гран Тогда Прервать; КонецЕсли; Составные.Добавить(Составное); Индекс2 = Числа[Индекс2]; КонецЦикла; Для Каждого Составное ИЗ Составные Цикл ПсевдоПростоеПред = Числа[Составное-1]; ПсевдоПростоеСлед = Числа[Составное]; Числа[ПсевдоПростоеПред] = ПсевдоПростоеСлед; Числа[ПсевдоПростоеСлед-1] = ПсевдоПростоеПред; КонецЦикла; Индекс1 = Числа[Индекс1]; Если Единожды Тогда Прервать; КонецЕсли; КонецЦикла; КонецПроцедуры Функция ПолучитьГраницу(Числа, ИндексПрав) Гран = 1; Для Индекс = 0 ПО ИндексПрав Цикл Гран = Гран * Числа[Индекс]; КонецЦикла; Возврат Гран; КонецФункции ПРОЦЕДУРА ГЕНЕРАЦИЯ() ВремяНачала = ТекущаяДата(); Сообщить(Символы.ПС); Сообщить("Начало: " + ВремяНачала); Числа = Новый Массив(Граница+1); Числа[3] = 5; Числа[5] = 7; Числа[5-1] = 3; ЧислоЛев = 3; ГраницаЛев = 6; ЧислоПрошлогоОтрезка = 5; Пока Истина Цикл ЧислоПрав = Числа[ЧислоЛев]; ГраницаПрав = ГраницаЛев*ЧислоПрав; Гран = ?(ГраницаПрав > Граница, Граница, ГраницаПрав); Шаг = 0; Пока Истина Цикл Шаг = Шаг + 1; Если Шаг = 1 Тогда Слагаемое = 1; ПсевдоПростоеПред = ЧислоПрошлогоОтрезка; ИначеЕсли Шаг = 2 Тогда Слагаемое = ЧислоПрав; Иначе Слагаемое = Числа[Слагаемое]; КонецЕсли; ПсевдоПростоеСлед = ГраницаЛев + Слагаемое; Если ПсевдоПростоеСлед > Гран Тогда Числа[ПсевдоПростоеПред] = 1; Прервать; КонецЕсли; Числа[ПсевдоПростоеСлед-1] = ПсевдоПростоеПред; Числа[ПсевдоПростоеПред] = ПсевдоПростоеСлед; ПсевдоПростоеПред = ПсевдоПростоеСлед; ЧислоПрошлогоОтрезка = ПсевдоПростоеСлед; КонецЦикла; Если ГраницаПрав > Граница Тогда ОтметитьСоставные(Числа, ЧислоПрав, Гран, Ложь); Прервать; Иначе ОтметитьСоставные(Числа, ЧислоПрав, Гран, Истина); КонецЕсли; ЧислоЛев = ЧислоПрав; ГраницаЛев = ГраницаПрав; КонецЦикла; ЧислоПростых = 1; // число 2 ПростоеПосле = 0; ПростоеДо = 3; Пока НЕ ПростоеПосле = 1 Цикл ЧислоПростых = ЧислоПростых + 1; ПростоеПосле = Числа[ПростоеДо]; ПростоеДо = ПростоеПосле; КонецЦикла; ВремяОкончания = ТекущаяДата(); Сообщить("Окончание: " + ВремяОкончания); Сообщить("Число простых до " + Граница + ": " + ЧислоПростых); Сообщить("Время выполнения : " + (ВремяОкончания - ВремяНачала) + " секунд"); КОНЕЦПРОЦЕДУРЫ |
|||
1
МойКодУныл
06.03.14
✎
17:41
|
Спасибо. А зачем?
|
|||
2
viktorovichvadim
06.03.14
✎
17:42
|
(1) может, кто-то возьмется оценить сложность алгоритма. было бы очень интересно.
|
|||
3
SUA
06.03.14
✎
17:49
|
а в чем смысл вообще?
что-то меня стиль "пока истина" убивает |
|||
4
SUA
06.03.14
✎
17:49
|
словами описать
|
|||
5
ЗлобнийМальчик
06.03.14
✎
17:56
|
(0) а зачем ява то? уж проще тогда на С# - его проще во внешнюю компоненту запихнуть...
|
|||
6
viktorovichvadim
06.03.14
✎
20:12
|
(3) не смущайтесь, это мой первый код на java, просто хотел чтобы идею смогли "прощупать" не только 1с-ники
|
|||
7
viktorovichvadim
06.03.14
✎
20:17
|
(3) в первом приближении: генерируется возрастающая последовательность чисел до N, где присутствуют ВСЕ простые числа до N, а также составные, которые потом исключаются по некоторому алгоритму. "решето", в-общем.
|
|||
8
Холст
06.03.14
✎
20:23
|
(0) это чтобы добывать биткоины в среде 1С ?
|
|||
9
viktorovichvadim
06.03.14
✎
20:36
|
(7) приближение второе. Рассматриваем только N>6. Отрезок (6; N) разбиваем на несколько отрезков, точками разбиения служат последовательные праймориалы: 6 = 2*3, 30 = 2*3*5, 210 = 2*3*5*7, 2310 = 2*3*5*7*11 и т.д. Например, если N = 1000, получаем отрезки (6, 30], (30, 210], (210, 1000]. Далее эти отрезки последовательно "отрабатываются".
|
|||
10
Рэйв
06.03.14
✎
20:38
|
Сферический конь в вакууме.
|
|||
11
viktorovichvadim
06.03.14
✎
20:39
|
(10) т.е.?
|
|||
12
viktorovichvadim
06.03.14
✎
20:48
|
(9) описанный способ генерации простых можно назвать улучшенным решетом Эйлера, описание стандартного решета Эйлера хорошо дано в википедии: wiki:Решето_Эратосфена
Оно короткое, приведу целиком здесь: Решето Эйлера Решето Эйлера это вариант решета Эратосфена, в котором каждое составное число удаляется из списка только один раз. Составляется исходный список начиная с числа 2. На каждом этапе алгоритма первый номер в списке берется как следующее простое число, и определяются его произведения на каждое число в списке которые маркируются для последуюшего удаления. После этого из списка убирают первое число и все помеченные числа, и процесс повторяется вновь: [2] (3) 5 7 9 11 13 15 17 19 21 23 25 27 29 31 33 35 37 39 41 43 45 47 49 51 53 55 57 59 61 63 65 67 69 71 73 75 77 79 ... [3] (5) 7 11 13 17 19 23 25 29 31 35 37 41 43 47 49 53 55 59 61 65 67 71 73 77 79 ... [4] (7) 11 13 17 19 23 29 31 37 41 43 47 49 53 59 61 67 71 73 77 79 ... [5] (11) 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 73 79 ... [...] Здесь показан пример начиная с нечетных чисел, после первого этапа алгоритма. Таким образом, после k-го этапа рабочий список содержит только числа взаимно простые с первыми k простыми числами (то есть числа не кратные ни одному из первых k простых чисел), и начинается с (k+1)-го простого числа. Все числа в списке, меньшие квадрата его первого числа, являются простыми. |
|||
13
Зойч
06.03.14
✎
20:55
|
Какова скорать алгоритма? N^2, 2^N или хуже?
Каково потребление памяти? |
|||
14
Tateossian
06.03.14
✎
21:25
|
(9) Решето Эратосфена
import java.util.*; /** * Эта программа выполняет тест "решето Эратосфена", подсчитывая * простые числа до 1 000 000. * @version 1.0 * @author NA */ public class Eratosphen { public static void main(String[] args) { int n = 1000000; long start = System.currentTimeMillis(); BitSet b = new BitSet(n + 1); int count = 0; int i; for (i = 2; i <= n; i++) b.set(i); i = 2; while (i * i <= n) { if (b.get(i)) { count++; int k = 2 * i; while (k <= n) { b.clear(k); k += i; } } i++; } while (i <= n) { if (b.get(i)) count++; i++; } long end = System.currentTimeMillis(); System.out.println(count + "простых чисел"); System.out.println((end - start) + "мс"); } } |
|||
15
viktorovichvadim
06.03.14
✎
21:32
|
(15) до 40 000 000 моим методом: 1157 millisecunds, твоим эратосфеном: 3585мс
|
|||
16
Tateossian
06.03.14
✎
21:38
|
(15) Да, у меня 887 мс твоим способом, моим 1930. Малаца!
|
|||
17
viktorovichvadim
06.03.14
✎
22:06
|
(12) "улучшение" заключается в том, что в отличие от обычного решета Эйлера исходный список чисел формируется не весь сразу, а "отрезками" (см. 9), и уже "очищенным" от большого количества составных чисел.
|
|||
18
viktorovichvadim
06.03.14
✎
22:27
|
вообще, хотелось бы выяснить, есть ли нечто новое в данном алгоритме или я изобрел "велосипед".
|
|||
19
viktorovichvadim
07.03.14
✎
12:23
|
коллеги, где Вы? есть какие мнения?
|
|||
20
Speshuric
07.03.14
✎
12:40
|
(18) Особо нового нет. И праймориалы использовать дальше 7-и или 11-и смысла нет - слишком быстро падает профит и слишком быстро растут накладные расходы на них.
|
|||
21
kosts
07.03.14
✎
12:41
|
(19) Про медицину еще спроси, получишь квалифицированный ответ... Ну и с другой стороны ужа давно всё изобретено... Так просто уже ничего не придумаешь.
|
|||
22
Speshuric
07.03.14
✎
12:48
|
(18) Вдогонку: с простыми числами, пока первые числа влезают в память и само число в целую размерность, вообще не сильно интересно, особенно, если идти по протоптанным алгоритмам.
|
Форум | Правила | Описание | Объявления | Секции | Поиск | Книга знаний | Вики-миста |