С недавним избиением Python , вот попытка показать сильные стороны Python. Ваша задача состоит в том, чтобы написать программу, которая вычисляет факториал как можно большего числа в течение 10 секунд.n
Ваша оценка будет (highest n for your program on your machine)/(highest n for my program on your machine)
правила
- Вы должны вычислить точное целочисленное решение. Поскольку факториал будет намного выше, чем у 64-разрядного целого числа без знака, вы можете использовать строки, если ваш язык не поддерживает большие целые числа
- Стандартные лазейки запрещены. В частности, вы не можете использовать какие-либо внешние ресурсы.
- Только часть вычисления (включая время для любых обходных путей с использованием строк) добавляет к общему времени, которое должно быть в среднем менее 10 секунд.
- Только однопоточные программы.
- Вы должны сохранить вывод в легко распечатываемой форме (поскольку печать занимает много времени) (см. Мою программу ниже), строку, переменную, массив символов и т. Д.
РЕДАКТИРОВАТЬ:
- Ваша программа должна дать правильный вывод для всех
n
:1 <= n <= (your highest n)
EDIT2:
- Я не хочу говорить это явно, но использование встроенных факторных функций вашего языка подпадает под стандартные лазейки http://meta.codegolf.stackexchange.com/a/1078/8766 Извините Mathematica и Sage
Моя программа
from __future__ import print_function
import time
def factorial( n ):
return reduce( ( lambda x , y : x * y ) , xrange( 1 , n + 1 ) , 1 )
start = time.clock()
answer = factorial( 90000 )
end = time.clock()
print ( answer )
print ( "Time:" , end - start , "sec" )
Самый высокий балл выигрывает. Для справки, мой код может справиться n = 90000
примерно за 9.89
секунды на Pentium 4 3.0 ГГц
РЕДАКТИРОВАТЬ: все могут, пожалуйста, добавить счет, а не только самый высокий п . Просто высшее n
не имеет значения само по себе, так как оно зависит от вашего оборудования. Иначе невозможно иметь объективный критерий победы. ani0sha anwer делает это правильно.
У нас есть победитель. Я не принял java-ответ /codegolf//a/26974/8766, так как он похож на юбки, близкие к http://meta.codegolf.stackexchange.com/a/1080/8766
источник
operator.mul
вместо лямбда-функцииfactorial(Inf)
возвращаетInf
в доли секунды.Ответы:
C ++ с GMP, оценка = 55,55 (10 000 000/180 000)
источник
Python 2.7
42,575 = (6 812 000/160 000) ок.
Код:
Тестовое задание:
Выход:
Как это устроено:
Большие умножения занимают больше времени, поэтому мы хотим сделать как можно больше маленьких умножений. Это особенно верно в Python, где для чисел меньше, что
2^64
мы используем аппаратную арифметику, и выше, что мы используем программное обеспечение. Итакm(L)
, начнем со спискаL
; если это нечетная длина, мы удаляем одно число из рассмотрения, чтобы сделать его еще раз. Затем мы умножаем элемент1
на элемент-2
, элемент3
на-4
и т. Д., ЧтобыЭтот подход гарантирует, что мы используем аппаратную арифметику как можно дольше, после чего переключаемся на эффективную арифметическую библиотеку gmc.
В
fac2
данном случае мы также применяем более классический подход «разделяй и властвуй», где мы разбиваем каждое кратное 2 и сдвигаем их в конце для тривиального повышения производительности. Я включил его здесь, потому что обычно он примерно на 0,5% быстрее, чемfac1
.Гольф версия
fac1
(потому что я могу), 220Висточник
gmpy2
? $ python Python 2.7.3 (по умолчанию, 27 февраля 2014 г., 19:58:35) [GCC 4.6.3] в linux2 Для получения дополнительной информации введите «help», «copyright», «credits» или «license». >>> из gmpy2 import mpz Traceback (последний вызов был последним): файл "<stdin>", строка 1, в <module> ImportError: нет модуля с именем gmpy2 >>>while len(L): ...
вместоwhile len(L)>1: ...
?Ява - 125,15 (21 400 000/171 000)
Также беззастенчиво скопированный из репозитория Github Питера Люшни (спасибо @ полуэкстрасичный) и лицензированный по лицензии MIT, в нем используется алгоритм «вложенного квадрата факторизации простых чисел», предложенный Albert Schönhage et al. (согласно странице описания факторных алгоритмов Лушного ).
Я немного адаптировал алгоритм, чтобы использовать Java BigInteger и не использовать справочную таблицу для n <20.
Скомпилирован с gcj, который использует GMP для реализации BigInteger, и работал на Linux 3.12.4 (Gentoo), на Core i7 4700MQ на частоте 2,40 ГГц
источник
gcj -O3 --main=PrimeSieveFactorialSchoenhage PrimeSieveFactorialSchoenhage.java -o pf_nest_square_fact
Python 3, n = 100000
Простое изменение алгоритма - это все, что было необходимо, чтобы увеличить пример кода на 10000.
Очевидно, не самый креативный ответ, но на самом деле есть только один способ сделать факториал ....
источник
Perl + C, n = около 3 миллионов
Здесь я использую библиотеку Math :: BigInt :: GMP, доступную на CPAN, которая обеспечивает значительное увеличение скорости для основных объектов Perl Math :: BigInt.
Имейте в виду, что мой компьютер, вероятно, немного медленнее, чем ваш. Используя ваш оригинальный скрипт на Python, я могу вычислить только
factorial(40000)
за 10 секунд;factorial(90000)
занимает намного больше времени (Я нажимаю Ctrl + C через минуту.) На вашем оборудовании, используя Math :: BigInt :: GMP, вы вполне можете рассчитать факториал 5 миллионов и более за менее чем 10 секунд.Вы можете заметить одну вещь: хотя факториал вычисляется невероятно быстро, распечатка результата происходит очень медленно, примерно в три раза дольше, чем первоначальный расчет. Это связано с тем, что GMP внутренне использует двоичное, а не десятичное представление, и для его распечатки требуется преобразование двоичного в десятичное.
источник
Math::BigInt
Python 2.7
5.94 = 1'200'000 / 202'000
Использует относительную легкость умножения многих групп небольших чисел, а затем умножения их по сравнению с большим числом умножений, включающих огромное количество.
источник
C #: 0,48 (77 000/160 000)
Я не доволен этим.
C # это медленно?
Но вот моя запись в любом случае.
Когда n = 77000, требуется
00:00:09:8708952
для расчета.Я работаю в режиме Release, вне Visual Studio, используя Core i3-2330M @ 2.2GHz.
Изменить: так как я не делаю ничего умного, я принимаю этот результат. Может быть, .NET Framework 4.5 требует дополнительных затрат (или BigInteger не так быстр).
источник
n
zero approached by
оператор, чтобы сделать его красивее (например, начать с того, чтоn = ... + 1
делатьwhile (0 <-- n) result *= n;
)bc, оценка = 0,19
Какого черта, вот мой претендент на "Сколько вы можете медленно размножаться?"
bc - это «язык калькулятора произвольной точности», но, к сожалению, довольно медленный:
Примерно за 10 секунд на моем MacBook Pro середины 2012 года (2,3 ГГц Intel Core i7) эталонный ответ Python может вычислить 122000 !, но этот скрипт bc может вычислить только 23600 !.
Наоборот 10000! занимает 1,5 с с помощью сценария Python Reference, но сценарий bc занимает 50 с.
О, Боже.
источник
read()
, поэтому я побежалtime sed 's/read()/28000/' factorial.bc | bc
.Bash: оценка = 0,001206 (181/150000)
Я украл математические функции из Rosettacode - долгое умножение я не анализировал и не пытался оптимизировать.
Вы можете изменить алгоритм или попробовать другой метод разделения строк.
источник
Питон 3, продвинутый алгоритм Питера Лушного: 8.25x (1 280 000/155 000)
Бесстыдно скопировано с Питера Лушного,
http://www.luschny.de/math/factorial/FastFactorialFunctions.htm ,
который предоставляет этот код под лицензией «Creative Commons Attribution-ShareAlike 3.0».
На самом деле это довольно продвинутый алгоритм, использующий то, что называется «раскачивающимся факториалом» и списком простых чисел. Я подозреваю, что это могло бы быть еще быстрее, если бы оно выполняло многие другие ответы и выполняло большинство умножений с 32-битными целыми числами.
источник
Ява - 10,9
n = 885000
Сортировка слиянием у.
BigInteger
с медленнымиРекомендации для высокоскоростных библиотек Java с произвольной точностью? :П
источник
C ++ (для x86_64) - 3,0 (390000/130000)
(легко переносимый на x86-32, портирование на другие архитектуры подразумевает значительную потерю скорости)
Вот моя собственная микро-реализация длинной арифметики.
Само вычисление занимает 10 секунд, и, в то время как вывод находится в легко распечатываемой форме (см.
operator<<
Перегрузку), для его печати требуется еще некоторое время.источник
g++ -O2 factorial.cc -o factorial
и она получила 3,90 = 382000 / 98000.r
увеличения. Если это так, и вы можете сделать большеr
за 10 секунд, то ваш счет снижается.Python 3: 280000/168000
Время запуска вашей программы: между
9.87585953253
и10.3046453994
. Время запуска моей программы: о10.35296977897559
.Я прочитал этот ответ на cs.SE и решил попробовать реализовать его на Python. Тем не менее, я случайно обнаружил, что
n! = (⌊n / 2⌋)! * 2**(⌊n / 2⌋) * n!!
(примечание:!!
это двойной факториал ). Поэтому я преобразовал это в нерекурсивную форму.В комментариях показана моя попытка избежать повторного вычисления двойного факториала, но я обнаружил, что хранение каждого значения было слишком дорогостоящим, что заставляло мой компьютер работать еще медленнее. Я могу улучшить это, только храня то, что нужно.
Странно, я реализовал наивное прямое умножение в Python 3, и оно работает лучше, чем ваша программа:
n = 169000
за 10 секунд.источник
Ruby 2.1
оценка = 1,80 = 176_000 / 98_000
РЕДАКТИРОВАТЬ: улучшено с
1,35 = 132_000 / 98_000Я взял идеи из факторного алгоритма GMP . Эта программа использует стандартную библиотеку для генерации простых чисел. Ruby - плохой выбор, потому что умножение в Ruby кажется медленнее, чем в Python.
Да, мой двоичный файл
ruby 2.1.0p0 (2013-12-25 revision 44422) [x86_64-openbsd]
ссылок против GMP. В Ruby 2.1 добавлена возможность использовать GMP для большого умножения, но он все еще кажется медленнее, чем Python 2.7.источник
Юлия - Счет = 15,194
Используя тот же подход, что и в эталонной программе ... то есть
Таким образом, он использует уменьшение, базовую операцию двоичного умножения и диапазон (в этом случае, используя big (n), чтобы заставить вычисление выполняться в BigInt, а не в Int64). От этого я получаю
На моем компьютере, с эталонной программой работы с вводом 154000, я получаю
Time: 10.041181 sec
выход (бег с использованиемpython ./test.py
, где test.py это имя файла , содержащего код ссылки)источник
ткл, 13757
Мой ответ - проверить пределы tcl.
Первая строка предназначена только для установки входного параметра:
Другие являются самим алгоритмом:
Я проверил свой код на http://rextester.com/live/WEL36956 ; Если я увеличу n, я получу SIGKILL; может n может стать больше на локальном интерпретаторе tcl, которого у меня нет.
источник