จัดการกับตัวเลขจำนวนมากในภาษาที่ไม่สามารถ?


15

ฉันพยายามที่จะคิดเกี่ยวกับวิธีที่ฉันจะไปเกี่ยวกับการคำนวณในจำนวนมาก (เพื่อ infinitum - intergers ไม่ลอย) หากโครงสร้างภาษาไม่สามารถจัดการตัวเลขที่มีขนาดใหญ่กว่าค่าที่แน่นอน

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

ฉันจะร่างอัลกอริทึมแบบนี้:

  1. กำหนดความยาวสูงสุดของตัวแปรจำนวนเต็มสำหรับภาษา

  2. หากตัวเลขมีความยาวมากกว่าครึ่งของความยาวสูงสุดของตัวแปรที่แยกออกเป็นอาเรย์ (ให้ห้องเล่นเล็ก ๆ )

  3. ลำดับ Array [0] = ตัวเลขที่อยู่ทางด้านขวา [n-max] = ตัวเลขที่อยู่ทางด้านซ้ายสุด

    อดีต Num: 29392023 Array [0]: 23, Array [1]: 20, array [2]: 39, array [3]: 29

เมื่อฉันสร้างความยาวครึ่งหนึ่งของตัวแปรเป็นจุดปิดมาร์คฉันก็สามารถคำนวณหาหนึ่งในสิบส่วนหนึ่งร้อย ฯลฯ วางผ่านเครื่องหมายครึ่งทางเพื่อที่ว่าถ้าความยาวสูงสุดของตัวแปรเท่ากับ 10 หลักจาก 0 ถึง 9999999999 ฉันรู้ว่า โดยครึ่งหนึ่งนั้นถึงห้าหลักทำให้ฉันมีห้องเล่น

ดังนั้นถ้าฉันเพิ่มหรือทวีคูณฉันสามารถมีฟังก์ชั่นตรวจสอบตัวแปรที่เห็นว่าหลักที่หก (จากด้านขวา) ของอาร์เรย์ [0] เป็นตำแหน่งเดียวกับหลักแรก (จากด้านขวา) ของอาร์เรย์ [1]

การหารและการลบมีปัญหาของตัวเองซึ่งฉันยังไม่ได้คิด

ฉันต้องการทราบเกี่ยวกับการใช้งานที่ดีที่สุดในการรองรับจำนวนที่มากขึ้นกว่าที่โปรแกรมสามารถทำได้


1
สิ่งแรกที่ควรคำนึงถึงคือ BigInteger ของ Java: docs.oracle.com/javase/6/docs/api/java/math/BigInteger.html
Ivan

นี่เป็นภาษาที่ทุกคนที่นี่อาจรู้จักและสามารถให้คำแนะนำเฉพาะเจาะจงหรือเป็นสิ่งที่คลุมเครือและเป็นกรรมสิทธิ์หรือไม่?
FrustratedWithFormsDesigner

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

คำตอบ:


25

คุณกำลังมองหาห้องสมุดคณิตศาสตร์ที่มีความแม่นยำตามอำเภอใจ (เรียกอีกอย่างว่า "ความแม่นยำหลายอย่าง" หรือ "บิ๊กนัม") สำหรับภาษาที่คุณใช้งาน ตัวอย่างเช่นหากคุณทำงานกับ C คุณสามารถใช้ GNU Bignum Library -> http://gmplib.org/

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


5
แน่นอน "หลัก" เป็นญาติห้องสมุด bignum จำนวนมากใช้ตัวเลขในฐาน 256 (ไบต์ไม่ได้ลงนาม []) ถึง 2 ^ 64 (ยาวไม่ลงนาม [])
วงล้อประหลาด

1
เพียงทำให้แน่ใจว่าฉันเข้าใจ 'หลัก' อาจเป็นอาร์เรย์ฐาน 256 หลักได้หรือไม่ ฉันคิดว่าฉันอาจจะเข้าใจผิดการทำคณิตศาสตร์บนฐาน 256 นั้นง่ายกว่าฐาน 88 แต่ก็ค่อนข้างเป็นงาน ... (อย่างน้อยตอนที่ฉันทำมันเมื่อคืนนี้ในแผ่นกระดาษฮ่าฮ่า)
Mallow

1
"การคำนวณทางคณิตศาสตร์บนฐาน 256 ง่ายกว่าฐาน 88" เท็จ มันง่ายพอ ๆ กัน
S.Lott

2
@ S.Lott: อืม ... เมื่อคุณมีการดำเนินงานระดับบิตที่มีอยู่การทำคณิตศาสตร์บนฐาน 256 นั้นง่ายกว่าฐาน 88 อย่างแน่นอน
Jason S

1
การสร้างเพิ่ม / ลบ / คูณของคุณเองนั้นค่อนข้างตรงไปตรงมา การแบ่งเป็นเรื่องยากเว้นแต่ว่าคุณกำลังนำไปใช้ในระบบเลขฐานสองซึ่งมันจะกลายเป็นการออกกำลังกายในการลบแบบมีเงื่อนไขและการเลื่อนบิต
Jason S

13

มันเป็นปัญหาที่รู้จักกันดี: ความแม่นยำทางคณิตศาสตร์โดยพลการ

