จะตรวจสอบได้อย่างไรว่าตัวเลขเป็นกำลังสองสมบูรณ์
ความเร็วไม่น่ากังวลตอนนี้ใช้งานได้
จะตรวจสอบได้อย่างไรว่าตัวเลขเป็นกำลังสองสมบูรณ์
ความเร็วไม่น่ากังวลตอนนี้ใช้งานได้
คำตอบ:
ปัญหาในการใช้การคำนวณจุดลอยตัวใด ๆ ( 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)
คำแนะนำ: มันขึ้นอยู่กับ "อัลกอริทึมบาบิโลน" สำหรับรากที่ดูวิกิพีเดีย มันใช้งานได้กับจำนวนบวกใด ๆ ที่คุณมีหน่วยความจำเพียงพอสำหรับการคำนวณเพื่อดำเนินการให้เสร็จสมบูรณ์ ;-)
แก้ไข : มาดูตัวอย่าง ...
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
. ถ้าใช้รุ่นเก่าของงูใหญ่ให้มองหา " 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
เหรอ? float
แมปของ Python กับ C double
แต่ฉันคิดว่าแม้แต่ประเภท FP 16 บิตก็มีความแม่นยำมากกว่านั้นดังนั้นบางทีถ้าคุณมีคอมไพเลอร์ C ที่ใช้ FP 8 บิต ("minifloats") เป็นdouble
ประเภท? ฉันคิดว่ามันเป็นไปได้ในทางเทคนิค แต่ดูเหมือนว่าฉันไม่น่าจะเป็นเช่นนั้นในคอมพิวเตอร์ทุกเครื่องที่ใช้ Python ในปัจจุบัน
math.sqrt(9)
จะกลับมา2.99999
ในระบบใดระบบหนึ่ง แต่ผลลัพธ์ที่แท้จริงขึ้นอยู่กับระบบและไม่สามารถคาดหวังได้อย่างแน่นอน
ถ้าคุณสนใจก็มีการตอบสนองบริสุทธิ์คณิตศาสตร์เพื่อคำถามที่คล้ายกันที่stackexchange คณิตศาสตร์ "การตรวจจับสี่เหลี่ยมที่สมบูรณ์แบบได้เร็วกว่าโดยแยกรากที่สอง"
การใช้ 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 <n ที่ถูกลดขนาดลงด้วยพาวเวอร์ 4 ถ้าเป็นไปได้ ซึ่งจะช่วยลดขนาดของจำนวนที่เรากำลังดำเนินการและเร่งวิธีการของบาบิโลน แต่ยังทำให้การตรวจสอบอื่น ๆ เร็วขึ้นด้วย
โค้ดบล็อกที่สามทำการทดสอบตรรกะบิตแบบบูลีนอย่างง่าย เลขสามหลักที่มีนัยสำคัญน้อยที่สุดในฐานสองของกำลังสองสมบูรณ์ใด ๆ คือ 001 เสมอ บันทึกสำหรับเลขศูนย์นำหน้าซึ่งเป็นผลมาจากอำนาจของ 4 อย่างไรก็ตามซึ่งได้รับการพิจารณาแล้ว หากไม่ผ่านการทดสอบคุณจะรู้ได้ทันทีว่าไม่ใช่สี่เหลี่ยมจัตุรัส ถ้ามันผ่านไปคุณไม่แน่ใจ
นอกจากนี้ถ้าเราลงท้ายด้วย 1 สำหรับค่าทดสอบแล้วหมายเลขทดสอบเดิมเป็นเลขยกกำลัง 4 รวมทั้งอาจเป็น 1 เองด้วย
เช่นเดียวกับบล็อกที่สามบล็อกที่สี่จะทดสอบค่าตัวที่เป็นทศนิยมโดยใช้ตัวดำเนินการโมดูลัสอย่างง่ายและมีแนวโน้มที่จะจับค่าที่ผ่านการทดสอบก่อนหน้านี้ นอกจากนี้ยังมีการทดสอบ mod 7, mod 8, mod 9 และ mod 13
โค้ดบล็อกที่ 5 จะตรวจสอบรูปแบบสี่เหลี่ยมจัตุรัสสมบูรณ์แบบที่รู้จักกันดี ตัวเลขที่ลงท้ายด้วย 1 หรือ 9 นำหน้าด้วยผลคูณของสี่ และตัวเลขที่ลงท้ายด้วย 5 ต้องลงท้ายด้วย 5625, 0625, 225 หรือ 025 ฉันรวมคนอื่นไว้ด้วย แต่รู้ว่ามันซ้ำซ้อนหรือไม่เคยใช้จริง
สุดท้ายรหัสบล็อกที่หกมีลักษณะคล้ายกับคำตอบของ Alex Martelli ซึ่งเป็นผู้ตอบสูงสุด โดยทั่วไปจะค้นหารากที่สองโดยใช้อัลกอริทึมของชาวบาบิโลนโบราณ แต่ จำกัด ไว้ที่ค่าจำนวนเต็มโดยไม่สนใจจุดลอยตัว ทำได้ทั้งเพื่อความเร็วและขยายขนาดของค่าที่ทดสอบได้ ฉันใช้ชุดแทนรายการเพราะใช้เวลาน้อยกว่ามากฉันใช้การเลื่อนบิตแทนการหารด้วยสองและฉันเลือกค่าเริ่มต้นเริ่มต้นอย่างชาญฉลาดได้อย่างมีประสิทธิภาพมากขึ้น
อย่างไรก็ตามฉันได้ทดสอบหมายเลขทดสอบที่แนะนำของ Alex Martelli รวมถึงตัวเลขสองสามคำสั่งที่มีขนาดใหญ่กว่าเช่น:
x=1000199838770766116385386300483414671297203029840113913153824086810909168246772838680374612768821282446322068401699727842499994541063844393713189701844134801239504543830737724442006577672181059194558045164589783791764790043104263404683317158624270845302200548606715007310112016456397357027095564872551184907513312382763025454118825703090010401842892088063527451562032322039937924274426211671442740679624285180817682659081248396873230975882215128049713559849427311798959652681930663843994067353808298002406164092996533923220683447265882968239141724624870704231013642255563984374257471112743917655991279898690480703935007493906644744151022265929975993911186879561257100479593516979735117799410600147341193819147290056586421994333004992422258618475766549646258761885662783430625 ** 2
for i in range(x, x+2):
print(i, isSquare(i))
พิมพ์ผลลัพธ์ต่อไปนี้:
1000399717477066534083185452789672211951514938424998708930175541558932213310056978758103599452364409903384901149641614494249195605016959576235097480592396214296565598519295693079257885246632306201885850365687426564365813280963724310434494316592041592681626416195491751015907716210235352495422858432792668507052756279908951163972960239286719854867504108121432187033786444937064356645218196398775923710931242852937602515835035177768967470757847368349565128635934683294155947532322786360581473152034468071184081729335560769488880138928479829695277968766082973795720937033019047838250608170693879209655321034310764422462828792636246742456408134706264621790736361118589122797268261542115823201538743148116654378511916000714911467547209475246784887830649309238110794938892491396597873160778553131774466638923135932135417900066903068192088883207721545109720968467560224268563643820599665232314256575428214983451466488658896488012211237139254674708538347237589290497713613898546363590044902791724541048198769085430459186735166233549186115282574626012296888817453914112423361525305960060329430234696000121420787598967383958525670258016851764034555105019265380321048686563527396844220047826436035333266263375049097675787975100014823583097518824871586828195368306649956481108708929669583308777347960115138098217676704862934389659753628861667169905594181756523762369645897154232744410732552956489694024357481100742138381514396851789639339362228442689184910464071202445106084939268067445115601375050153663645294106475257440167535462278022649865332161044187890625 True
1000399717477066534083185452789672211951514938424998708930175541558932213310056978758103599452364409903384901149641614494249195605016959576235097480592396214296565598519295693079257885246632306201885850365687426564365813280963724310434494316592041592681626416195491751015907716210235352495422858432792668507052756279908951163972960239286719854867504108121432187033786444937064356645218196398775923710931242852937602515835035177768967470757847368349565128635934683294155947532322786360581473152034468071184081729335560769488880138928479829695277968766082973795720937033019047838250608170693879209655321034310764422462828792636246742456408134706264621790736361118589122797268261542115823201538743148116654378511916000714911467547209475246784887830649309238110794938892491396597873160778553131774466638923135932135417900066903068192088883207721545109720968467560224268563643820599665232314256575428214983451466488658896488012211237139254674708538347237589290497713613898546363590044902791724541048198769085430459186735166233549186115282574626012296888817453914112423361525305960060329430234696000121420787598967383958525670258016851764034555105019265380321048686563527396844220047826436035333266263375049097675787975100014823583097518824871586828195368306649956481108708929669583308777347960115138098217676704862934389659753628861667169905594181756523762369645897154232744410732552956489694024357481100742138381514396851789639339362228442689184910464071202445106084939268067445115601375050153663645294106475257440167535462278022649865332161044187890626 False
และทำได้ภายใน 0.33 วินาที
ในความคิดของฉันอัลกอริทึมของฉันทำงานเหมือนกับของ Alex Martelli โดยมีประโยชน์ทั้งหมด แต่มีประโยชน์เพิ่มเติมในการปฏิเสธการทดสอบอย่างง่ายที่มีประสิทธิภาพสูงซึ่งช่วยประหยัดเวลาได้มากไม่ต้องพูดถึงการลดขนาดของตัวเลขทดสอบด้วยอำนาจของ 4 ซึ่งช่วยเพิ่มความเร็วประสิทธิภาพความแม่นยำและขนาดของตัวเลขที่ทดสอบได้ อาจเป็นจริงโดยเฉพาะอย่างยิ่งในการใช้งานที่ไม่ใช่ Python
ประมาณ 99% ของจำนวนเต็มทั้งหมดถูกปฏิเสธว่าไม่ใช่กำลังสองก่อนที่จะมีการใช้การแยกรูทของบาบิโลนและใน 2/3 เวลาที่ชาวบาบิโลนจะปฏิเสธจำนวนเต็ม และแม้ว่าการทดสอบเหล่านี้ไม่ได้ความเร็วในการประมวลผลที่มีนัยสำคัญลดลงในตัวเลขการทดสอบทั้งหมดจะแปลกโดยแบ่งออกอำนาจทั้งหมด 4 จริงๆเร่งการทดสอบบาบิโลน
ฉันทำการทดสอบเปรียบเทียบเวลา ฉันทดสอบจำนวนเต็มตั้งแต่ 1 ถึง 10 ล้านต่อเนื่องกัน การใช้วิธีการแบบบาบิโลนด้วยตัวเอง (ด้วยการคาดเดาเริ่มต้นที่ปรับแต่งเป็นพิเศษของฉัน) ทำให้ Surface 3 ของฉันใช้เวลาเฉลี่ย 165 วินาที (มีความแม่นยำ 100%) ด้วยการใช้การทดสอบเชิงตรรกะในอัลกอริทึมของฉัน (ไม่รวมบาบิโลน) ใช้เวลา 127 วินาทีมันปฏิเสธ 99% ของจำนวนเต็มทั้งหมดว่าไม่ใช่กำลังสองโดยไม่ปฏิเสธกำลังสองที่สมบูรณ์แบบโดยไม่ตั้งใจ จากจำนวนเต็มเหล่านั้นที่ผ่านไปมีเพียง 3% เท่านั้นที่เป็นกำลังสองสมบูรณ์ (ความหนาแน่นสูงกว่ามาก) การใช้อัลกอริทึมเต็มรูปแบบด้านบนที่ใช้ทั้งการทดสอบเชิงตรรกะและการแยกรากแบบบาบิโลนเรามีความแม่นยำ 100% และทดสอบเสร็จสิ้นในเวลาเพียง 14 วินาที จำนวนเต็ม 100 ล้านตัวแรกใช้เวลาทดสอบประมาณ 2 นาที 45 วินาที
แก้ไข: ฉันสามารถลดเวลาลงได้อีก ตอนนี้ฉันสามารถทดสอบจำนวนเต็ม 0 ถึง 100 ล้านใน 1 นาที 40 วินาที เสียเวลามากในการตรวจสอบชนิดข้อมูลและความเป็นบวก กำจัดการตรวจสอบสองครั้งแรกและฉันลดการทดสอบลงหนึ่งนาที ต้องถือว่าผู้ใช้ฉลาดพอที่จะรู้ว่าเนกาทีฟและลอยไม่ใช่กำลังสองที่สมบูรณ์แบบ
import math
def is_square(n):
sqrt = math.sqrt(n)
return (sqrt - int(sqrt)) == 0
กำลังสองสมบูรณ์คือจำนวนที่สามารถแสดงเป็นผลคูณของจำนวนเต็มสองจำนวนที่เท่ากัน math.sqrt(number)
กลับกfloat
. ปลดเปลื้องผลการint(math.sqrt(number))
int
หากรากที่เป็นจำนวนเต็มเช่น 3 เช่นนั้นmath.sqrt(number) - int(math.sqrt(number))
จะเป็น 0 และคำสั่งจะเป็นif
False
ถ้ารากที่สองเป็นจำนวนจริงเช่น 3.2 มันจะเป็นTrue
และพิมพ์ "มันไม่ใช่กำลังสองสมบูรณ์"
มันล้มเหลวสำหรับ non-square ขนาดใหญ่เช่น 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
มันเป็นพื้นไม่รากแล้ว modulo โดยที่ 1 ที่จะตัดส่วนจำนวนเต็มและหากผลที่ได้คือ 0 ผลตอบแทนอย่างอื่นกลับมาTrue
False
ในกรณีนี้ x อาจเป็นจำนวนมากก็ได้ แต่ไม่มากเท่ากับจำนวนลูกลอยสูงสุดที่ python สามารถจัดการได้: 1.7976931348623157e + 308
ไม่ถูกต้องสำหรับ non-square ขนาดใหญ่เช่น 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 ms บนเครื่องของฉัน) แต่เนื่องจากความเร็วไม่ใช่ข้อกังวลหลักของคุณนี่เป็นวิธีที่ดีในการทำกับไลบรารีมาตรฐานของ 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)
ไม่ถูกต้องสำหรับ non-square ขนาดใหญ่เช่น 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
ฉันตรวจสอบสิ่งนี้กับรายการกำลังสองสมบูรณ์ที่มีมากถึง 1,000
คำตอบนี้ไม่เกี่ยวข้องกับคำถามที่คุณระบุไว้ แต่สำหรับคำถามโดยปริยายที่ฉันเห็นในโค้ดที่คุณโพสต์กล่าวคือ "จะตรวจสอบได้อย่างไรว่าบางสิ่งเป็นจำนวนเต็ม"
คำตอบแรกที่คุณจะได้รับจากคำถามนั้นคือ "อย่า!" และเป็นความจริงที่ว่าใน 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)
ไม่ถูกต้องสำหรับ non-square ขนาดใหญ่เช่น 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)
มันล้มเหลวสำหรับ non-square ขนาดใหญ่เช่น 152415789666209426002111556165263283035677490