Поводження з надзвичайно великою кількістю мовою, яка не може?


15

Я намагаюся подумати над тим, як би я міг робити обчислення на надзвичайно великій кількості (до infinitum - intergers no floats), якщо мовна конструкція не здатна обробляти числа, що перевищують певне значення.

Я впевнений, що я не перший і не останній, хто задав це питання, але пошукові терміни, які я використовую, не дають мені алгоритму для вирішення цих ситуацій. Швидше за все, більшість пропозицій пропонують зміни мови чи змінну зміну або розповідають про речі, які здаються нерелевантними для мого пошуку. Тому мені потрібно невелике керівництво.

Я б намалював такий алгоритм:

  1. Визначте максимальну довжину цілочисельної змінної для мови.

  2. Якщо число більше половини довжини максимальної довжини змінної, розділіть її на масив. (дайте невелику ігрову кімнату)

  3. Порядок масиву [0] = числа найбільше праворуч [n-max] = числа найбільше зліва

    Вих. Число: 29392023 Масив [0]: 23, Масив [1]: 20, масив [2]: 39, масив [3]: 29

Оскільки я встановив половину довжини змінної як точки відмітки, то я можу обчислити одиниці, десяті, соті тощо. Розташуйте через позначку на півдорозі, щоб, якщо змінна максимальна довжина становила 10 цифр від 0 до 9999999999, то я знаю, що Половини, що на п’ять цифр, дають мені ігрову кімнату.

Отже, якщо я додаю або помножую, я можу мати функцію перевірки змінної, яка бачить, що шоста цифра (справа) масиву [0] - те саме місце, що і перша цифра (справа) масиву [1].

Ділення та віднімання мають свої проблеми, про які я ще не думав.

Я хотів би дізнатися про найкращі реалізації підтримки більшої кількості, ніж програма.


1
Перше, що спадає на думку - це BigInteger Java: docs.oracle.com/javase/6/docs/api/java/math/BigInteger.html
Іван

Це мова, яку хтось тут може знати і вміє давати конкретні рекомендації, чи це щось незрозуміле і власне?
FrustratedWithFormsDesigner

Я не знаю, на якій мові я цього ще хотів би. Я знаю php найбільше, але я не хочу робити це на тій мові. Lisp привабливий, оскільки з того, що я прочитав, він не обмежує довжину. Однак мій особистий недолік прагнення дізнатися, як це працює, змушує мене мати свободу робити це в qbasic, якби я застряг на острові. (Це теж для розваги. Я завжди думаю про обчислення великої кількості, а деякі онлайн-калькулятори занадто громіздкі для виконання завдання.)
Малв

Відповіді:


25

Ви шукаєте бібліотеку довільної арифметики точності (також її називають "багатоточна точність" або "велика кількість") для мови, з якою ви працюєте. Наприклад, якщо ви працюєте з C, ви можете використовувати Бібліотеку GNU Bignum -> http://gmplib.org/

Якщо ви хочете зрозуміти, як це працює, ви також можете написати свою власну бібліотеку великих чисел і використовувати її. Найпростіший спосіб впоратися з цим - це масиви, де кожен елемент - це цифра числа, з яким ви працюєте. Після цього потрібно реалізувати всі функції додавання, віднімання, множення, ділення, експоненціації тощо.


5
Звичайно, "цифра" є відносною, багато бібліотек bignum використовують цифри в базі 256 (без підпису байтів []) до 2 ^ 64 (без підпису довго [])
храповик виродка

1
Просто переконавшись, що я зрозумів, "цифра" може бути масивом базових 256 цифр? Я думаю, що я можу помилитися, робити математику на базі 256 простіше, ніж на базі 88, але все ж таки досить завдання ... (Принаймні, коли я це робив минулої ночі на аркуші паперу, ха-ха)
Малв

1
"робити математику на базі 256 простіше, ніж на базі 88". Помилковий. Вони однаково прості.
S.Lott

2
@ S.Lott: гм ... коли у вас доступні побітні операції, робити математику на базі 256, безумовно, простіше, ніж на базі 88.
Jason S

1
Створення власного додавання / віднімання / множення є досить простим. Поділ є складним, однак, якщо ви не впроваджуєте його у двійковій формі, де він стає вправою умовного віднімання та зміщення бітів.
Джейсон S

13

Це добре відома проблема: Довільна арифметика точності

Коли мова, якою ви користуєтеся, не вирішує цю проблему, спробуйте знайти бібліотеку сторонніх розробників. Якщо ви не знайдете його або вам цікаво, спробуйте його здійснити; у статті вікіпедії є хороші посилання на класичні реалізації.


6

Маючи справу з великою кількістю, мабуть, одне з найбільш фундаментальних дизайнерських рішень - як я буду представляти велику кількість?

Це буде рядок, масив, список або власний клас зберігання (в домашніх умовах).

Після того, як це рішення буде прийнято, фактичні математичні операції можна розбити на більш дрібні частини, а потім виконати з типом рідної мови, такими як int або integer.

Я включив дуже елементарний приклад додавань в 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 на дошку: це може здатися звичним і навіть іноді бути зрозумілим, але це дивно ... просто дивно. У дошці немає компілятора
gnat

Цей сайт обміняється, тому ми намагаємось допомогти один одному наскільки можемо. Можливо, я повинен робити такі коментарі в StackOverflow, але я намагався допомогти зі своїм підходом. Якщо комусь ще потрібне пояснення, він попросить його. Я роблю тут стандартне математичне додавання цифр за цифрою, починаючи з кінця.
Андранік Саргсян

Погодьтеся з гнатом. Принаймні поясніть алгоритм перед скиданням коду.
Френк Хілеман

Просто демпінговий код без жодних пояснень схожий на заохочення копіювання-минулого та йти. Я не бачу, як це може бути корисним у SoftwareEngineering. Можливо, в StackOverflow є, але обидва сайти насправді мають абсолютно різні цілі.
Лаїв
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.