Як я можу перевірити, чи є число ідеальним квадратом?
Швидкість не турбує, поки що просто працюю.
Як я можу перевірити, чи є число ідеальним квадратом?
Швидкість не турбує, поки що просто працюю.
Відповіді:
Проблема покладання на будь-яке обчислення з плаваючою точкою ( math.sqrt(x)
, або x**0.5
) полягає в тому, що ви насправді не можете бути впевнені, що воно є точним (для досить великих цілих чисел x
це не буде, а може навіть переповнюватися). На щастя (якщо хтось не поспішає ;-), існує безліч цілочисельних підходів, таких як наступні ...:
def is_square(apositiveint):
x = apositiveint // 2
seen = set([x])
while x * x != apositiveint:
x = (x + (apositiveint // x)) // 2
if x in seen: return False
seen.add(x)
return True
for i in range(110, 130):
print i, is_square(i)
Підказка: він базується на "вавілонському алгоритмі" для квадратного кореня, див. Wikipedia . Це робить роботу для будь-якого позитивного числа , для яких у вас є достатньо пам'яті для обчислення , щоб перейти до завершення ;-).
Редагувати : давайте подивимось приклад ...
x = 12345678987654321234567 ** 2
for i in range(x, x+2):
print i, is_square(i)
друкується за бажанням (і через розумний проміжок часу ;-):
152415789666209426002111556165263283035677489 True
152415789666209426002111556165263283035677490 False
Будь ласка, перш ніж пропонувати рішення на основі плаваючою комою проміжних результатів, переконайтеся , що вони коректно працюють на цьому простому прикладі - це не що важко (вам просто потрібно кілька додаткових перевірок в разі SQRT обчислений трохи вимкнений), просто займає трохи догляду.
А потім спробуйте x**7
знайти розумний спосіб вирішити проблему, яку ви отримаєте,
OverflowError: long int too large to convert to float
Вам доведеться ставати дедалі розумнішими, оскільки цифри постійно зростають, звичайно.
Якби я був в поспіху, звичайно, я хотів би використовувати gmpy - але тоді я явно упередженим ;-).
>>> import gmpy
>>> gmpy.is_square(x**7)
1
>>> gmpy.is_square(x**7 + 1)
0
Так, я знаю, це настільки просто, що це схоже на шахрайство (трохи так, як я почуваюся до Python загалом ;-) - взагалі ніякої кмітливості, просто ідеальна прямота та простота (і, у випадку з gmpy, чиста швидкість ; -) ...
set([x])
={x}
set
надмірне? Чи не просто сходиться Вавилон int(sqrt(x))
, де нам просто потрібно перевірити, чи не так prev != next
?
Використовуйте метод Ньютона, щоб швидко обнулити найближчий цілочисельний квадратний корінь, потім встановити його в квадрат і перевірити, чи це ваше число. Дивіться isqrt .
Python ≥ 3,8 має math.isqrt
. Якщо ви використовуєте стару версію Python, знайдіть " def isqrt(n)
" реалізацію тут .
import math
def is_square(i: int) -> bool:
return i == math.isqrt(i) ** 2
Оскільки ви ніколи не можете залежати від точних порівнянь, маючи справу з обчисленнями з плаваючою комою (наприклад, ці способи обчислення квадратного кореня), реалізація, менш схильна до помилок, буде
import math
def is_square(integer):
root = math.sqrt(integer)
return integer == int(root + 0.5) ** 2
Уявіть, що integer
є 9
. math.sqrt(9)
може бути 3.0
, але це може бути щось на кшталт 2.99999
або 3.00001
, тому відрахування результатів відразу не є надійним. Знаючи цеint
приймає мінімальне значення, 0.5
спочатку збільшивши плаваюче значення, ми отримаємо значення, яке ми шукаємо, якщо ми знаходимось в діапазоні, де float
все ще є достатньо точна роздільна здатність, щоб представити числа поблизу тієї, для якої ми шукаємо .
if int(root + 0.5) ** 2 == integer:
якщо int
діятиме як floor
щодо цифр, про які ми дбаємо.
math.sqrt(9)
це бути коли-небудь 2.99999
? Python float
відображає C double
, але я думаю, що навіть 16-розрядний тип FP має більшу точність, ніж це, то, можливо, якщо у вас був компілятор C, який використовував 8-бітний FP ("мініфлоти") як свій double
тип? Я гадаю, що це технічно можливо, але мені здається малоймовірним, що це стосується будь-якого комп’ютера, на якому сьогодні працює Python.
math.sqrt(9)
це повернеться 2.99999
для будь-якої конкретної системи, але фактичний результат залежить від системи, і не можна очікувати, що він буде точним.
Якщо вас цікавить, я маю чисто математичну відповідь на подібне запитання в математичному стек-біржі: "Виявлення ідеальних квадратів швидше, ніж шляхом вилучення квадратного кореня" .
Моя власна реалізація isSquare (n) може бути не найкращою, але мені це подобається. Мені знадобилося кілька місяців вивчення теорії математики, цифрових обчислень та програмування на пітоні, порівняння з іншими співавторами тощо, щоб справді натиснути на цей метод. Мені подобається простота та ефективність. Я не бачив кращого. Скажи мені, що ти думаєш.
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 <n, який, якщо це можливо, був зменшений степенями 4. Це зменшує розмір числа, з яким ми працюємо, і дійсно пришвидшує вавилонський метод, але також пришвидшує інші перевірки.
Третій блок коду виконує простий логічний тест бітової логіки. Найменш значущими трьома цифрами в двійковому вигляді будь-якого ідеального квадрата є 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 секунд для тестування.
EDIT: Я зміг скоротити час далі. Тепер я можу перевірити цілі числа від 0 до 100 мільйонів за 1 хвилину 40 секунд. Багато часу витрачається на перевірку типу даних та позитиву. Усуньте перші дві перевірки, і я скоротив експеримент на хвилину. Потрібно припустити, що користувач досить розумний, щоб знати, що негативи та плаваючі позиції не є ідеальними квадратами.
import math
def is_square(n):
sqrt = math.sqrt(n)
return (sqrt - int(sqrt)) == 0
Ідеальний квадрат - це число, яке можна виразити як добуток двох рівних цілих чисел. math.sqrt(number)
повернути a float
. int(math.sqrt(number))
визначає результат int
.
Якщо квадратним коренем є ціле число, наприклад 3, наприклад, тоді math.sqrt(number) - int(math.sqrt(number))
буде 0, а if
оператор буде False
. Якщо квадратний корінь був дійсним числом, таким як 3.2, тоді він буде True
і надрукує "це не ідеальний квадрат".
Це не вдається для великих неквадратичних, таких як 152415789666209426002111556165263283035677490.
if (math.sqrt(number)-int(math.sqrt(number))):
в a=math.sqrt(number)
іншу лінію для: if a-int(a):
. Це тому, що йому потрібно лише один раз обчислити квадратний корінь, що imo для великих n є значущим
Моя відповідь:
def is_square(x):
return x**.5 % 1 == 0
В основному він виконує квадратний корінь, а потім за модулем на 1, щоб позбавити цілочисельної частини, і якщо результат 0, повертається True
інакше False
. У цьому випадку x може бути будь-яким великим числом, лише не таким великим, як максимальне число з плаваючою здатністю, яке python може обробити: 1.7976931348623157e + 308
Неправильно для великого неквадратичного приміщення, такого як 152415789666209426002111556165263283035677490.
Це можна вирішити за допомогою decimal
модуля для отримання довільної точності квадратних коренів та легкої перевірки на "точність":
import math
from decimal import localcontext, Context, Inexact
def is_perfect_square(x):
# If you want to allow negative squares, then set x = abs(x) instead
if x < 0:
return False
# Create localized, default context so flags and traps unset
with localcontext(Context()) as ctx:
# Set a precision sufficient to represent x exactly; `x or 1` avoids
# math domain error for log10 when x is 0
ctx.prec = math.ceil(math.log10(x or 1)) + 1 # Wrap ceil call in int() on Py2
# Compute integer square root; don't even store result, just setting flags
ctx.sqrt(x).to_integral_exact()
# If previous line couldn't represent square root as exact int, sets Inexact flag
return not ctx.flags[Inexact]
Для демонстрації з справді величезними цінностями:
# I just kept mashing the numpad for awhile :-)
>>> base = 100009991439393999999393939398348438492389402490289028439083249803434098349083490340934903498034098390834980349083490384903843908309390282930823940230932490340983098349032098324908324098339779438974879480379380439748093874970843479280329708324970832497804329783429874329873429870234987234978034297804329782349783249873249870234987034298703249780349783497832497823497823497803429780324
>>> sqr = base ** 2
>>> sqr ** 0.5 # Too large to use floating point math
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
OverflowError: int too large to convert to float
>>> is_perfect_power(sqr)
True
>>> is_perfect_power(sqr-1)
False
>>> is_perfect_power(sqr+1)
False
Якщо збільшити розмір випробовуваного значення, це врешті-решт стає досить повільним (займає близько секунди для 200 000 бітових квадратів), але для більш помірних чисел (скажімо, 20 000 бітів) це все одно швидше, ніж людина помітила б для індивідуальні значення (~ 33 мс на моїй машині). Але оскільки швидкість не була вашим головним завданням, це хороший спосіб зробити це за допомогою стандартних бібліотек Python.
Звичайно, це було б набагато швидше використовувати gmpy2
і просто протестувати gmpy2.mpz(x).is_square()
, але якщо сторонні пакети - це не ваша річ, вищезазначене працює досить добре.
Я просто опублікував невелику варіацію деяких прикладів вище в іншому потоці ( Пошук ідеальних квадратів ) і подумав, що включу невелику варіацію того, що я розмістив тут (використовуючи nsqrt як тимчасову змінну), на випадок, якщо це цікавить / використання:
import math
def is_square(n):
if not (isinstance(n, int) and (n >= 0)):
return False
else:
nsqrt = math.sqrt(n)
return nsqrt == math.trunc(nsqrt)
Неправильно для великого неквадратичного приміщення, такого як 152415789666209426002111556165263283035677490.
Це мій метод:
def is_square(n) -> bool:
return int(n**0.5)**2 == int(n)
Візьміть квадратний корінь із числа. Перетворити на ціле число. Візьміть квадрат. Якщо числа рівні, то це ідеальний квадрат, інакше ні.
Неправильно для великого квадрата, наприклад 152415789666209426002111556165263283035677489.
Ви можете двійково шукати округлий квадратний корінь. Зробіть результат результатом, щоб перевірити, чи відповідає він початковому значенню.
Вам, мабуть, краще з відповіддю FogleBirds - хоча будьте обережні, оскільки арифметика з плаваючою крапкою є приблизною, що може викинути цей підхід. В принципі, ви можете отримати хибне позитивне з великого цілого числа, яке більше, ніж ідеальний квадрат, наприклад, через втрату точності.
Якщо модуль (залишок), що залишився від ділення на квадратний корінь, дорівнює 0, то це ідеальний квадрат.
def is_square(num: int) -> bool:
return num % math.sqrt(num) == 0
Я перевірив це на основі списку ідеальних квадратів, що збільшуються до 1000.
Ця відповідь стосується не вашого заявленого питання, а неявного питання, яке я бачу в коді, який ви опублікували, тобто "як перевірити, чи є щось цілим?"
Перша відповідь, яку ви зазвичай отримаєте на це запитання, - "Не!" І це правда, що в Python перевірка набору текстів зазвичай не є правильною.
Однак для цих рідкісних винятків замість того, щоб шукати десяткову крапку в рядковому поданні числа, потрібно скористатися функцією isinstance :
>>> isinstance(5,int)
True
>>> isinstance(5.0,int)
False
Звичайно, це стосується змінної, а не значення. Якби я хотів визначити, чи є значення цілим числом, я б зробив це:
>>> x=5.0
>>> round(x) == x
True
Але, як усі інші детально висвітлювали, у більшості неіграшкових прикладів подібних речей є питання з плаваючою крапкою.
Якщо ви хочете прокрутити діапазон і зробити щось для кожного числа, яке НЕ є ідеальним квадратом, ви можете зробити щось подібне:
def non_squares(upper):
next_square = 0
diff = 1
for i in range(0, upper):
if i == next_square:
next_square += diff
diff += 2
continue
yield i
Якщо ви хочете зробити щось для кожного числа, яке є ідеальним квадратом, генератор ще простіше:
(n * n for n in range(upper))
Я думаю, що це працює і дуже просто:
import math
def is_square(num):
sqrt = math.sqrt(num)
return sqrt == int(sqrt)
Неправильно для великого неквадратичного приміщення, такого як 152415789666209426002111556165263283035677490.
set
Коли x in seen
є True
:
x
послідовність 511, 256, 129, 68, 41, 32, 31 , 31 ;Отже, достатньо зупинитися, як тільки сила струму x
буде більшою або дорівнює попередній:
def is_square(n):
assert n > 1
previous = n
x = n // 2
while x * x != n:
x = (x + (n // x)) // 2
if x >= previous:
return False
previous = x
return True
x = 12345678987654321234567 ** 2
assert not is_square(x-1)
assert is_square(x)
assert not is_square(x+1)
Еквівалентність оригінальному алгоритму, перевіреному для 1 <n <10 ** 7. На тому ж інтервалі цей трохи простіший варіант приблизно в 1,4 рази швидший.
a=int(input('enter any number'))
flag=0
for i in range(1,a):
if a==i*i:
print(a,'is perfect square number')
flag=1
break
if flag==1:
pass
else:
print(a,'is not perfect square number')
Ідея полягає в тому, щоб запустити цикл від i = 1 до поверху (sqrt (n)), а потім перевірити, чи становить квадрат його n.
bool isPerfectSquare(int n)
{
for (int i = 1; i * i <= n; i++) {
// If (i * i = n)
if ((n % i == 0) && (n / i == i)) {
return true;
}
}
return false;
}
import math
def is_square(n):
sqrt = math.sqrt(n)
return sqrt == int(sqrt)
Це не вдається для великих неквадратичних, таких як 152415789666209426002111556165263283035677490.