Kiểm tra xem một số có phải là một hình vuông hoàn hảo không


Câu trả lời:


117

Vấn đề khi dựa vào bất kỳ phép tính dấu phẩy động nào ( math.sqrt(x)hoặc x**0.5) là bạn không thể thực sự chắc chắn rằng nó chính xác (đối với số nguyên đủ lớn x, nó sẽ không như vậy và thậm chí có thể bị tràn). May mắn thay (nếu ai đó không vội vàng ;-) có nhiều cách tiếp cận số nguyên thuần túy, chẳng hạn như sau ...:

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)

Gợi ý: nó dựa trên "thuật toán Babylon" cho căn bậc hai, xem wikipedia . Nó không làm việc cho bất kỳ số dương mà bạn có đủ bộ nhớ cho việc tính toán để tiến tới hoàn thành ;-).

Chỉnh sửa : hãy xem một ví dụ ...

x = 12345678987654321234567 ** 2

for i in range(x, x+2):
   print i, is_square(i)

bản in này, như mong muốn (và cũng trong một khoảng thời gian hợp lý ;-):

152415789666209426002111556165263283035677489 True
152415789666209426002111556165263283035677490 False

Xin vui lòng, trước khi bạn đưa ra các giải pháp dựa trên dấu chấm kết quả trung gian, chắc chắn rằng họ làm việc một cách chính xác trên ví dụ đơn giản này - nó không phải khó khăn (bạn chỉ cần một vài kiểm tra thêm trong trường hợp sqrt tính là một off ít), chỉ mất một một chút cẩn thận.

Và sau đó thử x**7và tìm ra cách thông minh để giải quyết vấn đề bạn sẽ gặp phải,

OverflowError: long int too large to convert to float

tất nhiên bạn sẽ phải ngày càng thông minh hơn khi các con số tiếp tục tăng lên.

Nếu tôi đang vội, tất nhiên, tôi sẽ sử dụng gmpy - nhưng sau đó, tôi rõ ràng là thành kiến ​​;-).

>>> import gmpy
>>> gmpy.is_square(x**7)
1
>>> gmpy.is_square(x**7 + 1)
0

Vâng, tôi biết, điều đó thật dễ dàng, cảm giác giống như gian lận (một chút cảm giác của tôi đối với Python nói chung ;-) - không thông minh chút nào, chỉ là sự trực tiếp và đơn giản hoàn hảo (và, trong trường hợp gmpy, tốc độ tuyệt đối ; -) ...


Nói những gì bạn muốn về tác giả, gmpy nghe có vẻ như một công cụ tuyệt vời cho nhiệm vụ này.
Mike Graham

3
Phương pháp Babylon hoạt động tốt, nhưng bạn cần phải có các trường hợp đặc biệt cho 0 và 1 để tránh chia cho 0.
mpenkov

2
Nhân tiện, set([x])={x}
Oscar Mederos

6
Không phải là quá mức setcần thiết? Không phải Babylon chỉ hội tụ đến int(sqrt(x)), nơi chúng ta chỉ cần kiểm tra xem prev != next?
Tomasz Gandor

1
"Tôi biết, đó chỉ là dễ dàng để nó cảm thấy như gian lận (một chút cách tôi cảm thấy đối với Python nói chung"; Soo đúng.)
Arulx Z

38

Sử dụng phương pháp Newton để nhanh chóng điền vào căn bậc hai số nguyên gần nhất, sau đó bình phương nó và xem đó có phải là số của bạn không. Xem isqrt .

Python ≥ 3,8 có math.isqrt. Nếu sử dụng phiên bản Python cũ hơn, hãy tìm cách def isqrt(n)triển khai "" tại đây .

import math

def is_square(i: int) -> bool:
    return i == math.isqrt(i) ** 2

20

Vì bạn không bao giờ có thể phụ thuộc vào các phép so sánh chính xác khi xử lý các phép tính dấu phẩy động (chẳng hạn như các cách tính căn bậc hai này), việc triển khai ít lỗi hơn sẽ là

import math

def is_square(integer):
    root = math.sqrt(integer)
    return integer == int(root + 0.5) ** 2

