Xử lý số lượng cực lớn trong một ngôn ngữ không thể?


15

Tôi đang cố gắng suy nghĩ về cách tôi sẽ thực hiện các phép tính trên các số cực lớn (đến infinitum - intergers no float) nếu cấu trúc ngôn ngữ không có khả năng xử lý các số lớn hơn một giá trị nhất định.

Tôi chắc chắn tôi không phải là người đầu tiên cũng không phải là người cuối cùng đặt câu hỏi này nhưng các thuật ngữ tìm kiếm tôi đang sử dụng không mang lại cho tôi một thuật toán để xử lý các tình huống đó. Thay vào đó, hầu hết các đề xuất cung cấp một sự thay đổi ngôn ngữ hoặc thay đổi biến đổi, hoặc nói về những điều dường như không liên quan đến tìm kiếm của tôi. Vì vậy, tôi cần một chút hướng dẫn.

Tôi sẽ phác thảo một thuật toán như thế này:

  1. Xác định độ dài tối đa của biến số nguyên cho ngôn ngữ.

  2. Nếu một số lớn hơn một nửa chiều dài của chiều dài tối đa của biến thì chia nó thành một mảng. (cho một phòng chơi nhỏ)

  3. Thứ tự mảng [0] = số nhiều nhất bên phải [n-max] = số nhiều nhất bên trái

    Ví dụ. Num: 29392023 Mảng [0]: 23, Mảng [1]: 20, mảng [2]: 39, mảng [3]: 29

Vì tôi đã thiết lập một nửa chiều dài của biến là điểm đánh dấu, sau đó tôi có thể tính toán các điểm, phần mười, phần trăm, v.v. Đặt qua dấu nửa chừng để nếu độ dài tối đa của biến là 10 chữ số từ 0 đến 9999999999 thì tôi biết rằng bằng một nửa số đó đến năm chữ số cho tôi một phòng chơi.

Vì vậy, nếu tôi thêm hoặc nhân tôi có thể có một hàm kiểm tra biến để thấy rằng chữ số thứ sáu (từ bên phải) của mảng [0] là cùng một vị trí với chữ số đầu tiên (từ bên phải) của mảng [1].

Chia và trừ có những vấn đề riêng mà tôi chưa nghĩ đến.

Tôi muốn biết về việc triển khai tốt nhất để hỗ trợ số lượng lớn hơn chương trình có thể.


1
Điều đầu tiên bạn nghĩ đến là BigInteger của Java: docs.oracle.com/javase/6/docs/api/java/math/BigInteger.html
Ivan

Đây có phải là một ngôn ngữ mà bất cứ ai ở đây có thể biết và có thể đưa ra các khuyến nghị cụ thể, hoặc nó là một cái gì đó tối nghĩa và độc quyền?
Thất vọngWithFormsDesigner

Tôi không biết ngôn ngữ nào tôi muốn có ngôn ngữ này. Tôi biết php nhiều nhất nhưng tôi không muốn làm điều đó bằng ngôn ngữ đó. Lisp hấp dẫn vì từ những gì tôi đã đọc, nó không có giới hạn về độ dài. Tuy nhiên, lỗ hổng cá nhân của tôi muốn biết nó hoạt động như thế nào khiến tôi muốn có tự do để làm điều đó trong qbasic nếu tôi bị mắc kẹt trên một hòn đảo. (Điều này cũng rất vui, tôi luôn nghĩ về việc tính toán số lượng lớn và một số máy tính trực tuyến quá cồng kềnh cho nhiệm vụ.)
Mallow

Câu trả lời:


25

Bạn đang tìm kiếm một thư viện số học chính xác tùy ý (còn được gọi là thư viện "nhiều độ chính xác" hoặc "chữ số lớn") cho ngôn ngữ bạn đang làm việc. Chẳng hạn, nếu bạn đang làm việc với C, bạn có thể sử dụng Thư viện Bignum GNU -> http://gmplib.org/

Nếu bạn muốn hiểu làm thế nào nó hoạt động, bạn cũng có thể viết thư viện num lớn của riêng bạn và sử dụng nó. Cách đơn giản nhất để xử lý việc này là với các mảng, trong đó mỗi phần tử là một chữ số của số bạn đang làm việc. Sau đó, bạn cần thực hiện tất cả các hàm để cộng, trừ, nhân, chia, lũy thừa, v.v.


5
tất nhiên "chữ số" là tương đối, nhiều thư viện bignum sử dụng các chữ số trong cơ sở 256 (byte không dấu []) đến 2 ^ 64 (dài không dấu [])
ratchet freak