เมื่อภาษาที่คุณใช้ไม่สามารถแก้ไขปัญหานี้ได้อันดับแรกให้ลองหาห้องสมุดบุคคลที่สาม หากคุณไม่พบมันหรืออยากรู้อยากเห็นลองนำไปใช้ บทความวิกิพีเดียมีการอ้างอิงที่ดีเกี่ยวกับการใช้งานแบบดั้งเดิม


6

เมื่อต้องรับมือกับจำนวนมากอาจเป็นหนึ่งในการตัดสินใจออกแบบขั้นพื้นฐานที่สุดคือฉันจะเป็นตัวแทนของจำนวนมากได้อย่างไร

มันจะเป็นสตริงอาร์เรย์รายการหรือคลาสหน่วยเก็บข้อมูลแบบกำหนดเอง (homegrown)

หลังจากทำการตัดสินใจแล้วการดำเนินการทางคณิตศาสตร์ที่เกิดขึ้นจริงสามารถแบ่งออกเป็นส่วนย่อย ๆ แล้วดำเนินการกับชนิดภาษาท้องถิ่นเช่น int หรือจำนวนเต็ม

ฉันได้รวมตัวอย่างเพิ่มเติมพื้นฐานใน C # .Net ที่เก็บผลจำนวนมากเป็นสตริง "ตัวเลข" ที่เข้ามายังเป็นสตริงดังนั้นจึงควรส่งหมายเลข "ใหญ่" มาก โปรดจำไว้ว่าตัวอย่างเป็นเพียงตัวเลขทั้งหมดเพื่อให้ง่าย

แม้ว่าจะมีสตริง แต่ก็มีข้อ จำกัด ในจำนวนตัวอักษรหรือ "ตัวเลข" ในจำนวนดังที่ระบุไว้ที่นี่:

ความยาวสูงสุดที่เป็นไปได้ของสตริง. NET คืออะไร?

แต่คุณสามารถเพิ่มตัวเลขจำนวนมาก ๆ ได้นอกเหนือจาก int32 หรือชนิด int64 ดั้งเดิมสำหรับ. Net

อย่างไรก็ตามนี่คือการใช้งานที่เก็บสตริง

/// <summary>
/// Adds two "integers".  The integers can be of any size string.
/// </summary>
/// <param name="BigInt1">The first integer</param>
/// <param name="BigInt2">The second integer</param>
/// <returns>A string that is the addition of the two integers passed.</returns>
/// <exception cref="Exception">Can throw an exception when parsing the individual parts     of the number.  Callers should handle. </exception>
public string AddBigInts(string BigInt1, string BigInt2)
{
    string result = string.Empty;

    //Make the strings the same length, pre-pad the shorter one with zeros
    int length = (BigInt1.Length > BigInt2.Length ? BigInt1.Length : BigInt2.Length);
    BigInt1 = BigInt1.PadLeft(length, '0');
    BigInt2 = BigInt2.PadLeft(length, '0');

    int remainder = 0;

    //Now add them up going from right to left
    for (int i = (BigInt1.Length - 1); i >= 0; i--)
    {
        //If we don't encounter a number, this will throw an exception as indicated.
        int int1 = int.Parse(BigInt1[i].ToString());
        int int2 = int.Parse(BigInt2[i].ToString());

        //Add
        int add = int1 + int2 + remainder;

        //Check to see if we need a remainder;
        if (add >= 10)
        {
            remainder = 1;
            add = add % 10;
        }
        else
        {
            remainder = 0;
        }

        //Add this to our "number"
        result = add.ToString() + result;
    }

    //Handle when we have a remainder left over at the end
    if (remainder == 1)
    {
        result = remainder + result;
    }

    return result;
}

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


เย็น!! ขอบคุณมันช่วยเคลียร์สิ่งต่างๆที่เหลือฉันจะมีความซับซ้อนมากกว่านั้นเล็กน้อย
ลโลว์

-2

อันนี้ใช้ได้ผลเร็วกว่าสำหรับฉัน:

static string Add(string a, string b)
        {
            string c = null;

            if (Compare(a, b) < 0)
            {
                c = a;
                a = b;
                b = c;
            }

            StringBuilder sb = new StringBuilder();

            b = b.PadLeft(a.Length, '0');

            int r = 0;

            for (int i = a.Length - 1; i >= 0; i--)
            {
                int part = a[i] + b[i] + r - 96;

                if (part <= 9)
                {
                    sb.Insert(0, part);

                    r = 0;
                }
                else
                {
                    sb.Insert(0, part - 10);

                    r = 1;
                }
            }

            if (r == 1)
            {
                sb.Insert(0, "1");
            }

            return sb.ToString();
        }

2
ไซต์นี้เกี่ยวกับคำถามเชิงแนวคิดและคำตอบที่คาดว่าจะอธิบายสิ่งต่าง ๆ การทิ้งโค้ดทิ้งแทนที่จะอธิบายเป็นเหมือนการคัดลอกโค้ดจาก IDE ไปยังไวท์บอร์ด: มันอาจดูคุ้นหูและบางครั้งก็เข้าใจได้ แต่มันให้ความรู้สึกแปลก ๆ ... มันแปลก ๆ ไวท์บอร์ดไม่ได้มีคอมไพเลอร์
ริ้น

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

เห็นด้วยกับริ้น อย่างน้อยอธิบายอัลกอริทึมก่อนที่จะทิ้งโค้ด
Frank Hileman

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