Hãy tưởng tượng integer9. math.sqrt(9)có thể là 3.0, nhưng nó cũng có thể là một cái gì đó giống như 2.99999hoặc 3.00001, vì vậy bình phương kết quả ngay lập tức là không đáng tin cậy. Biết rằng intcó giá trị sàn, tăng giá trị float 0.5trước tiên có nghĩa là chúng ta sẽ nhận được giá trị mà chúng ta đang tìm kiếm nếu chúng ta đang ở trong một phạm vi mà floatvẫn có độ phân giải đủ tốt để đại diện cho các số gần với giá trị mà chúng ta đang tìm kiếm .


5
Nó sẽ là tốt hơn một chút để chỉ làm if int(root + 0.5) ** 2 == integer:nếu inthoạt động như floorcho những con số chúng ta quan tâm.
David Johnstone,

@David Johnstone, tôi đã thay đổi bài đăng này để sử dụng cách triển khai đó, mà tôi đồng ý là đẹp hơn cách cũ mà tôi đã có. Trong mọi trường hợp, một số kỹ thuật khác mà những người khác đề cập ở đây thậm chí còn tốt hơn và đáng tin cậy hơn.
Mike Graham

Tôi hiểu rằng FP là gần đúng, nhưng math.sqrt(9)thực sự có thể là 2.99999? floatBản đồ của Python với C double, nhưng tôi nghĩ rằng ngay cả loại FP 16 bit cũng có độ chính xác cao hơn thế, vì vậy có thể nếu bạn có một trình biên dịch C sử dụng FP 8 bit ("minifloats") làm doubleloại của nó ? Tôi cho rằng về mặt kỹ thuật thì điều đó có thể xảy ra, nhưng đối với tôi thì có vẻ như đó là trường hợp trên bất kỳ máy tính nào chạy Python hiện nay.
Ken

@Ken, tôi đã nói "một cái gì đó giống như" để chỉ ra rằng tôi đang hiểu khái niệm cơ bản; nó không được đảm bảo rằng giá trị bạn nhận được sẽ không nhỏ hơn một chút so với giá trị chính xác. Tôi không thể tưởng tượng rằng điều đó math.sqrt(9)sẽ trả 2.99999về trên bất kỳ hệ thống cụ thể nào, nhưng kết quả thực tế phụ thuộc vào hệ thống và không thể mong đợi là chính xác.
Mike Graham,

1
Hàm này không chính xác đối với một hình vuông lớn, chẳng hạn như 152415789666209426002111556165263283035677489.
Acumenus

12

Nếu bạn quan tâm, tôi có câu trả lời thuần toán cho một câu hỏi tương tự tại math stackexchange, "Phát hiện hình vuông hoàn hảo nhanh hơn bằng cách trích xuất căn bậc hai" .

Việc triển khai isSquare (n) của riêng tôi có thể không phải là tốt nhất, nhưng tôi thích nó. Tôi đã mất vài tháng nghiên cứu về lý thuyết toán học, tính toán kỹ thuật số và lập trình python, so sánh bản thân với những người đóng góp khác, v.v., để thực sự nhấp vào phương pháp này. Tôi thích sự đơn giản và hiệu quả của nó. Tôi không thấy tốt hơn. Nói cho tôi biết bạn nghĩ gì.

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

Khá thẳng về phía trước. Đầu tiên, nó kiểm tra xem chúng ta có một số nguyên và một số dương tại đó hay không. Nếu không thì không có ích lợi gì. Nó cho phép 0 trượt qua là True (cần thiết hoặc khối tiếp theo là vòng lặp vô hạn).

Khối mã tiếp theo loại bỏ lũy thừa của 4 một cách có hệ thống trong một thuật toán con rất nhanh bằng cách sử dụng các phép toán dịch chuyển bit và logic bit. Cuối cùng, chúng ta không tìm thấy isSquare của n ban đầu của chúng ta mà là k <n đã được thu nhỏ theo lũy thừa 4, nếu có thể. Điều này làm giảm kích thước của số chúng tôi đang làm việc và thực sự tăng tốc phương pháp Babylon, nhưng cũng làm cho các kiểm tra khác cũng nhanh hơn.

