- 01
- 02
- 03
- 04
- 05
- 06
- 07
- 08
- 09
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
public class factorial {
public static void main(String[] args) {
boolean run = true;
long count = 2142;
long last_count=0;
while (run) {
if (ispand(count)) {
if (isprime(count)) {
System.out.println(count);
last_count=count;
}
}
if((count+"").length()>7){
System.out.println("Largest prime can be :"+last_count);
System.exit(1);
}
count++;
}
}
public static boolean ispand(long num) {
String text = num + "";
for (int i = 1; i <= text.length(); i++) {
if (!text.contains(i + "")) {
return false;
}
}
return true;
}
public static boolean isprime(long num) {
if (num == 1) {
return false;
} else {
for (int i = 2; i <= Math.sqrt(num); i++) {
if (num % i == 0) {
return false;
}
}
}
return true;
}
}
TheHamstertamer 24.05.2012 18:17 # +2
bormand 24.05.2012 19:49 # 0
bormand 24.05.2012 20:28 # +3
Работает миллисекунды даже в ghci... Что тут делать 2 секунды - я не знаю :)
3.14159265 25.05.2012 11:56 # 0
>reverse $ sort $ map makeNumber $ permutations [1..7]
Не хочу злорадствовать, но наверняка reverse $ sort тяжелые операции и от этого никакая ленивость и AsParallel не спасёт.
В моём варианте достаточно, как Вы уже указали ранее, взять первое значение.
bormand 25.05.2012 12:32 # +2
Ну а так, согласен, sort тут лишний, достаточно сделать правильный permutations (стандартный выдает их в каком-попало порядке).
guest 25.05.2012 16:01 # +4
bormand 25.05.2012 16:51 # +1
guest 25.05.2012 17:00 # +3
guest 25.05.2012 17:05 # +1
bormand 25.05.2012 17:25 # +1
sum $ map makeNumber $ sort $ permutations [1..10]
22.91с, 4.6Гб
sum $ map makeNumber $ ordPermutations [1..10]
5.88c, 5.2Гб
bormand 25.05.2012 17:32 # +1
3.14159265 25.05.2012 17:47 # 0
Хуясе! Это используемая память?! Та нахуй он тогда нужен этот Хацкель.
У меня даже жаба n=11 на приведенном мною алгоритме:
2.5с, память - неощутимо (пару метров).
Притом что по объему кода примерный паритет теплая ламповая императивщина заруливает ваши функцианалы в глубокий минус.
Байтоитоебы снова побеждают.
bormand 25.05.2012 17:51 # +1
3.14159265 25.05.2012 18:02 # +1
Предсказуемо.
> меньше пары метров для ленивой версии.
А, ясно. Меня несколько шокировали цифры.
Всё-равно n=10 у меня за 100мс. Агрумент о том что списки произвольной длины, а int всего 32 бита не катит, потому что уже на 20! железо просто помрет.
guest 25.05.2012 17:58 # 0
есть еще stream fusion - соединяет list-produces и consumer в одну ф-ию, будет сравнимо с С.
Ну и всегда (когда списки только как промежуточные) можно в рекурсивном виде записать, только очень некрасиво получится.
3.14159265 25.05.2012 20:16 # 0
Но вот одна действительно хорошая оптимизация - нахождение наибольшего неиспользуемого символа (позиция первого нулевого бита), чтобы сократить кол-во итераций.
Тут можно либо битовую магию применить, либо юзать заранее просчитанные таблицы.
10 бит - 1024 состояния, не так уж много. В L1 запросто влезет. Тогда вплотную подходим к O(n!)
guest 25.05.2012 17:38 # 0
Сравните, например, main = print $ length (permutations [1..11]) для двух вариантов.
bormand 25.05.2012 17:45 # 0
Хотя, возможно, их нельзя сравнивать напрямую - т.к. они решают немного разные задачи - permutations генерит перестановки в произвольном порядке, а ordPermutations в строго заданном.
P.S. попробую придумать версию пооптимальней.
wvxvw 25.05.2012 18:25 # +1
guest 25.05.2012 19:34 # 0
Пожалуй, главное чтоб коэффициент не вы рос быстрее, чем n*log n (оверхед sort). Вроде не выходит.
guest 25.05.2012 19:37 # 0
3.14159265 25.05.2012 17:56 # −1
Сборщик мусора очень рад Хацкелу.
http://ideone.com/IByI4
guest 25.05.2012 18:01 # 0
Проверятся как быстро создается список, length считает длину, посчитанное сразу в мусор. (оригинальный был 25% на [1..9], при больших - меньше)
bormand 25.05.2012 17:14 # 0
Поясните, пожалуйста, почему он должен работать на порядок дольше?
P.S. В контексте задачи про pandigital primes он явно быстрее прошлой версии с reverse + sort + permutations т.к. ленив и не генерирует лишних перестановок, после того как будет найдено первое решение.
bormand 25.05.2012 17:21 # +1
guest 25.05.2012 17:41 # 0
Раз написали так, значит, нужно сравнить с permutations в целом, а не в контексте данной задачи.
Для _данной_ задачи ваш вариант подходит, но в ответе 765 впереди, из 7! остается 24 варианта -- можно писать абы как, лишь бы лениво.
3.14159265 25.05.2012 17:54 # 0
guest 25.05.2012 18:16 # 0
3.14159265 25.05.2012 18:30 # 0
Это n! итераций.
В рекурсивном способе, чтобы не было дубликатов, нужно либо проверять использовалось/не использовалось как это сделал я, либо удалять из списка (порождением нового).
В любом случае думаю где-то в районе n^n проверок (итераций).
guest 25.05.2012 18:35 # 0
(Забыл, что еще оригинальный permutations может быть хуже n! - swap на списках затруднен).
3.14159265 25.05.2012 19:03 # 0
А в треде - неоптимальное говно, ибо я вчера писал первое что пришло в голову.
>swap на списках затруднен
Не гораздо трудней, чем удалить из него один элемент :)
3.14159265 25.05.2012 19:18 # 0
Как я и думал. Базовый Swap и иногда Reverse подсписка.
PS> Тестьте!
http://rosettacode.org/wiki/Sorting_algorithms/Permutation_sort#Haskell
bormand 25.05.2012 19:31 # 0
Неупорядоченный :(
Попробую реализовать алгоритм из вики.
3.14159265 25.05.2012 19:34 # 0
bormand 25.05.2012 19:40 # 0
guest 25.05.2012 21:48 # 0
сырой код, абы как:
корректность проверял так:
take 120 (iterate next [5,4..1]) == map reverse (sort $ permutations [1,2,3,4,5])
на [1..10] быстрее, чем у [color=blue]bormand[/blue] main = print $ length (ordPermutations [1..10])
А вот какой вывод сделать не знаю: не уверен, что смогу оценить сложность изкоробочного permutations.
3.14159265 29.05.2012 14:25 # 0
1. swap-версия с апплета (по сути, то что я предлагал тут: http://govnokod.ru/10361#comment139237)
Аналог вот этого http://en.wikipedia.org/wiki/Permutation#Generation_in_lexicographic_ order
2. оптимизированная вариация 3-го пункта (с массивом позиций младшего нулевого бита)
3. первоначальная версия с битами на быструю руку
n=12
1. 4313ms
2. 10500ms
3. 30391ms
n=11
1. 734ms
2. 875ms
3. 2359ms
n=10
1. 31ms
2. 78ms
3. 203ms
Разница между 1 и 2 ~ 2.5 раза. Но на N=11 - странный результат, запускал трижды - повторяется.
PS.Что интересно версия с Integer[] m_Val работает в два раза медленней, чем примитивные типы: new int[m_Max];
Вот вам и автобоксинг.
3.14159265 29.05.2012 14:35 # 0
1. 734ms
А сегодня запустил:
1. 360ms
Теперь всё стало на места, смотрите, в обоих методах зависимость от n! линейная:
10500ms/875ms=12 (ровно!)
875ms/78ms=11.2
4313ms/360ms=11.99
360/31=11.6
guest 25.05.2012 18:58 # 0
Хм.. n! + цена сортировки n! (log n!) должны сверху ограничивать оценки сортированных перестановок.
O(n! n (log n)), n (log n) - верхняя оценка коэф. разницы.
3.14159265 25.05.2012 19:43 # 0
Да. Это я загнул.
Посчитал кол-во итераций с своем алгоритме ~ 2*(n-1)*n!
Всё потому что это не таки тупой брутфорс n^n и скип ненужных веток присутствует:
if ((mask & 1<<j)==0);
3.14159265 25.05.2012 19:53 # 0
3.14159265 25.05.2012 20:56 # 0
http://ideone.com/NJpzU
время: 0.09s
bormand 25.05.2012 21:02 # 0
Built-in Function: int __builtin_clz (unsigned int x)
Returns the number of leading 0-bits in x, starting at the most significant bit position. If x is 0, the result is undefined.
На интеле она должна выполняться за 1 машинную команду. Жаль, что этой функции нет в стандарте.
3.14159265 25.05.2012 21:08 # 0
В любом случае как еще улучшать алгоритмически я не знаю.
И выходит рвет даже haskell unordered permutations.
bormand 25.05.2012 21:29 # 0
guest 25.05.2012 22:22 # +1
3.14159265 28.05.2012 15:20 # 0
Ну это в пределе при n->∞
Кстати через разложение e в сумму обратных факториалов как раз и доказывают, что оно иррациональное.
Вот, чтоб было понятней что я ниже написал - пикча e^x в ряд Тейлора.
http://upload.wikimedia.org/wikipedia/ru/math/f/5/5/f551e394956f5458a059c2b041a4fbfb.png
при x=1
3.14159265 28.05.2012 15:12 # 0
Да, Вы абсолютно правы. Просто я тогда чето затупил, и подумал на ln(n), вместо e.
Я думал и пришел к такой же формуле независимо.
>равно n!*e-1
Именно! Но это n!*e предел при n->∞.
При n=0 и n->∞ Сумма(1/n!) -> e
Q.E.D
3.14159265 28.05.2012 20:10 # +2
c = a - ((a >> 1) & 0x55555555);
c = ((c >> 2) & 0x33333333) + (c & 0x33333333);
c = ((c >> 4) + c) & 0x0F0F0F0F;
c = ((c >> 8) + c) & 0x00FF00FF;
неизбежен.
guest 25.05.2012 22:20 # 0
guest 25.05.2012 15:46 # 0
filter чем не устроил?
roman-kashitsyn 25.05.2012 15:58 # +1
bormand 25.05.2012 16:52 # 0
movaxbx 24.05.2012 20:56 # 0
>т.к. все остальные делятся на 3
Вот это не понял.
bormand 24.05.2012 21:02 # +2
Если мы берем все 10 цифр - то их сумма будет 45, она делится на 3 => по признаку делимости на 3 все эти числа делятся на 3. По тому же принципу отлетают все диапазоны кроме 1..7 и 1..4.
vistefan 25.05.2012 15:44 # +1
>все 10 цифр
=)
bormand 25.05.2012 17:33 # +1
wvxvw 25.05.2012 18:45 # 0
bormand 25.05.2012 18:53 # +1
Что при n=10 составляет 9864100
3.14159265 25.05.2012 18:59 # 0
Если считать вырожденный случай в виде всех значений деревом, то можно обойтись и n!
bormand 25.05.2012 19:03 # 0
3.14159265 25.05.2012 19:06 # 0
Формально это тоже префиксное дерево, но с глубиной 2.
bormand 25.05.2012 19:08 # 0
wvxvw 25.05.2012 19:02 # 0
3.14159265 25.05.2012 19:07 # 0
Но Вы же сами пишете, что дерево - "префиксное".
wvxvw 25.05.2012 19:30 # 0
Зы. транслит.ру посчитал, что правильно писать "пощитал" :)
3.14159265 25.05.2012 19:58 # +1
Тогда квадрат 9 на 9 :)
Но это, по определению, не префиксное дерево.
>пощитал
Тоже так иногда пейшу.
bormand 25.05.2012 20:08 # 0
3.14159265 25.05.2012 20:11 # 0
10 ведь минимально достаточно.
> это ориентированный граф
Циклов нет, значит дерево. Но требование префиксности, как уже отмечал, не выполняется.
bormand 25.05.2012 20:23 # 0
Если в средних слоях брать по 10 - то получим лишние пути, которые не являются перестановками.
> Циклов нет, значит дерево. Но требование префиксности, как уже отмечал, не выполняется.
Да, согласен, это не префиксное дерево.
wvxvw 25.05.2012 22:50 # 0
wvxvw 25.05.2012 22:58 # 0
bormand 26.05.2012 05:54 # 0
Если сгруппировать эти узлы по множеству чисел, входящих в пути к ним, то получим C(10,5) = 252 группы по 5! = 120 узлов.
К каждой группе мы прицепляем оставшиеся 5! = 120 суффиксов.
В применении к генерации перестановок - получается, что нужно сгенерить C(10,5) подмножеств. А затем для каждого из них сгенерить по 5! перестановок элементов подмножества, и 5! перестановок оставшихся элементов и взять их декартово произведение.
Как-то так.
wvxvw 25.05.2012 19:09 # 0
wvxvw 25.05.2012 19:15 # 0
bormand 25.05.2012 21:27 # 0
bormand 25.05.2012 20:56 # 0
В комментах к коду написано что это менее эффективная версия L-алгоритма из книги Кнута.
n: 9 10 11
fasc2B_algorithm_L: 0.124с 1.27с 14.757с
permutations: 0.03с 0.20с 1.938с
мой тупой однострочник: 0.29с 3.13с 35.639с
К сожалению, результаты L-алгоритма отличаются от моего в константное число раз (2.4). Поэтому рискну предположить, что в языке с иммутабельными данными понизить сложность алгоритма уже не получится, только выиграть в константе.
guest 25.05.2012 22:37 # 0
guest 25.05.2012 22:37 # 0
bormand 26.05.2012 05:21 # 0
bormand 26.05.2012 07:04 # +1
Результаты теста на print $ length:
n: 9 10 11 12
permutations: 0.03 0.20 1.938 22.329
новый генератор: 0.02 0.358 2.485 15.371
К сожалению пример с вычислением длины для этого генератора совсем не показателен.
bormand 26.05.2012 07:26 # 0
n: 9 10 11
permutations: 0.151 2.077 30.32
perms: 0.21 2.8666 34.08
guest 26.05.2012 11:48 # 0
Определенно, ленивость надо обходить, хотел заметить, но вы сами написали.
BTW, вы смотрели http://govnokod.ru/10361#comment139267 ?
Потом форсировал через (sum . map sum) вроде быстрее оригинального (по идее еще неплохо было бы вычитать из всех время для такого генератора: replicate (product [1..length xs]) xs)
bormand 26.05.2012 12:13 # 0
Для n=9
Ваш вариант - 0.09с (1.2% GC)
perms - 0.15с (49% GC)
replicate - 0.01с (3.3% GC)
Для n=10
Ваш вариант - 0.94с (1.1% GC)
perms - 1.41с (45% GC)
replicate - 0.06с (1.7% GC)
Для n=11
Ваш вариант - 11.43с (1.0% GC)
perms - 11.23с (15% GC)
replicate - 1.28с (1.1% GC)
Странно, но при росте n perms начинает догонять ваш вариант. Жаль, что для 12 ждать уже слишком долго.
guest 26.05.2012 12:27 # 0
bormand 26.05.2012 12:32 # 0
guest 26.05.2012 12:33 # 0
Все-таки ваш первый вариант по соотношению кол-во кода / производительность неплох, и его легко можно улучшить раз в два: http://haskell.1045720.n5.nabble.com/String-permutation-td3190999.html (последний пост)
bormand 26.05.2012 12:47 # 0
Ага, согласен, производительность на хаскеле хрен измеришь. То GC вмешается, то поленится раскрыть что-то, то фаза луны не та...
>Все-таки ваш первый вариант по соотношению кол-во кода / производительность неплох, и его легко можно улучшить раз в два
Ага, их вариант selections интересный и краткий.
guest 26.05.2012 12:04 # 0
"генератор"-"то, что форсирует"-"длина списка", для ordPermutations опустил n=9
ваш perms обозвал subs, dumb - то что предлагал выше вычитать.
Можно делить sum на n! / n! n / n! (log n0) / n! n (log n) и смотреть графики: что больше на прямую похоже. Но как то уже лень), да и выборка маловата.
guest 26.05.2012 12:22 # 0
bormand 26.05.2012 12:33 # 0
guest 26.05.2012 12:34 # 0
3.14159265 28.05.2012 14:50 # 0
Я об таком думал, но только как бы еще закешировать маленькие перестановки.
3.14159265 28.05.2012 15:05 # 0
Это что же получается. Новый сортированный генератор работает быстрее родного в Хацкеле, да еще и несортированного.
Проверьте, пожалуйста, на своей машине мой первый вариант на С:
>http://www.govnokod.ru/10361#comment139219
У меня сопоставимые цифры - 2-3 секунды при n=11.
bormand 28.05.2012 15:46 # 0
$ g++ -O2 1.cpp
$ time ./a.out
39916800
real 0m2.933s
user 0m2.932s
sys 0m0.000s