คำอธิบายทางคณิตศาสตร์ที่แม่นยำโดยพลการ


92

ฉันกำลังพยายามเรียนรู้ภาษา C และพบว่าไม่สามารถทำงานกับตัวเลขขนาดใหญ่ได้จริงๆ (เช่น 100 หลัก 1,000 หลักเป็นต้น) ฉันทราบว่ามีไลบรารีให้ทำสิ่งนี้ได้ แต่ฉันต้องการลองใช้งานด้วยตัวเอง

ฉันแค่อยากรู้ว่าใครมีหรือสามารถให้คำอธิบายที่ละเอียดมากเกี่ยวกับเลขคณิตที่มีความแม่นยำตามอำเภอใจได้บ้าง

คำตอบ:


163

ทุกอย่างเป็นเรื่องของการจัดเก็บและอัลกอริทึมที่เพียงพอในการถือว่าตัวเลขเป็นส่วนเล็ก ๆ สมมติว่าคุณมีคอมไพเลอร์ที่intสามารถเป็น 0 ถึง 99 เท่านั้นและคุณต้องการจัดการตัวเลขได้ถึง 999999 (เราจะกังวลเฉพาะตัวเลขบวกที่นี่เพื่อให้มันง่าย)

คุณทำได้โดยให้เลขสามตัวแต่ละตัวintและใช้กฎเดียวกันกับที่คุณ (ควรจะได้) เรียนกลับมาในโรงเรียนประถมเพื่อการบวกการลบและการดำเนินการพื้นฐานอื่น ๆ

ในไลบรารีความแม่นยำตามอำเภอใจไม่มีการ จำกัด จำนวนประเภทฐานที่แน่นอนที่ใช้แทนตัวเลขของเราหน่วยความจำใดก็ได้

นอกจากนี้ตัวอย่างเช่น123456 + 78:

12 34 56
      78
-- -- --
12 35 34

การทำงานจากจุดสิ้นสุดที่สำคัญน้อยที่สุด:

  • เริ่มต้นดำเนินการ = 0
  • 56 + 78 + 0 พกพา = 134 = 34 พร้อม 1 พก
  • 34 + 00 + 1 พก = 35 = 35 กับ 0 พก
  • 12 + 00 + 0 พกพา = 12 = 12 กับ 0 พก

นี่คือความจริงแล้วการเพิ่มโดยทั่วไปทำงานอย่างไรในระดับบิตภายใน CPU ของคุณ

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

ฉันได้เขียนไลบรารีเพื่อทำสิ่งเหล่านี้โดยใช้กำลังสูงสุดสิบที่สามารถใส่เป็นจำนวนเต็มเมื่อยกกำลังสองได้ (เพื่อป้องกันการล้นเมื่อคูณสองints เข้าด้วยกันเช่น 16 บิตintถูก จำกัด ไว้ที่ 0 ถึง 99 ถึง สร้าง 9,801 (<32,768) เมื่อกำลังสองหรือ 32 บิตintโดยใช้ 0 ถึง 9,999 เพื่อสร้าง 99,980,001 (<2,147,483,648)) ซึ่งทำให้อัลกอริทึมง่ายขึ้นมาก

เทคนิคบางอย่างที่ต้องระวัง

1 / เมื่อเพิ่มหรือคูณตัวเลขให้จัดสรรพื้นที่สูงสุดที่จำเป็นไว้ล่วงหน้าแล้วลดในภายหลังหากคุณพบว่ามันมากเกินไป ตัวอย่างเช่นการเพิ่มตัวเลข 100- "หลัก" สองตัว (โดยที่หลักคือ an int) จะไม่ทำให้คุณเกิน 101 หลัก การคูณตัวเลข 12 หลักด้วยตัวเลข 3 หลักจะไม่ทำให้เกิดตัวเลขเกิน 15 หลัก (บวกจำนวนหลัก)

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

3 / การบวกจำนวนบวกและลบคือการลบและการลบจำนวนลบจะเหมือนกับการบวกบวกที่เท่ากัน คุณสามารถบันทึกโค้ดได้เล็กน้อยโดยให้วิธีการบวกและลบเรียกหากันหลังจากปรับสัญญาณ