Khối mã thứ ba thực hiện kiểm tra logic bit Boolean đơn giản. Ba chữ số có nghĩa nhỏ nhất, trong hệ nhị phân, của bất kỳ hình vuông hoàn hảo nào là 001. Luôn luôn. Dù sao, hãy để dành cho các số 0 đứng đầu từ lũy thừa của 4, đã được tính. Nếu nó không thành công trong bài kiểm tra, bạn ngay lập tức biết nó không phải là hình vuông. Nếu nó vượt qua, bạn không thể chắc chắn.

Ngoài ra, nếu chúng ta kết thúc bằng 1 cho giá trị thử nghiệm thì số thử nghiệm ban đầu là lũy thừa của 4, bao gồm cả chính nó có lẽ là 1.

Giống như khối thứ ba, khối thứ tư kiểm tra giá trị một vị trí trong số thập phân bằng cách sử dụng toán tử mô đun đơn giản và có xu hướng bắt các giá trị trượt qua lần kiểm tra trước. Cũng là một thử nghiệm mod 7, mod 8, mod 9 và mod 13.

Khối mã thứ năm kiểm tra một số mẫu hình vuông hoàn hảo nổi tiếng. Các số kết thúc bằng 1 hoặc 9 được đặt trước bội số của bốn. Và các số kết thúc bằng 5 phải kết thúc bằng 5625, 0625, 225 hoặc 025. Tôi đã đưa vào các số khác nhưng nhận ra rằng chúng thừa hoặc không bao giờ thực sự được sử dụng.

Cuối cùng, khối mã thứ sáu rất giống với câu trả lời của người trả lời hàng đầu - Alex Martelli -. Về cơ bản tìm căn bậc hai bằng cách sử dụng thuật toán Babylon cổ đại, nhưng giới hạn nó ở các giá trị nguyên trong khi bỏ qua dấu phẩy động. Thực hiện cho cả tốc độ và mở rộng độ lớn của các giá trị có thể kiểm tra được. Tôi đã sử dụng tập hợp thay vì danh sách vì nó mất ít thời gian hơn nhiều, tôi đã sử dụng dịch chuyển bit thay vì chia cho hai và tôi đã chọn một giá trị bắt đầu ban đầu một cách thông minh hiệu quả hơn nhiều.

Nhân tiện, tôi đã kiểm tra số thử nghiệm được đề xuất của Alex Martelli, cũng như một số con số mà nhiều đơn đặt hàng lớn hơn, chẳng hạn như:

x=1000199838770766116385386300483414671297203029840113913153824086810909168246772838680374612768821282446322068401699727842499994541063844393713189701844134801239504543830737724442006577672181059194558045164589783791764790043104263404683317158624270845302200548606715007310112016456397357027095564872551184907513312382763025454118825703090010401842892088063527451562032322039937924274426211671442740679624285180817682659081248396873230975882215128049713559849427311798959652681930663843994067353808298002406164092996533923220683447265882968239141724624870704231013642255563984374257471112743917655991279898690480703935007493906644744151022265929975993911186879561257100479593516979735117799410600147341193819147290056586421994333004992422258618475766549646258761885662783430625 ** 2
for i in range(x, x+2):
    print(i, isSquare(i))

in các kết quả sau:

