การจัดการกับจำนวนมากใน Python


143

ฉันได้พิจารณาการประเมินมือโป๊กเกอร์อย่างรวดเร็วใน Python สำหรับฉันแล้ววิธีหนึ่งที่จะทำให้กระบวนการเร็วขึ้นคือการแสดงหน้าไพ่ทั้งหมดและเหมาะสมเป็นจำนวนเฉพาะและคูณเข้าด้วยกันเพื่อแสดงถึงมือ เพื่อเล็กน้อย:

class PokerCard:
    faces = '23456789TJQKA'
    suits = 'cdhs'
    facePrimes = [11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 53, 59, 61]
    suitPrimes = [2, 3, 5, 7]

และ

    def HashVal(self):
      return PokerCard.facePrimes[self.cardFace] * PokerCard.suitPrimes[self.cardSuit]

สิ่งนี้จะให้ค่าตัวเลขแต่ละมือซึ่งโมดูโลสามารถบอกได้ว่ามีกษัตริย์ในมือกี่องค์หรือกี่หัวใจ ตัวอย่างเช่นมือใด ๆ ที่มีห้าไม้ขึ้นไปในนั้นจะหารเท่า ๆ กันด้วย 2 ^ 5; มือใด ๆ ที่มีสี่กษัตริย์จะหารเท่า ๆ กันด้วย 59 ^ 4 เป็นต้น

ปัญหาคือไพ่เจ็ดใบเช่น AcAdAhAsKdKhKs มีค่าแฮชประมาณ 62.7 สี่ล้านล้านซึ่งจะใช้เวลามากกว่า 32 บิตในการแสดงภายใน มีวิธีการจัดเก็บตัวเลขจำนวนมากใน Python ที่จะช่วยให้ฉันทำการคำนวณทางคณิตศาสตร์ได้หรือไม่


14
คุณแน่ใจหรือไม่ว่าเมื่อคุณเริ่มแสดงข้อมูลด้วยวิธีนี้คุณจะยังคงเห็นการปรับปรุงความเร็วอย่างมีนัยสำคัญ ฉันรู้ว่านี่ไม่ได้ตอบคำถามของคุณ แต่ก็ยัง ..
Thomi

3
ฉันมีข้อเสนอแนะ: แทนที่จะใช้ตัวแปรแยกกันสำหรับค่าการ์ดและค่าแทนฉันขอแนะนำให้ใช้พจนานุกรม (ดังนั้นใบหน้า = {'2': 11, '3': 13, '4': 17, '5': 19, '6': 23, '7': 29, '8': 31, '9' : 37, 'T': 41, 'J': 43, 'Q': 53, 'K': 59, 'A': 61} และชุด = {'c': 2, 'd': 3, ' h ': 5,' s ': 7})
JAB

คำตอบ:


183

Python รองรับประเภทจำนวนเต็ม "bignum" ซึ่งสามารถทำงานกับตัวเลขขนาดใหญ่ได้ตามอำเภอใจ ใน Python 2.5+ ประเภทนี้ถูกเรียกlongและแยกออกจากintประเภท แต่ล่ามจะใช้โดยอัตโนมัติแล้วแต่ว่าแบบใดจะเหมาะสมกว่า ใน Python 3.0+ intประเภทถูกทิ้งทั้งหมด

นั่นเป็นเพียงรายละเอียดการใช้งาน - ตราบใดที่คุณมีเวอร์ชัน 2.5 ขึ้นไปเพียงแค่ดำเนินการคำนวณทางคณิตศาสตร์มาตรฐานและตัวเลขใด ๆ ที่เกินขอบเขตของคณิตศาสตร์ 32 บิตจะถูกแปลงเป็น bignum โดยอัตโนมัติ (และโปร่งใส)

คุณสามารถค้นหารายละเอียดทั้งหมดที่เต็มไปด้วยเลือดในPEP 0237


2
คำถามคือประสิทธิภาพที่ได้รับจากการใช้ bignum แทนที่จะเป็นจำนวนเต็ม 32 บิตนั้นเกินกว่าประสิทธิภาพที่ได้รับจากวิธีการประเมินมือที่ชาญฉลาดที่เขาใช้อยู่
Chris Upchurch

3
อันที่จริงกำแพงกั้นระหว่าง int และ long ถูกหักใน 2.5 3.0 ลบ int ออกทั้งหมดทำให้เป็นประเภทจำนวนเต็มแบบยาวเท่านั้น
Ignacio Vazquez-Abrams

1
ตัวเลขขนาดใหญ่คืออะไร? เป็น PHI ^ 4000000 ได้ไหม
Mike Caron