4 / หลีกเลี่ยงการลบตัวเลขจำนวนมากออกจากตัวเลขขนาดเล็กเนื่องจากคุณมักจะลงท้ายด้วยตัวเลขเช่น:

         10
         11-
-- -- -- --
99 99 99 99 (and you still have a borrow).

ให้ลบ 10 จาก 11 แทนแล้วลบมัน:

11
10-
--
 1 (then negate to get -1).

นี่คือความคิดเห็น (กลายเป็นข้อความ) จากหนึ่งในห้องสมุดที่ฉันต้องทำเพื่อ น่าเสียดายที่รหัสนั้นมีลิขสิทธิ์ แต่คุณอาจสามารถเลือกข้อมูลที่เพียงพอเพื่อจัดการกับการทำงานพื้นฐานทั้งสี่อย่างได้ สมมติในสิ่งต่อไปนี้-aและ-bแทนจำนวนลบและaและbเป็นศูนย์หรือจำนวนบวก

สำหรับนอกจากนี้ถ้าสัญญาณที่แตกต่างกันใช้ลบของการปฏิเสธ:

-a +  b becomes b - a
 a + -b becomes a - b

สำหรับการลบหากสัญญาณแตกต่างกันให้ใช้การเพิ่มการปฏิเสธ:

 a - -b becomes   a + b
-a -  b becomes -(a + b)

นอกจากนี้การจัดการพิเศษเพื่อให้แน่ใจว่าเรากำลังลบจำนวนน้อยออกจากจำนวนมาก:

small - big becomes -(big - small)

การคูณใช้คณิตศาสตร์ระดับเริ่มต้นดังนี้:

475(a) x 32(b) = 475 x (30 + 2)
               = 475 x 30 + 475 x 2
               = 4750 x 3 + 475 x 2
               = 4750 + 4750 + 4750 + 475 + 475

วิธีที่บรรลุเป้าหมายนี้เกี่ยวข้องกับการแยกแต่ละหลัก 32 ทีละครั้ง (ถอยหลัง) จากนั้นใช้การเพิ่มเพื่อคำนวณค่าที่จะเพิ่มให้กับผลลัพธ์ (เริ่มต้นเป็นศูนย์)

ShiftLeftและShiftRightการดำเนินการใช้เพื่อคูณหรือหาร a อย่างรวดเร็วLongIntด้วยค่าการห่อ (10 สำหรับคณิตศาสตร์ "จริง") ในตัวอย่างด้านบนเราบวก 475 เป็นศูนย์ 2 ครั้ง (ตัวเลขสุดท้ายของ 32) เพื่อให้ได้ 950 (ผลลัพธ์ = 0 + 950 = 950)

จากนั้นเราเลื่อนซ้าย 475 เพื่อรับ 4750 และเลื่อนขวา 32 เพื่อรับ 3 เพิ่ม 4750 เป็นศูนย์ 3 ครั้งเพื่อรับ 14250 จากนั้นเพิ่มผลของ 950 เพื่อรับ 15200

เลื่อนไปทางซ้าย 4750 เพื่อรับ 47500 กะขวา 3 เพื่อรับ 0 เนื่องจากตอนนี้เลื่อนขวา 32 เป็นศูนย์เราจึงเสร็จสิ้นและในความเป็นจริง 475 x 32 เท่ากับ 15200

การหารก็ยุ่งยากเช่นกัน แต่ขึ้นอยู่กับเลขคณิตในช่วงต้น (วิธี "gazinta" สำหรับ "ไปสู่") พิจารณาการหารยาวต่อไปนี้สำหรับ12345 / 27:

       457
   +-------
27 | 12345    27 is larger than 1 or 12 so we first use 123.
     108      27 goes into 123 4 times, 4 x 27 = 108, 123 - 108 = 15.
     ---
      154     Bring down 4.
      135     27 goes into 154 5 times, 5 x 27 = 135, 154 - 135 = 19.
      ---
       195    Bring down 5.
       189    27 goes into 195 7 times, 7 x 27 = 189, 195 - 189 = 6.
       ---
         6    Nothing more to bring down, so stop.

ดังนั้นจึง12345 / 27เป็นส่วนที่เหลือ457 6ตรวจสอบ:

  457 x 27 + 6