1000399717477066534083185452789672211951514938424998708930175541558932213310056978758103599452364409903384901149641614494249195605016959576235097480592396214296565598519295693079257885246632306201885850365687426564365813280963724310434494316592041592681626416195491751015907716210235352495422858432792668507052756279908951163972960239286719854867504108121432187033786444937064356645218196398775923710931242852937602515835035177768967470757847368349565128635934683294155947532322786360581473152034468071184081729335560769488880138928479829695277968766082973795720937033019047838250608170693879209655321034310764422462828792636246742456408134706264621790736361118589122797268261542115823201538743148116654378511916000714911467547209475246784887830649309238110794938892491396597873160778553131774466638923135932135417900066903068192088883207721545109720968467560224268563643820599665232314256575428214983451466488658896488012211237139254674708538347237589290497713613898546363590044902791724541048198769085430459186735166233549186115282574626012296888817453914112423361525305960060329430234696000121420787598967383958525670258016851764034555105019265380321048686563527396844220047826436035333266263375049097675787975100014823583097518824871586828195368306649956481108708929669583308777347960115138098217676704862934389659753628861667169905594181756523762369645897154232744410732552956489694024357481100742138381514396851789639339362228442689184910464071202445106084939268067445115601375050153663645294106475257440167535462278022649865332161044187890625 True
1000399717477066534083185452789672211951514938424998708930175541558932213310056978758103599452364409903384901149641614494249195605016959576235097480592396214296565598519295693079257885246632306201885850365687426564365813280963724310434494316592041592681626416195491751015907716210235352495422858432792668507052756279908951163972960239286719854867504108121432187033786444937064356645218196398775923710931242852937602515835035177768967470757847368349565128635934683294155947532322786360581473152034468071184081729335560769488880138928479829695277968766082973795720937033019047838250608170693879209655321034310764422462828792636246742456408134706264621790736361118589122797268261542115823201538743148116654378511916000714911467547209475246784887830649309238110794938892491396597873160778553131774466638923135932135417900066903068192088883207721545109720968467560224268563643820599665232314256575428214983451466488658896488012211237139254674708538347237589290497713613898546363590044902791724541048198769085430459186735166233549186115282574626012296888817453914112423361525305960060329430234696000121420787598967383958525670258016851764034555105019265380321048686563527396844220047826436035333266263375049097675787975100014823583097518824871586828195368306649956481108708929669583308777347960115138098217676704862934389659753628861667169905594181756523762369645897154232744410732552956489694024357481100742138381514396851789639339362228442689184910464071202445106084939268067445115601375050153663645294106475257440167535462278022649865332161044187890626 False

Và nó đã làm được điều này trong 0,33 giây.

Theo ý kiến ​​của tôi, thuật toán của tôi hoạt động giống như của Alex Martelli, với tất cả các lợi ích của nó, nhưng có thêm lợi ích là từ chối kiểm tra đơn giản hiệu quả cao giúp tiết kiệm rất nhiều thời gian, chưa kể đến việc giảm kích thước của số thử nghiệm theo lũy thừa của 4, cải thiện tốc độ, hiệu quả, độ chính xác và kích thước của các con số có thể kiểm tra được. Có lẽ đặc biệt đúng trong các triển khai không phải Python.

Gần như 99% tất cả các số nguyên bị từ chối là không phải là Hình vuông trước khi thực hiện chiết tách từ gốc Babylon và trong 2/3 thời gian, người Babylon sẽ từ chối số nguyên. Và mặc dù những bài kiểm tra này không tăng tốc quá trình đáng kể, nhưng việc giảm tất cả các số kiểm tra đến số lẻ bằng cách chia tất cả lũy thừa của 4 thực sự đẩy nhanh bài kiểm tra Babylon.

Tôi đã làm một bài kiểm tra so sánh thời gian. Tôi đã thử nghiệm liên tiếp tất cả các số nguyên từ 1 đến 10 Triệu. Chỉ sử dụng phương pháp Babylon (với dự đoán ban đầu được điều chỉnh đặc biệt của tôi), Surface 3 của tôi đã mất trung bình 165 giây (với độ chính xác 100%). Chỉ sử dụng các bài kiểm tra logic trong thuật toán của tôi (không bao gồm Babylon), mất 127 giây, nó từ chối 99% tất cả các số nguyên là không phải là Hình vuông mà không từ chối nhầm bất kỳ hình vuông hoàn hảo nào. Trong số những số nguyên đã qua, chỉ 3% là Hình vuông hoàn hảo (mật độ cao hơn nhiều). Sử dụng thuật toán đầy đủ ở trên sử dụng cả các bài kiểm tra logic và phép chiết xuất từ ​​gốc Babylon, chúng tôi có độ chính xác 100% và hoàn thành bài kiểm tra chỉ trong 14 giây. 100 Triệu số nguyên đầu tiên mất khoảng 2 phút 45 giây để kiểm tra.

