Целое число произвольной длины в Аде

В настоящее время я учу себя Аде, и хотя я мог бы начать с решения некоторых из более обычных задач для начала.

Точнее, я пытаюсь вычислить факториал n!, тогда как n>100. Моя реализация до сих пор:

with Ada.Text_IO;
with Ada.Integer_Text_IO;

use Ada.Text_IO;

procedure Factorial is 
    -- define a type covering the range beginning at 1 up to which faculty is to
    -- be computed.
    subtype Argument is Long_Long_Integer range 1..100;

    -- define a type that is large enough to hold the result
    subtype Result is Long_Long_Integer range 1..Long_Long_Integer'Last;
    package Result_IO is new Ada.Text_IO.Integer_IO(Result); use Result_IO;

    -- variable holding the faculty calculated.
    fac : Result := 1;

begin
    -- loop over whole range of ARGUMENT and calculate n!
    for n in ARGUMENT loop
        fac := (fac * n);
    end loop;
end;

Проблема, очевидно, в том, что даже Long_Long_Integer может быть слишком мал для этого и выдает исключение CONTRAINT_ERROR для n>20.

Есть ли пакет, реализующий целые числа произвольного размера?

Спасибо!

PS: я отказался от рекурсии, потому что хотел изучить циклы в этом упражнении. Но в противном случае, пожалуйста, прокомментируйте все аспекты кода (стиль, лучшие практики, ошибки..)


ada
person Arne    schedule 20.08.2009    source источник


Ответы (2)


Криптобиблиотека Ады поддерживает большие числа без знака (Big_Numbers). Вы можете загрузить библиотеку с http://sourceforge.net/projects/libadacrypt-dev/. . Я рекомендую проверить svn. Функция умножения Big_Numbers в текущем выпуске содержит небольшую ошибку.

Вы можете скомпилировать библиотеку с текущим компилятором GNAT с сайта AdaCore Libre.

Библиотека не будет компилироваться под gcc-4.3 или gcc-4.4 из-за ошибки в gcc. .

Наконец, я приведу небольшой пример, как умножить два 512-битных Big_Number из библиотеки LibAdaCrypt.

package Test.Big_Numbers is

with Crypto.Types.Big_Numbers;

pragma Elaborate_All(Crypto.Types.Big_Numbers);

package Big is new Crypto.Types.Big_Numbers(512);
    use Big;
    use Big.Utils;
end Test.Big_Numbers;



package body Test.Big_Numbers is

x : Big_Unsigned := To_Big_Unsigned("16#57C19F8F7866F8633AC1D25B92FC83B4#");
Y : Big_Unsigned := To_Big_Unsigned("16#FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF60#");

x := X * Y;
Put_Line(X);

end Test.Big_Numbers;
 
Best regards
   Christian
person Christian Forler    schedule 21.08.2009
comment
большое спасибо! Это гораздо больший ответ, чем я надеялся получить. Я проверю. - person Arne; 23.08.2009
comment
Хороший ответ, Кристиан. Я пошел дальше и проверил ваши дополнительные веб-страницы и превратил их в ссылки для вас. Надеюсь, дополнительные 10 баллов от моего голоса помогут вам быстрее покинуть ненадежную страну нубов. - person T.E.D.; 24.08.2009

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

Учитывая это, жаль, что стандарт не предоставил нам, пользователям, стандартный доступ к этому средству. Опять же, использование для того, что нужно компилятору, и использование для общего использования часто могут быть двумя разными вещами.

person T.E.D.    schedule 24.08.2009