Подтвердить что ты не робот

Как обращаться с произвольно большими целыми числами

Я работаю над языком программирования, и сегодня у меня есть точка, где я могу скомпилировать факториальную функцию (рекурсивную), однако из-за максимального размера целого числа, которое я могу получить, это факторный (12). Каковы некоторые методы обработки целых чисел произвольного максимального размера. Язык в настоящее время работает, переводя код на С++.

4b9b3361

Ответ 1

Если вам нужно больше 32 бит, вы можете рассмотреть возможность использования 64-битных целых чисел (длинный длинный) или использовать или записывать произвольную математическую библиотеку точности, например. GNU MP.

Ответ 2

Если вы хотите перевернуть свою собственную произвольную библиотеку точности, см. Семинумерные алгоритмы Кнута, том 2 его магнума opus.

Ответ 3

Если вы строите это на языке (для учебных целей, я бы догадался), я думаю, что, вероятно, я бы написал небольшую библиотеку BCD. Просто сохраните номера BCD в массивах байтов.

Фактически, с сегодняшними гигантскими способностями хранения вы можете просто использовать массив байтов, где каждый байт просто содержит цифру (0-9). Затем вы пишете свою собственную процедуру для добавления, вычитания умножения и деления массивов байтов.

(Divide - жесткий, но я уверен, вы можете найти там какой-то код.)

Я могу дать вам некоторый Java-подобный psuedocode, но на данный момент он не может делать С++ с нуля:

class BigAssNumber {
    private byte[] value;

    // This constructor can handle numbers where overflows have occurred.
    public BigAssNumber(byte[] value) {
        this.value=normalize(value);
    }

    // Adds two numbers and returns the sum.  Originals not changed.
    public BigAssNumber add(BigAssNumber other) {
        // This needs to be a byte by byte copy in newly allocated space, not pointer copy!
        byte[] dest = value.length > other.length ? value : other.value;         

        // Just add each pair of numbers, like in a pencil and paper addition problem.
        for(int i=0; i<min(value.length, other.value.length); i++)
            dest[i]=value[i]+other.value[i];

        // constructor will fix overflows.
        return new BigAssNumber(dest);
    }

    // Fix things that might have overflowed  0,17,22 will turn into 1,9,2        
    private byte[] normalize(byte [] value) {
        if (most significant digit of value is not zero)
            extend the byte array by a few zero bytes in the front (MSB) position.

        // Simple cheap adjust.  Could lose inner loop easily if It mattered.
        for(int i=0;i<value.length;i++)
            while(value[i] > 9) {
                value[i] -=10;
                value[i+1] +=1;
            }
        }
    }
}

Я использую тот факт, что у нас есть много лишней комнаты в байте, чтобы помочь справиться с дополнительными переполнениями в общем виде. Может также работать для вычитания и помогать в некоторых умножениях.

Ответ 4

В С++ нет простого способа сделать это. Вам нужно будет использовать внешнюю библиотеку, такую ​​как GNU Multiprecision, или использовать другой язык, который изначально поддерживает сколь угодно большие целые числа, такие как Python.

Ответ 5

Другие плакаты предоставили ссылки на библиотеки, которые сделают это для вас, но похоже, что вы пытаетесь создать это на своем языке. Моя первая мысль: вы уверены, что вам нужно это сделать? Большинство языков будут использовать дополнительную библиотеку, как предложили другие.

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

Например, простая (но неоптимальная) реализация будет представлять числа как двоично-кодированные десятичные числа. Арифметические функции могут использовать те же алгоритмы, которые вы использовали бы, если бы делали математику с карандашом и бумагой.

Также рассмотрим использование специализированного типа данных для этих больших целых чисел. Таким образом, "нормальные" целые числа могут использовать стандартную 32-разрядную арифметику.

Ответ 6

Мой предпочтительный подход состоял бы в том, чтобы использовать мой текущий тип int для 32-битных int (или, возможно, изменить его на внутреннее, чтобы быть длинным или некоторым таким, если он может продолжать использовать одни и те же алгоритмы), тогда, когда он переполняется, изменяет ли он на сохранение в виде бигма, будь то мое собственное создание или использование внешней библиотеки. Тем не менее, я чувствую, что мне нужно будет проверять переполнение при каждой арифметической операции, примерно в 2 раза выше арифметических операций. Как я могу это решить?

Ответ 7

Если бы я реализовал свой собственный язык и хочу поддерживать произвольные номера длин, я буду использовать целевой язык с концепцией переноса/записи. Но поскольку нет HLL, который реализует это без серьезных последствий для производительности (например, исключений), я обязательно пойду реализовать его в сборке. Вероятно, потребуется одна инструкция (как в JC в x86), чтобы проверить переполнение и обработать ее (как в ADC на x86), что является приемлемым компромиссом для языка, реализующего произвольную точность. Тогда я буду использовать несколько функций, написанных в сборке вместо обычных операторов, если вы можете использовать перегрузку для более элегантного вывода, еще лучше. Но я не ожидаю, что сгенерированный С++ будет поддерживаться (или должен поддерживаться) как целевой язык.

Или просто используйте библиотеку, которая имеет больше колоколов и свистов, чем вам нужно, и используйте ее для всех ваших номеров.

Как гибридный подход, обнаруживайте переполнение в сборке и вызывайте библиотечную функцию, если переполнение, вместо того, чтобы сворачивать собственную мини-библиотеку.