CHỈNH SỬA: Tôi đã có thể rút ngắn thời gian hơn nữa. Bây giờ tôi có thể kiểm tra các số nguyên từ 0 đến 100 Triệu trong 1 phút 40 giây. Rất nhiều thời gian bị lãng phí để kiểm tra kiểu dữ liệu và tính tích cực. Loại bỏ hai lần kiểm tra đầu tiên và tôi cắt thử nghiệm xuống một phút. Người ta phải cho rằng người dùng đủ thông minh để biết rằng âm bản và dấu nổi không phải là hình vuông hoàn hảo.


Đối với sự đơn giản, thật khó để đánh bại câu trả lời được chấp nhận. Hiệu suất khôn ngoan, của bạn nên tốt hơn. Tôi hoài nghi về giá trị của việc giảm mục tiêu theo lũy thừa bình phương của các số nguyên tố nhỏ, nhưng tính toán các ký hiệu jacobi cho các số nguyên tố nhỏ sẽ là một chiến thắng. Và những con số càng lớn thì lợi thế cho câu trả lời này càng lớn.
Tổng thống James K. Polk

1
Cần giảm theo lũy thừa của các số nguyên tố nhỏ để tính toán ký hiệu jacobi để cung cấp kết quả xác định. Nếu không thì nó ở mức xác suất tốt nhất, hoặc xác định cho tính không bình phương, nhưng không xác minh tính bình phương. Đó là một phần lý do tại sao tôi tính toán theo quyền hạn của bình phương; các ký hiệu jacobi duy nhất mà tôi tính toán là cho các số nguyên tố nhỏ giống nhau mà tôi tính toán. Tôi cũng làm điều đó đơn giản để giảm kích thước của số thử nghiệm để làm cho phương pháp Babylon được sử dụng sau này nhanh hơn một chút (nhưng điều đó còn gây tranh cãi).
CogitoErgoCogitoSum

Chà, đó chắc chắn là một câu trả lời hay và độc đáo và nếu tôi có chút thời gian trong tương lai, tôi muốn giải quyết vấn đề này, hãy thử một số thời gian thay đổi số lượng số nguyên tố nhỏ để xem liệu có thể tìm thấy một số tối ưu ở một kích thước bit nhất định không .
Tổng thống James K. Polk,

Bằng mọi cách, hãy kiểm tra mã của tôi. Phá vỡ nó. Tôi không phải là một lập trình viên theo thương mại, tôi là một chuyên gia toán học. Trăn chỉ là một sở thích. Tôi rất tò mò xem nó có hiệu quả hơn trung bình không.
CogitoErgoCogitoSum

1
Nếu bạn vẫn quan tâm đến cơ bản có một câu hỏi trùng lặp ở đây với một số câu trả lời thú vị, đặc biệt là câu trả lời của A.Rex .
Tổng thống James K. Polk

12
import math

def is_square(n):
    sqrt = math.sqrt(n)
    return (sqrt - int(sqrt)) == 0

Hình vuông hoàn hảo là một số có thể được biểu thị dưới dạng tích của hai số nguyên bằng nhau. math.sqrt(number)trả lại a float. int(math.sqrt(number))đưa kết quả đếnint .

Nếu căn bậc hai là một số nguyên, chẳng hạn như 3, thì math.sqrt(number) - int(math.sqrt(number))sẽ là 0 và ifcâu lệnh sẽ là False. Nếu căn bậc hai là một số thực như 3.2, thì nó sẽ là Truevà in ra "nó không phải là một hình vuông hoàn hảo".

Nó không thành công đối với một không phải hình vuông lớn như 152415789666209426002111556165263283035677490.


Thay đổi if (math.sqrt(number)-int(math.sqrt(number))):để a=math.sqrt(number)sau đó một dòng khác cho: if a-int(a):. Đây là vì nó chỉ có để tính căn bậc hai lần, mà imo cho n lớn có ý nghĩa
unseen_rider

@JamesKPolk Tại sao vậy?
user1717828

Tôi khá chắc chắn rằng sqrt - int (sqrt) giống với sqrt% 1. Toàn bộ hàm của bạn có thể chỉ là trả về math.sqrt (n)% 1 == 0
CogitoErgoCogitoSum

6

Câu trả lời của tôi là:

def is_square(x):
    return x**.5 % 1 == 0

