// Наработки в области длинной арифметики (даже не пытался оптимизировать)
// Число представляется в виде цифр в 100^n-ричной системе
// Показатель n определяется размером ячейки, отведенной для хранения цифры
// Формат выбран как наиболее удобный для вывода десятичных чисел (не требует деления по модулю 10)
// Реализованы функции сложения и умножения цифр в такой системе счисления
// CopyLeft (c) 2015 Alexey Kuzminov
program VeryLongInteger;
type
// Тип ячейки может быть любым:
// Integer, ShortInt, SmallInt, Longint, Byte, Word, LongWord, Cardinal
// Теоретически возможен QWord и Int64, но не компилится FullTest
TDigit = type SmallInt; // размер - 2 байта
var
MaxDigit: TDigit; // максимальное число, кратное степени 100 и не превосходящее High(TDigit)
HalfDigit: TDigit; // половина MaxDigit
SqrtDigit: TDigit; // квадратный корень из MaxDigit
DigitLength: Integer; // длина текста при выводе цифры
// Определяет MaxDigit и другие константы
procedure Init;
var
t: TDigit;
begin
t := High(TDigit);
MaxDigit := 1;
SqrtDigit := 1;
DigitLength := 0;
while t > 100 do begin
t := t div 100;
MaxDigit := MaxDigit * 100;
SqrtDigit := SqrtDigit * 10;
Inc(DigitLength, 2);
end;
HalfDigit := MaxDigit div 2;
end;
// a := (a + b) mod MaxDigit, результат 1 - есть переполнение, 0 - нет
function Add(var a: TDigit; b: TDigit): TDigit;
var
p: Byte;
begin
// Во избежание переполнения ЗАРАНЕЕ отнимем половину MaxDigit от a и b
p := 0;
if (a > HalfDigit) then begin Dec(a, HalfDigit); Inc(p); end;
if (b > HalfDigit) then begin Dec(b, HalfDigit); Inc(p); end;
// Теперь эта операция переполнения не вызовет
Inc(a, b);
if p = 0 then Add := 0 // оба слагаемых маленькие, переполнения нет
else if p = 2 then Add := 1 // оба слагаемых большие, переполнение гарантировано
else if a < HalfDigit then begin // одно слагаемое большое, но переполнения нет
Inc(a, HalfDigit);
Add := 0
end
else begin // сумма превысила MaxDigit, поэтому переполнеие
Dec(a, HalfDigit);
Add := 1
end;
end;
// a := (a * b) mod MaxDigit, результат (a * b) div MaxDigit - старшая часть
function Mul(var a: TDigit; b: TDigit): TDigit;
var
ah, al, bh, bl: TDigit;
t: TDigit;
begin
// разложим a = ah*SqrtDigit + al и b = bh*SqrtDigit + bl
al := a mod SqrtDigit; ah := a div SqrtDigit;
bl := b mod SqrtDigit; bh := b div SqrtDigit;
// результат: ah*bh*SqrtDigit^2 + (ah*bl+bh*al)*SqrtDigit + al*bl
// в процессе сложения нужно не допускать переполнения MaxDigit
// крайние слагаемые перепонения не вызовут
a := al*bl;
Mul := ah*bh; // SqrtDigit^2 = MaxDigit
// а вот со средним всё интереснее...
t := ah*bl;
if Add(t, bh*al) > 0 then Inc(Mul, SqrtDigit); // сложение может вызвать переполнение
// среднее слагаемое бьется на части: старшая в результат, mладшая в a
Inc(Mul, t div SqrtDigit);
Inc(Mul, Add(a, (t mod SqrtDigit)*SqrtDigit)); // и тут переполнение
// Замечание: ни при каком вызове Inc Mul не переполнится (не станет > MaxDigit)
end;
// дополняет нужное количество нулей левее числа
function DigitToStr(a: TDigit): String;
begin
Str(a, DigitToStr);
while DigitLength > Length(DigitToStr) do
DigitToStr := '0'+DigitToStr;
end;
// значение с коррекцией ошибок
function MakeDigit(Value: Int64): TDigit;
begin
MakeDigit := Value mod MaxDigit;
if MakeDigit < 0 then Inc(MakeDigit, MaxDigit);
end;
var
a, b, c, d: TDigit;
// процедура полномасштабного тестирования
procedure FullTest;
var
r, t: Int64;
begin
for a := 0 to MaxDigit - 1 do
for b := 0 to MaxDigit - 1 do begin
c := a;
d := Add(c, b);
t := Int64(d)*MaxDigit + Int64(c);
r := Int64(a)+Int64(b);
if (t <> r) or (c < 0) then begin
WriteLn('Ошибка сложения: ', a, ' + ', b, ' = ', d, '''', DigitToStr(c),
' должно быть: ', r);
Exit;
end;
c := a;
d := Mul(c, b);
t := Int64(d)*MaxDigit + Int64(c);
r := Int64(a)*Int64(b);
if (t <> r) or (c < 0) then begin
WriteLn('Ошибка умножения: ', a, ' * ', b, ' = ', d, '''', DigitToStr(c),
' должно быть: ', r);
Exit;
end;
end;
WriteLn('Проверка сложения и умножения успешна');
end;
begin
Init;
WriteLn('MaxDigit = ', MaxDigit, ' (length = ', DigitLength, ')');
a := MakeDigit(912223443222);
b := MakeDigit(123223448326);
Write(DigitToStr(a), ' + ', DigitToStr(b), ' = ');
Write(DigitToStr(Add(a, b)), ''''); WriteLn(DigitToStr(a));
a := MakeDigit(673993403459);
b := MakeDigit(381212100238);
Write(DigitToStr(a), ' * ', DigitToStr(b), ' = ');
Write(DigitToStr(Mul(a, b)), ''''); WriteLn(DigitToStr(a));
// полная проверка сложения и умножения, только для коротких типов
if SizeOf(TDigit) <= 1 then
FullTest;
end.
Ly8g0J3QsNGA0LDQsdC+0YLQutC4INCyINC+0LHQu9Cw0YHRgtC4INC00LvQuNC90L3QvtC5INCw0YDQuNGE0LzQtdGC0LjQutC4ICjQtNCw0LbQtSDQvdC1INC/0YvRgtCw0LvRgdGPINC+0L/RgtC40LzQuNC30LjRgNC+0LLQsNGC0YwpCi8vINCn0LjRgdC70L4g0L/RgNC10LTRgdGC0LDQstC70Y/QtdGC0YHRjyDQsiDQstC40LTQtSDRhtC40YTRgCDQsiAxMDBebi3RgNC40YfQvdC+0Lkg0YHQuNGB0YLQtdC80LUKLy8g0J/QvtC60LDQt9Cw0YLQtdC70YwgbiDQvtC/0YDQtdC00LXQu9GP0LXRgtGB0Y8g0YDQsNC30LzQtdGA0L7QvCDRj9GH0LXQudC60LgsINC+0YLQstC10LTQtdC90L3QvtC5INC00LvRjyDRhdGA0LDQvdC10L3QuNGPINGG0LjRhNGA0YsKLy8g0KTQvtGA0LzQsNGCINCy0YvQsdGA0LDQvSDQutCw0Log0L3QsNC40LHQvtC70LXQtSDRg9C00L7QsdC90YvQuSDQtNC70Y8g0LLRi9Cy0L7QtNCwINC00LXRgdGP0YLQuNGH0L3Ri9GFINGH0LjRgdC10LsgKNC90LUg0YLRgNC10LHRg9C10YIg0LTQtdC70LXQvdC40Y8g0L/QviDQvNC+0LTRg9C70Y4gMTApCi8vINCg0LXQsNC70LjQt9C+0LLQsNC90Ysg0YTRg9C90LrRhtC40Lgg0YHQu9C+0LbQtdC90LjRjyDQuCDRg9C80L3QvtC20LXQvdC40Y8g0YbQuNGE0YAg0LIg0YLQsNC60L7QuSDRgdC40YHRgtC10LzQtSDRgdGH0LjRgdC70LXQvdC40Y8KLy8gQ29weUxlZnQgKGMpIDIwMTUgQWxleGV5IEt1em1pbm92CnByb2dyYW0gVmVyeUxvbmdJbnRlZ2VyOwoKdHlwZQogIC8vINCi0LjQvyDRj9GH0LXQudC60Lgg0LzQvtC20LXRgiDQsdGL0YLRjCDQu9GO0LHRi9C8OgogIC8vICAgSW50ZWdlciwgU2hvcnRJbnQsIFNtYWxsSW50LCBMb25naW50LCBCeXRlLCBXb3JkLCBMb25nV29yZCwgQ2FyZGluYWwKICAvLyDQotC10L7RgNC10YLQuNGH0LXRgdC60Lgg0LLQvtC30LzQvtC20LXQvSBRV29yZCDQuCBJbnQ2NCwg0L3QviDQvdC1INC60L7QvNC/0LjQu9C40YLRgdGPIEZ1bGxUZXN0CiAgVERpZ2l0ID0gdHlwZSBTbWFsbEludDsgLy8g0YDQsNC30LzQtdGAIC0gMiDQsdCw0LnRgtCwCgp2YXIKICBNYXhEaWdpdDogVERpZ2l0OyAgLy8g0LzQsNC60YHQuNC80LDQu9GM0L3QvtC1INGH0LjRgdC70L4sINC60YDQsNGC0L3QvtC1INGB0YLQtdC/0LXQvdC4IDEwMCDQuCDQvdC1INC/0YDQtdCy0L7RgdGF0L7QtNGP0YnQtdC1IEhpZ2goVERpZ2l0KQogIEhhbGZEaWdpdDogVERpZ2l0OyAvLyDQv9C+0LvQvtCy0LjQvdCwIE1heERpZ2l0CiAgU3FydERpZ2l0OiBURGlnaXQ7IC8vINC60LLQsNC00YDQsNGC0L3Ri9C5INC60L7RgNC10L3RjCDQuNC3IE1heERpZ2l0CiAgRGlnaXRMZW5ndGg6IEludGVnZXI7IC8vINC00LvQuNC90LAg0YLQtdC60YHRgtCwINC/0YDQuCDQstGL0LLQvtC00LUg0YbQuNGE0YDRiwoKLy8g0J7Qv9GA0LXQtNC10LvRj9C10YIgTWF4RGlnaXQg0Lgg0LTRgNGD0LPQuNC1INC60L7QvdGB0YLQsNC90YLRiwpwcm9jZWR1cmUgSW5pdDsKdmFyCiAgdDogVERpZ2l0OwpiZWdpbgogIHQgOj0gSGlnaChURGlnaXQpOwogIE1heERpZ2l0IDo9IDE7CiAgU3FydERpZ2l0IDo9IDE7CiAgRGlnaXRMZW5ndGggOj0gMDsKICB3aGlsZSB0ID4gMTAwIGRvIGJlZ2luCiAgICB0IDo9IHQgZGl2IDEwMDsKICAgIE1heERpZ2l0IDo9IE1heERpZ2l0ICogMTAwOwogICAgU3FydERpZ2l0IDo9IFNxcnREaWdpdCAqIDEwOwogICAgSW5jKERpZ2l0TGVuZ3RoLCAyKTsKICBlbmQ7CiAgSGFsZkRpZ2l0IDo9IE1heERpZ2l0IGRpdiAyOwplbmQ7CgovLyBhIDo9IChhICsgYikgbW9kIE1heERpZ2l0LCDRgNC10LfRg9C70YzRgtCw0YIgMSAtINC10YHRgtGMINC/0LXRgNC10L/QvtC70L3QtdC90LjQtSwgMCAtINC90LXRggpmdW5jdGlvbiBBZGQodmFyIGE6IFREaWdpdDsgYjogVERpZ2l0KTogVERpZ2l0OyAKdmFyCiAgcDogQnl0ZTsKYmVnaW4KICAvLyDQktC+INC40LfQsdC10LbQsNC90LjQtSDQv9C10YDQtdC/0L7Qu9C90LXQvdC40Y8g0JfQkNCg0JDQndCV0JUg0L7RgtC90LjQvNC10Lwg0L/QvtC70L7QstC40L3RgyBNYXhEaWdpdCDQvtGCIGEg0LggYgogIHAgOj0gMDsKICBpZiAoYSA+IEhhbGZEaWdpdCkgdGhlbiBiZWdpbiBEZWMoYSwgSGFsZkRpZ2l0KTsgSW5jKHApOyBlbmQ7CiAgaWYgKGIgPiBIYWxmRGlnaXQpIHRoZW4gYmVnaW4gRGVjKGIsIEhhbGZEaWdpdCk7IEluYyhwKTsgZW5kOwogIAogIC8vINCi0LXQv9C10YDRjCDRjdGC0LAg0L7Qv9C10YDQsNGG0LjRjyDQv9C10YDQtdC/0L7Qu9C90LXQvdC40Y8g0L3QtSDQstGL0LfQvtCy0LXRggogIEluYyhhLCBiKTsKICBpZiBwID0gMCB0aGVuIEFkZCA6PSAwICAgICAgIC8vINC+0LHQsCDRgdC70LDQs9Cw0LXQvNGL0YUg0LzQsNC70LXQvdGM0LrQuNC1LCDQv9C10YDQtdC/0L7Qu9C90LXQvdC40Y8g0L3QtdGCCiAgZWxzZSBpZiBwID0gMiB0aGVuIEFkZCA6PSAxICAvLyDQvtCx0LAg0YHQu9Cw0LPQsNC10LzRi9GFINCx0L7Qu9GM0YjQuNC1LCDQv9C10YDQtdC/0L7Qu9C90LXQvdC40LUg0LPQsNGA0LDQvdGC0LjRgNC+0LLQsNC90L4KICBlbHNlIGlmIGEgPCBIYWxmRGlnaXQgdGhlbiBiZWdpbiAgLy8g0L7QtNC90L4g0YHQu9Cw0LPQsNC10LzQvtC1INCx0L7Qu9GM0YjQvtC1LCDQvdC+INC/0LXRgNC10L/QvtC70L3QtdC90LjRjyDQvdC10YIKICAJSW5jKGEsIEhhbGZEaWdpdCk7CiAgCUFkZCA6PSAwCiAgZW5kCiAgZWxzZSBiZWdpbiAgLy8g0YHRg9C80LzQsCDQv9GA0LXQstGL0YHQuNC70LAgTWF4RGlnaXQsINC/0L7RjdGC0L7QvNGDINC/0LXRgNC10L/QvtC70L3QtdC40LUKICAJRGVjKGEsIEhhbGZEaWdpdCk7CiAgCUFkZCA6PSAxCiAgZW5kOwplbmQ7CgovLyBhIDo9IChhICogYikgbW9kIE1heERpZ2l0LCDRgNC10LfRg9C70YzRgtCw0YIgKGEgKiBiKSBkaXYgTWF4RGlnaXQgLSDRgdGC0LDRgNGI0LDRjyDRh9Cw0YHRgtGMCmZ1bmN0aW9uIE11bCh2YXIgYTogVERpZ2l0OyBiOiBURGlnaXQpOiBURGlnaXQ7CnZhcgogIGFoLCBhbCwgYmgsIGJsOiBURGlnaXQ7CiAgdDogVERpZ2l0OwpiZWdpbgogIC8vINGA0LDQt9C70L7QttC40LwgYSA9IGFoKlNxcnREaWdpdCArIGFsINC4IGIgPSBiaCpTcXJ0RGlnaXQgKyBibAogIGFsIDo9IGEgbW9kIFNxcnREaWdpdDsgYWggOj0gYSBkaXYgU3FydERpZ2l0OwogIGJsIDo9IGIgbW9kIFNxcnREaWdpdDsgYmggOj0gYiBkaXYgU3FydERpZ2l0OwoKICAvLyDRgNC10LfRg9C70YzRgtCw0YI6IGFoKmJoKlNxcnREaWdpdF4yICsgKGFoKmJsK2JoKmFsKSpTcXJ0RGlnaXQgKyBhbCpibAogIC8vINCyINC/0YDQvtGG0LXRgdGB0LUg0YHQu9C+0LbQtdC90LjRjyDQvdGD0LbQvdC+INC90LUg0LTQvtC/0YPRgdC60LDRgtGMINC/0LXRgNC10L/QvtC70L3QtdC90LjRjyBNYXhEaWdpdAogIAogIC8vINC60YDQsNC50L3QuNC1INGB0LvQsNCz0LDQtdC80YvQtSDQv9C10YDQtdC/0L7QvdC10L3QuNGPINC90LUg0LLRi9C30L7QstGD0YIKICBhIDo9IGFsKmJsOwogIE11bCA6PSBhaCpiaDsgLy8gU3FydERpZ2l0XjIgPSBNYXhEaWdpdAogIAogIC8vINCwINCy0L7RgiDRgdC+INGB0YDQtdC00L3QuNC8INCy0YHRkSDQuNC90YLQtdGA0LXRgdC90LXQtS4uLgogIHQgOj0gYWgqYmw7CiAgaWYgQWRkKHQsIGJoKmFsKSA+IDAgdGhlbiBJbmMoTXVsLCBTcXJ0RGlnaXQpOyAvLyDRgdC70L7QttC10L3QuNC1INC80L7QttC10YIg0LLRi9C30LLQsNGC0Ywg0L/QtdGA0LXQv9C+0LvQvdC10L3QuNC1CiAgLy8g0YHRgNC10LTQvdC10LUg0YHQu9Cw0LPQsNC10LzQvtC1INCx0YzQtdGC0YHRjyDQvdCwINGH0LDRgdGC0Lg6INGB0YLQsNGA0YjQsNGPINCyINGA0LXQt9GD0LvRjNGC0LDRgiwgbdC70LDQtNGI0LDRjyDQsiBhCiAgSW5jKE11bCwgdCBkaXYgU3FydERpZ2l0KTsgICAgICAgICAgICAgICAgICAgICAKICBJbmMoTXVsLCBBZGQoYSwgKHQgbW9kIFNxcnREaWdpdCkqU3FydERpZ2l0KSk7IC8vINC4INGC0YPRgiDQv9C10YDQtdC/0L7Qu9C90LXQvdC40LUKICAvLyDQl9Cw0LzQtdGH0LDQvdC40LU6INC90Lgg0L/RgNC4INC60LDQutC+0Lwg0LLRi9C30L7QstC1IEluYyBNdWwg0L3QtSDQv9C10YDQtdC/0L7Qu9C90LjRgtGB0Y8gKNC90LUg0YHRgtCw0L3QtdGCID4gTWF4RGlnaXQpCmVuZDsKCi8vINC00L7Qv9C+0LvQvdGP0LXRgiDQvdGD0LbQvdC+0LUg0LrQvtC70LjRh9C10YHRgtCy0L4g0L3Rg9C70LXQuSDQu9C10LLQtdC1INGH0LjRgdC70LAKZnVuY3Rpb24gRGlnaXRUb1N0cihhOiBURGlnaXQpOiBTdHJpbmc7CmJlZ2luCiAgU3RyKGEsIERpZ2l0VG9TdHIpOwogIHdoaWxlIERpZ2l0TGVuZ3RoID4gTGVuZ3RoKERpZ2l0VG9TdHIpIGRvCiAgICBEaWdpdFRvU3RyIDo9ICcwJytEaWdpdFRvU3RyOwplbmQ7CgovLyDQt9C90LDRh9C10L3QuNC1INGBINC60L7RgNGA0LXQutGG0LjQtdC5INC+0YjQuNCx0L7QugpmdW5jdGlvbiBNYWtlRGlnaXQoVmFsdWU6IEludDY0KTogVERpZ2l0OwpiZWdpbgogIE1ha2VEaWdpdCA6PSBWYWx1ZSBtb2QgTWF4RGlnaXQ7CiAgaWYgTWFrZURpZ2l0IDwgMCB0aGVuIEluYyhNYWtlRGlnaXQsIE1heERpZ2l0KTsgCmVuZDsKCnZhcgogIGEsIGIsIGMsIGQ6IFREaWdpdDsKCi8vINC/0YDQvtGG0LXQtNGD0YDQsCDQv9C+0LvQvdC+0LzQsNGB0YjRgtCw0LHQvdC+0LPQviDRgtC10YHRgtC40YDQvtCy0LDQvdC40Y8KcHJvY2VkdXJlIEZ1bGxUZXN0Owp2YXIKICByLCB0OiBJbnQ2NDsKYmVnaW4KICBmb3IgYSA6PSAwIHRvIE1heERpZ2l0IC0gMSBkbwogICAgZm9yIGIgOj0gMCB0byBNYXhEaWdpdCAtIDEgZG8gYmVnaW4KICAgICAgYyA6PSBhOwogICAgICBkIDo9IEFkZChjLCBiKTsKICAgICAgdCA6PSBJbnQ2NChkKSpNYXhEaWdpdCArIEludDY0KGMpOwogICAgICByIDo9IEludDY0KGEpK0ludDY0KGIpOwogICAgICBpZiAodCA8PiByKSBvciAoYyA8IDApIHRoZW4gYmVnaW4KICAgICAgICBXcml0ZUxuKCfQntGI0LjQsdC60LAg0YHQu9C+0LbQtdC90LjRjzogJywgYSwgJyArICcsIGIsICcgPSAnLCBkLCAnJycnLCBEaWdpdFRvU3RyKGMpLAogICAgICAgICAgJyDQtNC+0LvQttC90L4g0LHRi9GC0Yw6ICcsIHIpOwogICAgICAgIEV4aXQ7CiAgICAgIGVuZDsKICAgICAgCiAgICAgIGMgOj0gYTsKICAgICAgZCA6PSBNdWwoYywgYik7CiAgICAgIHQgOj0gSW50NjQoZCkqTWF4RGlnaXQgKyBJbnQ2NChjKTsKICAgICAgciA6PSBJbnQ2NChhKSpJbnQ2NChiKTsKICAgICAgaWYgKHQgPD4gcikgb3IgKGMgPCAwKSB0aGVuIGJlZ2luCiAgICAgICAgV3JpdGVMbign0J7RiNC40LHQutCwINGD0LzQvdC+0LbQtdC90LjRjzogJywgYSwgJyAqICcsIGIsICcgPSAnLCBkLCAnJycnLCBEaWdpdFRvU3RyKGMpLAogICAgICAgICAgJyDQtNC+0LvQttC90L4g0LHRi9GC0Yw6ICcsIHIpOwogICAgICAgIEV4aXQ7CiAgICAgIGVuZDsKICAgIGVuZDsKICBXcml0ZUxuKCfQn9GA0L7QstC10YDQutCwINGB0LvQvtC20LXQvdC40Y8g0Lgg0YPQvNC90L7QttC10L3QuNGPINGD0YHQv9C10YjQvdCwJyk7CmVuZDsKCmJlZ2luCiAgSW5pdDsKICAKICBXcml0ZUxuKCdNYXhEaWdpdCA9ICcsIE1heERpZ2l0LCAnIChsZW5ndGggPSAnLCBEaWdpdExlbmd0aCwgJyknKTsKICAKICBhIDo9IE1ha2VEaWdpdCg5MTIyMjM0NDMyMjIpOwogIGIgOj0gTWFrZURpZ2l0KDEyMzIyMzQ0ODMyNik7CiAgV3JpdGUoRGlnaXRUb1N0cihhKSwgJyArICcsIERpZ2l0VG9TdHIoYiksICcgPSAnKTsKICBXcml0ZShEaWdpdFRvU3RyKEFkZChhLCBiKSksICcnJycpOyBXcml0ZUxuKERpZ2l0VG9TdHIoYSkpOwoKICBhIDo9IE1ha2VEaWdpdCg2NzM5OTM0MDM0NTkpOwogIGIgOj0gTWFrZURpZ2l0KDM4MTIxMjEwMDIzOCk7CiAgV3JpdGUoRGlnaXRUb1N0cihhKSwgJyAqICcsIERpZ2l0VG9TdHIoYiksICcgPSAnKTsKICBXcml0ZShEaWdpdFRvU3RyKE11bChhLCBiKSksICcnJycpOyBXcml0ZUxuKERpZ2l0VG9TdHIoYSkpOwoKICAvLyDQv9C+0LvQvdCw0Y8g0L/RgNC+0LLQtdGA0LrQsCDRgdC70L7QttC10L3QuNGPINC4INGD0LzQvdC+0LbQtdC90LjRjywg0YLQvtC70YzQutC+INC00LvRjyDQutC+0YDQvtGC0LrQuNGFINGC0LjQv9C+0LIKICBpZiBTaXplT2YoVERpZ2l0KSA8PSAxIHRoZW4KICAgIEZ1bGxUZXN0OwplbmQu