= 12339    + 6
= 12345

สิ่งนี้ถูกนำไปใช้โดยใช้ตัวแปร draw-down (เริ่มต้นเป็นศูนย์) เพื่อลดส่วนของ 12345 ทีละส่วนจนกว่าจะมากกว่าหรือเท่ากับ 27

จากนั้นเราก็ลบ 27 จากนั้นจนกว่าเราจะได้ต่ำกว่า 27 - จำนวนการลบคือส่วนที่เพิ่มในบรรทัดบนสุด

เมื่อไม่มีกลุ่มที่จะนำมาลงอีกเราก็ได้ผลลัพธ์ของเรา


โปรดทราบว่านี่เป็นอัลกอริทึมพื้นฐานที่ค่อนข้างดี มีวิธีที่ดีกว่ามากในการคำนวณเลขคณิตเชิงซ้อนหากตัวเลขของคุณมีขนาดใหญ่เป็นพิเศษ คุณสามารถดูบางอย่างเช่นGNU Multiple Precision Arithmetic Library - มันดีกว่าและเร็วกว่าไลบรารีของฉันเอง

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

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

ฉันยังพบว่า bods ที่MPIR (ส่วนแยกของ GMP) นั้นเอื้อต่อการพูดคุยเกี่ยวกับการเปลี่ยนแปลงที่อาจเกิดขึ้นได้มากขึ้นซึ่งดูเหมือนจะเป็นกลุ่มที่เป็นมิตรกับนักพัฒนามากกว่า


14
ฉันคิดว่าคุณพูดถึง "ฉันแค่อยากรู้ว่าใครมีหรือสามารถให้คำอธิบายเกี่ยวกับเลขคณิตที่มีความแม่นยำตามอำเภอใจโดยละเอียด" ได้ดีมาก
Grant Peters

คำถามติดตามผลหนึ่งคำถาม: เป็นไปได้หรือไม่ที่จะตั้งค่า / ตรวจจับการบรรทุกและล้นโดยไม่ต้องเข้าถึงรหัสเครื่อง?
SasQ

8

ในขณะที่การประดิษฐ์วงล้อขึ้นมาใหม่นั้นเป็นสิ่งที่ดีอย่างยิ่งสำหรับการจรรโลงใจและการเรียนรู้ส่วนบุคคลของคุณ แต่ก็เป็นงานที่ใหญ่มาก ฉันไม่ต้องการห้ามปรามคุณว่าเป็นการออกกำลังกายที่สำคัญและเป็นสิ่งที่ฉันได้ทำด้วยตัวเอง แต่คุณควรทราบว่ามีปัญหาที่ละเอียดอ่อนและซับซ้อนในที่ทำงานซึ่งบรรจุภัณฑ์ขนาดใหญ่ขึ้น

ตัวอย่างเช่นการคูณ คุณอาจนึกถึงวิธีการ 'เด็กนักเรียน' คือเขียนเลขหนึ่งไว้เหนืออีกตัวจากนั้นคูณยาว ๆ ตามที่เรียนในโรงเรียน ตัวอย่าง:

      123
    x  34
    -----
      492
+    3690
---------
     4182

แต่วิธีนี้ช้ามาก (O (n ^ 2), n เป็นจำนวนหลัก) แต่แพ็คเกจ bignum สมัยใหม่จะใช้การแปลงฟูเรียร์แบบไม่ต่อเนื่องหรือการแปลงตัวเลขเพื่อเปลี่ยนเป็นการดำเนินการ O (n ln (n)) เป็นหลัก

และนี่เป็นเพียงจำนวนเต็ม เมื่อคุณเข้าสู่ฟังก์ชันที่ซับซ้อนมากขึ้นในการแสดงจำนวนจริงบางประเภท (log, sqrt, exp ฯลฯ ) สิ่งต่างๆจะซับซ้อนยิ่งขึ้น

หากคุณต้องการพื้นหลังทฤษฎีบางอย่างผมขอแนะนำให้อ่านบทแรกของหนังสือเล่มเห่าของ"ปัญหาพื้นฐานของขั้นตอนพีชคณิต" ดังที่ได้กล่าวไปแล้วว่าห้องสมุด gmp bignum เป็นห้องสมุดที่ยอดเยี่ยม สำหรับตัวเลขจริงฉันเคยใช้ mpfr และชอบมัน