Về cơ bản, nó thực hiện một căn bậc hai, sau đó modulo bằng 1 để loại bỏ phần nguyên và nếu kết quả là 0 Truethì trả về ngược lại False. Trong trường hợp này x có thể là bất kỳ số lớn nào, chỉ không lớn bằng số thực tối đa mà python có thể xử lý: 1.7976931348623157e + 308

Nó không chính xác cho một không phải hình vuông lớn như 152415789666209426002111556165263283035677490.


5

Điều này có thể được giải quyết bằng các decimalmô-đun để lấy rễ chính xác vuông tùy ý và kiểm tra dễ dàng cho "tính chính xác":

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]

Để trình diễn với những giá trị thực sự to lớn:

# 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

Nếu bạn tăng kích thước của giá trị đang được kiểm tra, điều này cuối cùng sẽ khá chậm (mất gần một giây cho hình vuông 200.000 bit), nhưng đối với những con số vừa phải hơn (ví dụ, 20.000 bit), nó vẫn nhanh hơn con người sẽ nhận thấy các giá trị riêng lẻ (~ 33 ms trên máy của tôi). Nhưng vì tốc độ không phải là mối quan tâm chính của bạn, nên đây là một cách tốt để làm điều đó với các thư viện chuẩn của Python.

Tất nhiên, sẽ nhanh hơn nhiều khi sử dụng gmpy2và chỉ cần kiểm tra gmpy2.mpz(x).is_square(), nhưng nếu các gói của bên thứ ba không phải là thứ của bạn, thì các cách trên hoạt động khá tốt.


5

Tôi chỉ đăng một biến thể nhỏ đối với một số ví dụ ở trên trên một chủ đề khác ( Tìm các hình vuông hoàn hảo ) và nghĩ rằng tôi sẽ bao gồm một biến thể nhỏ của những gì tôi đã đăng ở đây (sử dụng nsqrt làm biến tạm thời), trong trường hợp nó quan tâm / sử dụng:

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)

Nó không chính xác cho một không phải hình vuông lớn như 152415789666209426002111556165263283035677490.


2

Đây là phương pháp của tôi:

def is_square(n) -> bool:
    return int(n**0.5)**2 == int(n)

Lấy căn bậc hai của số. Chuyển đổi thành số nguyên. Đi theo hình vuông. Nếu các số bằng nhau thì nó là một hình vuông hoàn hảo, ngược lại thì không.

Nó không chính xác cho một hình vuông lớn chẳng hạn như 152415789666209426002111556165263283035677489.


Sẽ không hoạt động đối với số âm nhưng vẫn là một giải pháp tuyệt vời!
Rick M.

1

Bạn có thể tìm kiếm nhị phân cho căn bậc hai làm tròn. Bình phương kết quả để xem nó có khớp với giá trị ban đầu hay không.

Có lẽ bạn sẽ tốt hơn với câu trả lời của FogleBirds - mặc dù hãy cẩn thận, vì số học dấu phẩy động là gần đúng, có thể loại bỏ phương pháp này. Về nguyên tắc, bạn có thể nhận được một số dương sai từ một số nguyên lớn hơn một hình vuông hoàn hảo, chẳng hạn, do mất độ chính xác.


1

Nếu môđun (phần dư) còn lại từ phép chia cho căn bậc hai là 0, thì nó là một hình vuông hoàn hảo.

def is_square(num: int) -> bool:
    return num % math.sqrt(num) == 0

Tôi đã kiểm tra điều này với một danh sách các ô vuông hoàn hảo lên đến 1000.


0
  1. Quyết định con số sẽ là bao lâu.
  2. lấy một đồng bằng 0,000000000000 ....... 000001
  3. xem (sqrt (x)) ^ 2 - x lớn hơn / bằng / nhỏ hơn delta hay không và quyết định dựa trên lỗi delta.

0

Câu trả lời này không liên quan đến câu hỏi đã nêu của bạn, nhưng đối với một câu hỏi ngầm mà tôi thấy trong mã bạn đã đăng, tức là "làm thế nào để kiểm tra xem một cái gì đó có phải là số nguyên hay không?"

Câu trả lời đầu tiên mà bạn thường nhận được cho câu hỏi đó là "Đừng!" Và đúng là trong Python, việc đánh máy thường không phải là điều đúng đắn.