9
@ Mike Caron - หากโครงสร้างที่ระบุใน PEP 0237 ถูกต้องlongความยาวของ s (เป็นตัวเลข) จะถูกจัดเก็บเป็นจำนวนเต็ม 32 บิตที่ไม่ได้ลงนามซึ่งมีจำนวนสูงสุด 4,294,967,295 หลักซึ่งหมายความว่าสามารถถือφ ** (4 * 10 ** 6 ได้อย่างง่ายดาย ) ซึ่งมีค่า "เพียง" 832,951 หลัก อย่างไรก็ตามφไม่ใช่จำนวนเต็มดังนั้นคุณจะต้องใช้ทศนิยม ( เครื่องหมายทศนิยมของ Python) ในการคำนวณจำนวน อย่างไรก็ตามคุณสามารถจัดเก็บผลลัพธ์ในlongภายหลังได้
Ben Blank

17
@ IgnacioVazquez อับราฮัมเพียงแค่จุดของการชี้แจงที่longเป็นชนิดเดียวในจำนวนเต็ม 3.0 intแต่มันชื่อ (และเก่าintก็หายไป)
Michael Mior

77

หลามรองรับจำนวนเต็มขนาดใหญ่โดยพลการตามธรรมชาติ:

ตัวอย่าง:

>>> 10**1000
10000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000

คุณอาจได้รับตัวอย่างเช่นค่าจำนวนเต็มขนาดใหญ่ fib (4000000)

แต่ก็ยังไม่ (สำหรับตอนนี้) รองรับการลอยตัวขนาดใหญ่โดยพลการ!!

หากคุณต้องการขนาดใหญ่ขนาดใหญ่ลอยจากนั้นตรวจสอบโมดูลทศนิยม มีตัวอย่างการใช้งานใน foruns เหล่านี้: OverflowError: (34, 'Result too large')

ข้อมูลอ้างอิงอื่น: http://docs.python.org/2/library/decimal.html

คุณสามารถใช้โมดูล gmpy ได้หากต้องการเร่งความเร็ว (ซึ่งน่าจะเป็นที่สนใจของคุณ): การจัดการตัวเลขจำนวนมากในรหัส

ข้อมูลอ้างอิงอื่น: https://code.google.com/p/gmpy/


35

คุณสามารถทำสิ่งนี้เพื่อความสนุกสนาน แต่นอกเหนือจากนั้นก็ไม่ใช่ความคิดที่ดี มันจะไม่เร่งความเร็วอะไรที่ฉันคิดได้

  • การนำไพ่มาไว้ในมือจะเป็นการดำเนินการแยกตัวประกอบจำนวนเต็มซึ่งมีราคาแพงกว่าการเข้าถึงอาร์เรย์มาก

  • การเพิ่มการ์ดจะเป็นการคูณและการลบการแบ่งการ์ดซึ่งเป็นตัวเลขหลายคำขนาดใหญ่ซึ่งเป็นการดำเนินการที่มีราคาแพงกว่าการเพิ่มหรือลบองค์ประกอบออกจากรายการ

  • ค่าตัวเลขที่แท้จริงของมือจะไม่บอกอะไรคุณ คุณจะต้องแยกตัวประกอบของช่วงเวลาและปฏิบัติตามกฎโป๊กเกอร์เพื่อเปรียบเทียบสองมือ h1 <h2 สำหรับมือดังกล่าวไม่มีความหมาย


27

หลามรองรับจำนวนเต็มขนาดใหญ่โดยพลการตามธรรมชาติ:

In [1]: 59**3*61**4*2*3*5*7*3*5*7
Out[1]: 62702371781194950
In [2]: _ % 61**4
Out[2]: 0

4

ล่ามหลามจะจัดการให้คุณเพียงแค่ดำเนินการ (+, -, *, /) ก็จะทำงานได้ตามปกติ

intค่าไม่ จำกัด

ระมัดระวังเมื่อทำการหารโดยค่าเริ่มต้นผลหารจะเปลี่ยนเป็นfloatแต่floatไม่รองรับตัวเลขจำนวนมากเช่นนี้ หากคุณได้รับข้อความแสดงข้อผิดพลาดว่าfloatไม่รองรับตัวเลขจำนวนมากนั่นหมายความว่าผลหารมีขนาดใหญ่เกินไปที่จะจัดเก็บไว้floatคุณจะต้องใช้การแบ่งชั้น ( //)

จะละเว้นทศนิยมใด ๆ ที่มาหลังจุดทศนิยมด้วยวิธีนี้ผลลัพธ์จะเป็นintดังนั้นคุณสามารถมีผลลัพธ์จำนวนมากได้

>>>10//3
3

>>>10//4
2

1
คำตอบของคุณตอบปัญหาจำนวนมากในคำถามอย่างไร
StupidWolf

หมายความว่าคุณสามารถดำเนินการตามปกติด้วยตัวเลขจำนวนมาก แต่ระวังการแบ่ง
Hedy
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.