1
Chỉ cần chắc chắn rằng tôi hiểu, 'chữ số' có thể là một mảng gồm 256 chữ số cơ bản? Tôi nghĩ rằng tôi có thể bị nhầm lẫn, làm toán trên cơ sở 256 là dễ dàng hơn cơ sở 88 nhưng vẫn còn khá một nhiệm vụ ... (Ít nhất là khi tôi đã làm nó đêm qua trên một tờ giấy haha)
Mallow

1
"Làm toán trên cơ sở 256 dễ hơn cơ sở 88". Sai. Chúng dễ dàng như nhau.
S.Lott

2
@ S.Lott: ừm ... khi bạn có sẵn các thao tác bitwise, làm toán trên cơ sở 256 chắc chắn dễ dàng hơn cơ sở 88.
Jason S

1
Xây dựng phép cộng / trừ / nhân của riêng bạn khá đơn giản. Mặc dù vậy, việc phân chia là khó khăn, trừ khi bạn thực hiện nó ở dạng nhị phân, nơi nó trở thành một bài tập trong phép trừ có điều kiện và dịch chuyển bit.
Jason S

13

Đây là một vấn đề nổi tiếng: Số học chính xác tùy ý

Khi ngôn ngữ bạn đang sử dụng không giải quyết được vấn đề này, trước tiên hãy thử tìm thư viện bên thứ ba. Nếu bạn không tìm thấy nó hoặc bạn tò mò, hãy thử thực hiện nó; bài viết trên wikipedia có một tài liệu tham khảo tốt để triển khai cổ điển.


6

Khi xử lý số lượng lớn, có lẽ một trong những quyết định thiết kế cơ bản nhất là làm thế nào để tôi đại diện cho số lượng lớn?

Nó sẽ là một chuỗi, một mảng, một danh sách hoặc lớp lưu trữ tùy chỉnh (cây nhà lá vườn).

Sau khi quyết định đó được đưa ra, các phép toán thực tế có thể được chia thành các phần nhỏ hơn và sau đó được thực hiện với các loại ngôn ngữ bản địa như int hoặc số nguyên.

Tôi đã bao gồm một ví dụ THÊM rất thô sơ trong C # .Net lưu trữ số lượng lớn kết quả dưới dạng chuỗi. "Số" đến cũng là các chuỗi, vì vậy người ta có thể gửi số "rất lớn". Hãy nhớ rằng ví dụ này chỉ dành cho các số nguyên để giữ cho nó đơn giản.

Ngay cả với các chuỗi cũng có giới hạn về số lượng ký tự hoặc "số" trong số, như được chỉ ra ở đây:

Độ dài tối đa có thể có của một chuỗi .NET là bao nhiêu?

Nhưng bạn có thể thêm một số số thực sự lớn, vượt xa các kiểu gốc int32 hoặc int64 cho .Net.

Dù sao, đây là một triển khai lưu trữ chuỗi.

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

Tôi hy vọng rằng cung cấp cho bạn một số ý tưởng về việc thực hiện của riêng bạn. Xin lưu ý rằng mã mẫu có thể không được tối ưu hóa hoặc bất cứ thứ gì tương tự. Nó có nghĩa là để đưa ra một số ý tưởng về cách nó có thể được thực hiện.


Mát mẻ!! Cảm ơn nó giúp làm sáng tỏ mọi thứ với phần còn lại tôi sẽ có phần phức tạp hơn.
Mallow

-2

Cái này hoạt động nhanh hơn đối với tôi:

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
Trang web này là về câu hỏi khái niệm và câu trả lời dự kiến ​​sẽ giải thích mọi thứ. Ném các đoạn mã thay vì giải thích giống như sao chép mã từ IDE sang bảng trắng: nó có thể trông quen thuộc và thậm chí đôi khi có thể hiểu được, nhưng nó cảm thấy kỳ lạ ... chỉ là lạ. Bảng trắng không có trình biên dịch
gnat

Trang web này là TRAO ĐỔI, vì vậy chúng tôi cố gắng giúp đỡ nhau hết mức có thể. Có lẽ tôi nên bình luận như vậy trong StackOverflow, nhưng tôi đã cố gắng giúp đỡ với cách tiếp cận của mình. Nếu ai đó vẫn cần một lời giải thích, anh ta sẽ yêu cầu nó. Tôi làm ở đây một chữ số bổ sung toán học tiêu chuẩn bằng chữ số, bắt đầu từ cuối.
Andranik Sargsyan

Đồng ý với gnat. Ít nhất là giải thích thuật toán trước khi bán mã.
Frank Hileman

Chỉ cần bán mã mà không có lời giải thích cũng giống như khuyến khích bản sao và quá khứ. Tôi không thấy làm thế nào có thể hữu ích trong SoftwareEngineering. Có thể tại StackOverflow, nhưng cả hai trang web thực sự có mục đích hoàn toàn khác nhau.
Laiv
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.