1
ฉันสนใจในส่วนที่เกี่ยวกับ "ใช้การแปลงฟูเรียร์แบบไม่ต่อเนื่องหรือการแปลงตัวเลขเพื่อเปลี่ยนให้เป็นการดำเนินการ O (n ln (n)) เป็นหลัก" - มันทำงานอย่างไร เพียงแค่การอ้างอิงจะปรับ :)
detly

1
@detly: การคูณพหุนามเหมือนกับการแปลงควรจะง่ายต่อการค้นหาข้อมูลเกี่ยวกับการใช้ FFT เพื่อดำเนินการแปลงอย่างรวดเร็ว ระบบตัวเลขใด ๆ เป็นพหุนามโดยที่ตัวเลขเป็นสัมประสิทธิ์และฐานเป็นฐาน แน่นอนว่าคุณจะต้องดูแลการพกพาเพื่อไม่ให้เกินช่วงของตัวเลข
Ben Voigt

6

อย่าสร้างล้อใหม่: มันอาจกลายเป็นสี่เหลี่ยม!

ใช้ไลบรารีของบุคคลที่สามเช่นGNU MPที่ทดลองและทดสอบ


4
ฉันหากคุณต้องการเรียนรู้ C ฉันจะกำหนดสถานที่ท่องเที่ยวของคุณให้ต่ำลงเล็กน้อย การใช้ห้องสมุด bignum ไม่ใช่เรื่องสำคัญสำหรับเหตุผลที่ละเอียดอ่อนทุกประเภทที่จะทำให้ผู้เรียนรู้
Mitch Wheat

3
ไลบรารีของบุคคลที่สาม: เห็นด้วย แต่ GMP มีปัญหาการออกใบอนุญาต (LGPL แม้ว่าจะทำหน้าที่เป็น GPL ได้อย่างมีประสิทธิภาพเนื่องจากเป็นเรื่องยากที่จะคำนวณทางคณิตศาสตร์ที่มีประสิทธิภาพสูงผ่านอินเทอร์เฟซที่เข้ากันได้กับ LGPL)
Jason S

การอ้างอิง Futurama ที่ดี (โดยเจตนา?)
Grant Peters

7
GNU MP เรียกร้องabort()ความล้มเหลวในการจัดสรรโดยไม่มีเงื่อนไขซึ่งจะเกิดขึ้นกับการคำนวณขนาดใหญ่อย่างไม่น่าเชื่อ นี่เป็นพฤติกรรมที่ไม่สามารถยอมรับได้สำหรับไลบรารีและมีเหตุผลเพียงพอที่จะเขียนโค้ดของคุณเองโดยพลการ
R .. GitHub STOP HELPING ICE

ฉันต้องเห็นด้วยกับ R ที่นั่น ไลบรารีสำหรับใช้งานทั่วไปที่ดึงพรมออกจากด้านล่างโปรแกรมของคุณเมื่อหน่วยความจำเหลือน้อยไม่สามารถให้อภัยได้ ฉันค่อนข้างจะยอมเสียสละความเร็วเพื่อความปลอดภัย / การกู้คืน
paxdiablo

4

โดยพื้นฐานแล้วคุณทำแบบเดียวกับดินสอและกระดาษ ...

  • จำนวนจะถูกแสดงในบัฟเฟอร์ (อาร์เรย์) ที่สามารถรับขนาดโดยพลการ (ซึ่งหมายถึงการใช้mallocและrealloc) ตามต้องการ
  • คุณใช้เลขคณิตพื้นฐานให้มากที่สุดเท่าที่จะเป็นไปได้โดยใช้โครงสร้างที่รองรับภาษาและจัดการกับการดำเนินการและย้ายจุดรัศมีด้วยตนเอง
  • คุณค้นหาข้อความการวิเคราะห์ตัวเลขเพื่อค้นหาข้อโต้แย้งที่มีประสิทธิภาพสำหรับการจัดการโดยฟังก์ชันที่ซับซ้อนมากขึ้น
  • คุณใช้เท่าที่คุณต้องการเท่านั้น

