Цель проста: вычислить функцию totenent для максимально возможного числа чисел за 10 секунд и суммировать числа.
Вы должны напечатать свой результат в конце, и вы должны фактически рассчитать его. Автоматические функции не допускаются, но библиотеки bignum разрешены. Вы должны начать с 1 и последовательно подсчитать все целые числа. Вам не разрешено пропускать номера.
Ваша оценка состоит в том, сколько чисел ваша программа может рассчитать на вашем компьютере / сколько моя программа может рассчитать на вашем компьютере . Мой код - простая программа на C ++ (без оптимизации), надеюсь, вы сможете ее запустить.
Важные свойства, которые вы могли бы использовать!
- если
gcd(m,n) = 1, phi(mn) = phi(m) * phi(n)
- если
p
простое число,phi(p) = p - 1
(дляp < 10^20
) - если
n
даже,phi(2n) = 2 phi(n)
- другие перечислены в первой ссылке
Мой код
#include <iostream>
using namespace std;
int gcd(int a, int b)
{
while (b != 0)
{
int c = a % b;
a = b;
b = c;
}
return a;
}
int phi(int n)
{
int x = 0;
for (int i=1; i<=n; i++)
{
if (gcd(n, i) == 1)
x++;
}
return x;
}
int main()
{
unsigned int sum = 0;
for (int i=1; i<19000; i++) // Change this so it runs in 10 seconds
{
sum += phi(i);
}
cout << sum << endl;
return 0;
}
fastest-code
qwr
источник
источник
1, 3, 5, 2, 4
или как?Ответы:
Нимрод: ~ 38 667 (580 000 000/15 000)
Этот ответ использует довольно простой подход. В коде используется простое сито простых чисел, которое хранит простое число наименьшей простой степени в каждом слоте для составных чисел (ноль для простых чисел), затем использует динамическое программирование для построения функции-накопителя в том же диапазоне, а затем суммирует результаты. Программа тратит практически все свое время на создание сита, а затем вычисляет суммарную функцию за долю времени. Похоже, все сводится к созданию эффективного сита (с небольшим уклоном в то, что нужно также уметь извлекать из результата главный фактор для составных чисел и поддерживать разумное использование памяти).
Обновление: улучшена производительность за счет уменьшения объема памяти и улучшения поведения кэша. Можно выжать на 5-10% больше производительности, но увеличение сложности кода того не стоит. В конечном счете, этот алгоритм в первую очередь использует узкое место ЦП фон Неймана, и существует очень мало алгоритмических настроек, которые могут обойти это.
Также обновлен делитель производительности, так как код C ++ не предназначался для компиляции со всеми оптимизациями, и никто другой не делал этого. :)
Обновление 2: оптимизирована работа сита для улучшения доступа к памяти. Теперь обрабатывайте небольшие простые числа с помощью memcpy () (~ 5% ускорения) и пропускайте кратные 2, 3 и 5 при просеивании больших простых чисел (~ 10% ускорения).
Код C ++: 9,9 секунды (с g ++ 4,9)
Код Nimrod: 9,9 секунды (с -d: release, бэкэнд gcc 4.9)
источник
Java, оценка ~ 24 000 (360 000 000/15 000)
Приведенный ниже код Java выполняет вычисление суммарной функции и простого сита вместе. Обратите внимание, что в зависимости от вашей машины вы должны увеличить начальный / максимальный размер кучи (на моем довольно медленном ноутбуке мне пришлось подняться
-Xmx3g -Xms3g
).источник
Нимрод: ~ 2 333 333 (42 000 000 000/18 000)
Это использует совершенно другой подход от моего предыдущего ответа. Смотрите комментарии для деталей.
longint
Модуль можно найти здесь .источник
2*sqrt(n)
), Что значительно снижает балл.C #: 49 000 (980 000 000/20 000)
/codegolf//a/26800 "Код Говарда".
Но измененные значения фи вычисляются для нечетных целых чисел.
Новый счет: 61 000 (1 220 000 000/20 000)
В «App.config» мне пришлось добавить «gcAllowVeryLargeObjects enabled = true».
источник
Python 3: ~ 24000 (335 000 000/14 000)
Моя версия представляет собой Python-порт алгоритма Говарда . Моя оригинальная функция была модификацией алгоритма, представленного в этом посте .
Я использую модули Numpy и Numba, чтобы ускорить время выполнения. Обратите внимание, что обычно вам не нужно объявлять типы локальных переменных (при использовании Numba), но в этом случае я хотел максимально сократить время выполнения.
Редактирование: объединяет функции constructsieve и summarum в одну функцию.
С ++: 9,99 (n = 14 000); Python 3: 9,94 (n = 335 000 000)
источник
Вот моя реализация Python, которая, кажется, способна набрать ~ 60000 чисел за 10 секунд. Я делю числа на множители, используя алгоритм Полларда Ро и критерий простоты Рабина Миллера.
источник
φ (2 n ) = 2 n - 1
Σ φ (2 i ) = 2 i - 1 для i от 1 до n
Во-первых, что-то найти раз:
Для справочного кода, для меня это:
Теперь Хаскелл:
Это делает что-то с 2525224 цифрами за 0,718 секунды. И теперь я просто замечаю комментарий @ Говарда.
источник
Matlab: 1464 = 26355867/18000
Я не могу проверить ваш код, поэтому я разделил на 18000, так как он представляет собой самый быстрый компьютер из тех, кто тестировал. Я пришел на счет, используя это свойство:
Мне больше всего нравится, что это один лайнер:
источник
phi(p)
всех не премьерp
?Python 2.7: 10.999 (165975/15090)
Pypy 2.3.1: 28.496 (430000/15090)
Некоторые интересные методы, которые я использую:
Тест Рабина-Миллера Стронга с псевдопримаром - тест простоты, который обеспечивает эффективный вероятностный алгоритм для определения, является ли данное число простым
Формула произведения Эйлера - произведение на различные простые числа, делящие n
Код:
источник