Tuy nhiên, đối với những trường hợp ngoại lệ hiếm hoi đó, thay vì tìm kiếm dấu thập phân trong biểu diễn chuỗi của số, điều cần làm là sử dụng hàm isinstance :

>>> isinstance(5,int)
True
>>> isinstance(5.0,int)
False

Tất nhiên điều này áp dụng cho biến hơn là một giá trị. Nếu tôi muốn xác định xem giá trị có phải là số nguyên hay không, tôi sẽ làm như sau:

>>> x=5.0
>>> round(x) == x
True

Nhưng như những người khác đã trình bày chi tiết, có những vấn đề dấu phẩy động cần được xem xét trong hầu hết các ví dụ không phải đồ chơi về loại vật này.


1
"Điều này áp dụng cho biến thay vì giá trị" có nghĩa là gì? Bạn có thể sử dụng round (5.0) == 5.0 và isinstance (x, int) mà không gặp vấn đề gì. (Và OOWTDI chỉ để gọi x.is_integer ().)
Veky

0

Nếu bạn muốn lặp qua một phạm vi và thực hiện điều gì đó với mọi số KHÔNG phải là một hình vuông hoàn hảo, bạn có thể làm như sau:

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ếu bạn muốn làm điều gì đó cho mỗi số LÀ một hình vuông hoàn hảo, trình tạo thậm chí còn dễ dàng hơn:

(n * n for n in range(upper))

0

Tôi nghĩ rằng điều này hoạt động và rất đơn giản:

import math

def is_square(num):
    sqrt = math.sqrt(num)
    return sqrt == int(sqrt)

Nó không chính xác cho một không phải hình vuông lớn như 152415789666209426002111556165263283035677490.


Điều này giống như câu trả lời trên.
Kowalski

0

Một biến thể của giải pháp @Alex Martelli không có set

Khi nào x in seenTrue:

  • Trong hầu hết các trường hợp, nó là số cuối cùng được thêm vào, ví dụ: 1022 tạo ra xchuỗi của 511, 256, 129, 68, 41, 32, 31 , 31 ;
  • Trong một số trường hợp (ví dụ: đối với các hình vuông hoàn hảo trước đó), nó là hình vuông thứ hai đến cuối cùng được thêm vào, ví dụ: 1023 tạo ra 511, 256, 129, 68, 41, 32 , 31, 32 .

Do đó, nó đủ để dừng ngay khi dòng điện xlớn hơn hoặc bằng dòng điện trước đó:

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)

Tương đương với thuật toán ban đầu được thử nghiệm cho 1 <n <10 ** 7. Trong cùng một khoảng thời gian, biến thể đơn giản hơn một chút này nhanh hơn khoảng 1,4 lần.


0
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')

Mặc dù mã này có thể giải quyết được vấn đề, một câu trả lời tốt cũng nên giải thích những gì mã lệnh thực hiện và cách nó giúp.
BDL

0

Ý tưởng là chạy một vòng lặp từ i = 1 đến tầng (sqrt (n)) sau đó kiểm tra xem bình phương nó có tạo ra n hay không.

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; 
} 

-3
import math

def is_square(n):
    sqrt = math.sqrt(n)
    return sqrt == int(sqrt)

Nó không thành công đối với một không phải hình vuông lớn như 152415789666209426002111556165263283035677490.


2
Đây là một câu trả lời chỉ có mã. Vui lòng cung cấp một chút lý luận.
hotzst

Bạn không thể lý giải theo cách của mình thông qua @hotzst đó? Nó có ý nghĩa hoàn hảo và tôi thậm chí không phải là một chuyên gia về trăn. Nó không phải là bài kiểm tra lớn nhất nhưng nó có giá trị cả về lý thuyết và đối với các trường hợp nhỏ.
CogitoErgoCogitoSum

1
@CogitoErgoCogitoSum: Bạn không hiểu. Các câu trả lời chỉ có mã không được tìm thấy bằng các tìm kiếm sử dụng các công cụ tìm kiếm như google. Cho dù người ta có thể hiểu câu trả lời là không liên quan.
Tổng thống James K. Polk
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.