โดยปกติคุณจะใช้เป็นหน่วยพื้นฐานของการคำนวณ

  • ไบต์ที่ประกอบด้วย 0-99 หรือ 0-255
  • คำ 16 บิตที่เหี่ยวเฉา 0-9999 หรือ 0--65536
  • คำ 32 บิตที่ประกอบด้วย ...
  • ...

ตามที่กำหนดโดยสถาปัตยกรรมของคุณ

การเลือกฐานเลขฐานสองหรือฐานสิบขึ้นอยู่กับความต้องการของคุณสำหรับประสิทธิภาพของพื้นที่สูงสุดความสามารถในการอ่านของมนุษย์และการไม่มีการสนับสนุนทางคณิตศาสตร์ฐานสองรหัสฐานสอง (BCD) บนชิปของคุณ


3

คุณสามารถทำได้กับคณิตศาสตร์ระดับมัธยมศึกษาตอนปลาย แม้ว่าจะมีการใช้อัลกอริทึมขั้นสูงมากกว่าในความเป็นจริง ตัวอย่างเช่นการเพิ่มตัวเลข 1024 ไบต์สองตัว:

unsigned char first[1024], second[1024], result[1025];
unsigned char carry = 0;
unsigned int  sum   = 0;

for(size_t i = 0; i < 1024; i++)
{
    sum = first[i] + second[i] + carry;
    carry = sum - 255;
}

ผลลัพธ์จะต้องใหญ่ขึ้นโดยone placeในกรณีที่ต้องดูแลค่าสูงสุด ดูนี่สิ :

9
   +
9
----
18

TTMathเป็นห้องสมุดที่ยอดเยี่ยมหากคุณต้องการเรียนรู้ สร้างขึ้นโดยใช้ C ++ ตัวอย่างข้างต้นเป็นเรื่องโง่ แต่นี่คือวิธีการบวกและการลบโดยทั่วไป!

การอ้างอิงที่ดีเกี่ยวกับเรื่องที่มีความซับซ้อนการคำนวณทางคณิตศาสตร์ของการดำเนินงาน จะบอกคุณว่าต้องใช้พื้นที่เท่าใดสำหรับแต่ละการดำเนินการที่คุณต้องการใช้ ตัวอย่างเช่นหากคุณมีN-digitตัวเลขสองตัวคุณจะต้อง2N digitsเก็บผลลัพธ์ของการคูณ

ดังที่มิทช์กล่าวไว้มันไม่ใช่เรื่องง่ายเลยที่จะนำไปใช้! ฉันแนะนำให้คุณดู TTMath ถ้าคุณรู้จัก C ++


การใช้อาร์เรย์เกิดขึ้นกับฉัน แต่ฉันกำลังมองหาบางสิ่งที่กว้างกว่านั้น ขอบคุณสำหรับการตอบกลับ!
TT.

2
อืม ... ชื่อผู้ถามกับชื่อห้องสมุดไม่ใช่เรื่องบังเอิญได้มั้ย? ;)
John Y

ฮ่า ๆ ฉันไม่ได้สังเกตว่า! ฉันหวังว่า TTMath จะเป็นของฉันจริงๆ :) Btw นี่คือหนึ่งในคำถามของฉันเกี่ยวกับเรื่องนี้:
AraK


3

หนึ่งในข้อมูลอ้างอิงขั้นสูงสุด (IMHO) คือ TAOCP Volume II ของ Knuth มันอธิบายอัลกอริทึมมากมายสำหรับการแสดงตัวเลขและการคำนวณทางคณิตศาสตร์ในการแทนค่าเหล่านี้

@Book{Knuth:taocp:2,
   author    = {Knuth, Donald E.},
   title     = {The Art of Computer Programming},
   volume    = {2: Seminumerical Algorithms, second edition},
   year      = {1981},
   publisher = {\Range{Addison}{Wesley}},
   isbn      = {0-201-03822-6},
}

