Если вам интересно, у меня есть чисто математический ответ на аналогичный вопрос в math stack exchange Exchange: «Обнаружение идеальных квадратов быстрее, чем путем извлечения квадратного корня» .
Моя собственная реализация isSquare (n) может быть не самой лучшей, но мне она нравится. Мне потребовалось несколько месяцев изучения математической теории, цифровых вычислений и программирования на Python, сравнивая себя с другими участниками и т. Д., Чтобы по-настоящему использовать этот метод. Мне нравится его простота и эффективность, хотя. Я не видел лучше. Скажи мне, что ты думаешь.
def isSquare(n):
## Trivial checks
if type(n) != int: ## integer
return False
if n < 0: ## positivity
return False
if n == 0: ## 0 pass
return True
## Reduction by powers of 4 with bit-logic
while n&3 == 0:
n=n>>2
## Simple bit-logic test. All perfect squares, in binary,
## end in 001, when powers of 4 are factored out.
if n&7 != 1:
return False
if n==1:
return True ## is power of 4, or even power of 2
## Simple modulo equivalency test
c = n%10
if c in {3, 7}:
return False ## Not 1,4,5,6,9 in mod 10
if n % 7 in {3, 5, 6}:
return False ## Not 1,2,4 mod 7
if n % 9 in {2,3,5,6,8}:
return False
if n % 13 in {2,5,6,7,8,11}:
return False
## Other patterns
if c == 5: ## if it ends in a 5
if (n//10)%10 != 2:
return False ## then it must end in 25
if (n//100)%10 not in {0,2,6}:
return False ## and in 025, 225, or 625
if (n//100)%10 == 6:
if (n//1000)%10 not in {0,5}:
return False ## that is, 0625 or 5625
else:
if (n//10)%4 != 0:
return False ## (4k)*10 + (1,9)
## Babylonian Algorithm. Finding the integer square root.
## Root extraction.
s = (len(str(n))-1) // 2
x = (10**s) * 4
A = {x, n}
while x * x != n:
x = (x + (n // x)) >> 1
if x in A:
return False
A.add(x)
return True
Довольно прямо. Сначала он проверяет, что у нас есть целое и положительное число. Иначе нет смысла. Он пропускает 0 как True (необходимо, иначе следующий блок - бесконечный цикл).
Следующий блок кода систематически удаляет степени 4 в очень быстром под-алгоритме, использующем битовые сдвиги и битовые логические операции. В конечном итоге мы не находим isSquare нашего исходного n, а k
Третий блок кода выполняет простой логический битовый тест. Наименее значимые три цифры в двоичном коде любого идеального квадрата - 001. Всегда. В любом случае, за исключением начальных нулей, возникающих из степеней 4, которые уже были учтены. Если тест не пройден, вы сразу узнаете, что это не квадрат. Если это пройдет, вы не можете быть уверены.
Кроме того, если мы получим 1 для тестового значения, тогда тестовый номер первоначально был степенью 4, включая, возможно, саму 1.
Как и в третьем блоке, четвертый проверяет однозначное значение в десятичном виде с помощью простого оператора модуля и стремится отловить значения, которые проскальзывают в предыдущем тесте. Также тест мод 7, мод 8, мод 9 и мод 13.
Пятый блок кода проверяет некоторые из известных шаблонов совершенных квадратов. Числам, оканчивающимся на 1 или 9, предшествует число, кратное четырем. А числа, оканчивающиеся на 5, должны заканчиваться на 5625, 0625, 225 или 025. Я включил другие, но понял, что они избыточны или никогда не использовались.
Наконец, шестой блок кода очень напоминает ответ главного мэра Алекса Мартелли. В основном находит квадратный корень, используя древний вавилонский алгоритм, но ограничивая его целочисленными значениями, игнорируя с плавающей запятой. Сделано как для скорости, так и для увеличения величин проверяемых величин. Я использовал наборы вместо списков, потому что это занимает гораздо меньше времени, я использовал сдвиги битов вместо деления на два, и я более умно выбрал начальное начальное значение гораздо более эффективно.
Кстати, я проверил рекомендованный тестовый номер Алекса Мартелли, а также несколько чисел на много порядков больше, например:
x=1000199838770766116385386300483414671297203029840113913153824086810909168246772838680374612768821282446322068401699727842499994541063844393713189701844134801239504543830737724442006577672181059194558045164589783791764790043104263404683317158624270845302200548606715007310112016456397357027095564872551184907513312382763025454118825703090010401842892088063527451562032322039937924274426211671442740679624285180817682659081248396873230975882215128049713559849427311798959652681930663843994067353808298002406164092996533923220683447265882968239141724624870704231013642255563984374257471112743917655991279898690480703935007493906644744151022265929975993911186879561257100479593516979735117799410600147341193819147290056586421994333004992422258618475766549646258761885662783430625 ** 2
for i in range(x, x+2):
print(i, isSquare(i))
напечатаны следующие результаты:
1000399717477066534083185452789672211951514938424998708930175541558932213310056978758103599452364409903384901149641614494249195605016959576235097480592396214296565598519295693079257885246632306201885850365687426564365813280963724310434494316592041592681626416195491751015907716210235352495422858432792668507052756279908951163972960239286719854867504108121432187033786444937064356645218196398775923710931242852937602515835035177768967470757847368349565128635934683294155947532322786360581473152034468071184081729335560769488880138928479829695277968766082973795720937033019047838250608170693879209655321034310764422462828792636246742456408134706264621790736361118589122797268261542115823201538743148116654378511916000714911467547209475246784887830649309238110794938892491396597873160778553131774466638923135932135417900066903068192088883207721545109720968467560224268563643820599665232314256575428214983451466488658896488012211237139254674708538347237589290497713613898546363590044902791724541048198769085430459186735166233549186115282574626012296888817453914112423361525305960060329430234696000121420787598967383958525670258016851764034555105019265380321048686563527396844220047826436035333266263375049097675787975100014823583097518824871586828195368306649956481108708929669583308777347960115138098217676704862934389659753628861667169905594181756523762369645897154232744410732552956489694024357481100742138381514396851789639339362228442689184910464071202445106084939268067445115601375050153663645294106475257440167535462278022649865332161044187890625 True
1000399717477066534083185452789672211951514938424998708930175541558932213310056978758103599452364409903384901149641614494249195605016959576235097480592396214296565598519295693079257885246632306201885850365687426564365813280963724310434494316592041592681626416195491751015907716210235352495422858432792668507052756279908951163972960239286719854867504108121432187033786444937064356645218196398775923710931242852937602515835035177768967470757847368349565128635934683294155947532322786360581473152034468071184081729335560769488880138928479829695277968766082973795720937033019047838250608170693879209655321034310764422462828792636246742456408134706264621790736361118589122797268261542115823201538743148116654378511916000714911467547209475246784887830649309238110794938892491396597873160778553131774466638923135932135417900066903068192088883207721545109720968467560224268563643820599665232314256575428214983451466488658896488012211237139254674708538347237589290497713613898546363590044902791724541048198769085430459186735166233549186115282574626012296888817453914112423361525305960060329430234696000121420787598967383958525670258016851764034555105019265380321048686563527396844220047826436035333266263375049097675787975100014823583097518824871586828195368306649956481108708929669583308777347960115138098217676704862934389659753628861667169905594181756523762369645897154232744410732552956489694024357481100742138381514396851789639339362228442689184910464071202445106084939268067445115601375050153663645294106475257440167535462278022649865332161044187890626 False
И он сделал это за 0,33 секунды.
По моему мнению, мой алгоритм работает так же, как алгоритм Алекса Мартелли, со всеми его преимуществами, но имеет дополнительное преимущество - высокоэффективные отклонения простых тестов, которые экономят много времени, не говоря уже об уменьшении размера тестовых чисел. степенями 4, что повышает скорость, эффективность, точность и размер проверяемых чисел. Вероятно, особенно актуально в не-Python реализациях.
Примерно 99% всех целых чисел отбрасываются как неквадратные, прежде чем даже вавилонское извлечение корней будет реализовано, и в 2/3 времени потребуется вавилонское отклонение целого числа. И хотя эти тесты не значительно ускоряют процесс, сокращение всех тестовых чисел до нечетного путем деления всех степеней 4 на самом деле ускоряет вавилонский тест.
Я сделал тест сравнения времени. Я проверил все целые числа от 1 до 10 миллионов подряд. Используя сам по себе вавилонский метод (с моей специально разработанной первоначальной догадкой), для моего Surface 3 потребовалось в среднем 165 секунд (со 100% точностью). Используя только логические тесты в моем алгоритме (исключая вавилонский), это заняло 127 секунд, он отклонил 99% всех целых чисел как неквадратные, по ошибке не отклонив ни одного идеального квадрата. Из тех целых чисел, которые прошли, только 3% были идеальными квадратами (гораздо более высокой плотности). Используя приведенный выше полный алгоритм, который использует как логические тесты, так и извлечение вавилонских корней, мы получаем 100% точность и завершение теста всего за 14 секунд. На первые 100 миллионов целых чисел уходит примерно 2 минуты 45 секунд.
РЕДАКТИРОВАТЬ: я смог сократить время дальше. Теперь я могу проверить целые числа от 0 до 100 миллионов за 1 минуту 40 секунд. Много времени тратится на проверку типа данных и положительности. Откажитесь от первых двух проверок, и я сократил эксперимент на минуту. Нужно предположить, что пользователь достаточно умен, чтобы знать, что негативы и плавающие числа не являются идеальными квадратами.