1

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

  • ฉันเก็บทศนิยมแต่ละหลักไว้เป็นเลขคู่ ทำให้การดำเนินการหลายอย่างเป็นเรื่องง่ายโดยเฉพาะเอาต์พุต แม้ว่าจะใช้พื้นที่เก็บข้อมูลมากกว่าที่คุณต้องการ แต่หน่วยความจำก็มีราคาถูกที่นี่และทำให้การคูณมีประสิทธิภาพมากหากคุณสามารถแปลงเวกเตอร์คู่ได้อย่างมีประสิทธิภาพ อีกวิธีหนึ่งคือคุณสามารถจัดเก็บเลขฐานสิบได้หลายหลักในการคูณ แต่โปรดระวังว่าการคิดเลขในการคูณอาจทำให้เกิดปัญหาเกี่ยวกับตัวเลขกับตัวเลขจำนวนมากได้

  • จัดเก็บบิตป้ายแยกต่างหาก

  • การบวกเลขสองตัวส่วนใหญ่เป็นเรื่องของการเพิ่มตัวเลขจากนั้นตรวจสอบการพกพาในแต่ละขั้นตอน

  • การคูณตัวเลขคู่หนึ่งทำได้ดีที่สุดในรูปแบบ Convolution ตามด้วยขั้นตอนพกพาอย่างน้อยถ้าคุณมีรหัส Convolution ที่รวดเร็วเมื่อแตะ

  • แม้ว่าคุณจะจัดเก็บตัวเลขเป็นสตริงของตัวเลขทศนิยมแต่ละตัวการหาร (เช่น mod / rem ops) สามารถทำได้เพื่อให้ได้ทศนิยมประมาณ 13 หลักต่อครั้งในผลลัพธ์ สิ่งนี้มีประสิทธิภาพมากกว่าการหารที่ทำงานบนทศนิยมเพียง 1 หลักในแต่ละครั้ง

  • ในการคำนวณกำลังจำนวนเต็มของจำนวนเต็มให้คำนวณการแทนค่าฐานสองของเลขชี้กำลัง จากนั้นใช้การดำเนินการกำลังสองซ้ำ ๆ เพื่อคำนวณพาวเวอร์ตามต้องการ

  • การดำเนินการหลายอย่าง (การแยกตัวประกอบการทดสอบความเป็นจริง ฯลฯ ) จะได้รับประโยชน์จากการดำเนินการของ powermod นั่นคือเมื่อคุณคำนวณ mod (a ^ p, N) ให้ลดผลลัพธ์ mod N ในแต่ละขั้นตอนของการยกกำลังโดยที่ p แสดงในรูปแบบไบนารี อย่าคำนวณ a ^ p ก่อนจากนั้นพยายามลดค่า mod N


1
หากคุณจัดเก็บตัวเลขแต่ละตัวแทนที่จะเป็นฐาน -10 ^ 9 หรือฐาน -2 ^ 32 หรือสิ่งที่คล้ายกันสิ่งที่น่าสนใจสำหรับการคูณทั้งหมดของคุณเป็นเพียงการสูญเปล่า Big-O ไม่มีความหมายเลยเมื่อค่าคงที่ของคุณแย่ขนาดนั้น ...
R .. GitHub STOP HELPING ICE

0

นี่เป็นตัวอย่างง่ายๆ (ไร้เดียงสา) ที่ฉันทำใน PHP

ฉันใช้ "เพิ่ม" และ "คูณ" และใช้เป็นตัวอย่างเลขชี้กำลัง

http://adevsoft.com/simple-php-arbitrary-precision-integer-big-num-example/

การตัดโค้ด

// Add two big integers
function ba($a, $b)
{
    if( $a === "0" ) return $b;
    else if( $b === "0") return $a;

    $aa = str_split(strrev(strlen($a)>1?ltrim($a,"0"):$a), 9);
    $bb = str_split(strrev(strlen($b)>1?ltrim($b,"0"):$b), 9);
    $rr = Array();

    $maxC = max(Array(count($aa), count($bb)));
    $aa = array_pad(array_map("strrev", $aa),$maxC+1,"0");
    $bb = array_pad(array_map("strrev", $bb),$maxC+1,"0");

    for( $i=0; $i<=$maxC; $i++ )
    {
        $t = str_pad((string) ($aa[$i] + $bb[$i]), 9, "0", STR_PAD_LEFT);

        if( strlen($t) > 9 )
        {
            $aa[$i+1] = ba($aa[$i+1], substr($t,0,1));
            $t = substr($t, 1);
        }

        array_unshift($rr, $t);
     }

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