Операции с числами в разных системах счисления

// Модуль для работы с натуральными числами в различных системах исчисления
// Далее, если говорится, что Система Исчисления (СИ) задается строкой (CharSet)
// то имеется в виду, что эта строка содержит символы требуемой СИ, начиная с нуля
// Примеры CharSet (стандартный вид)
// Двоичная - '01'
// Восьмиричная - '01234567'
// Десятичная - '0123456789'
// Шестнадцатиричная - '0123456789ABCDEF'
// Можно использовать и нестандартные виды, например для двоичной 'ab', а для
// троичной 'abc' - данному модулю все равно.
// "-Ричность" СИ ограничена только наличием доступных различных символов.
// Работа с числами в определенной СИ производится как со строками, потому величина
// чисел значения почти не имеет, но это отрицательно сказывается на времени работы
// функций (особенно на умножении).
unit MyUnit;
interface
function Convert(Num, SetIn, SetOut: String): String;
function MySum (Num1, Num2, CharSet: String): String;
function MyMulti (Num1, Num2, CharSet: String): String;
function MyOrd(A: Char; CharSet: String): Integer;
function MyChr(Num: Integer; CharSet: String): Char;
implementation
// Функция возвращает позицию символа A в строке CharSet (начиная с 0)
function MyOrd(A: Char; CharSet: String): Integer;
var
 i: Integer;
begin
 Result := 0;
 for i := 1 to Length(CharSet) do
 begin
 if CharSet[i] = A then
 begin
 Result := i-1;
 exit;
 end
 end;
end;
// Функция возвращает символ из строки CharSet по номеру Num (~CharSet[Num+1])
function MyChr(Num: Integer; CharSet: String): Char;
begin
 Result := CharSet[Num mod Length(CharSet) + 1];
end;
// Функция возвращает число без ведущих нулей, то есть ShortNum('0000123')='123'
function ShortNum(Num, CharSet: String): String;
var
 k, j: Integer;
begin
 Result := ;
 k := 1;
 while Num[k] = MyChr(0, CharSet) do
 k := k + 1;
 for j := k to Length(Num) do
 Result := Result + Num[j];
end;
// Функция выполняет сложение двух чисел Num1 и Num2 в СИ, задаваемой CharSet
function MySum (Num1, Num2, CharSet: String): String;
var
 i, Pos, Add, L, L_CharSet: Integer;
 N1 , N2 , O, Res: String;
begin
 // Далее потребуется что бы первое число по длине было не менее второго,
 // если не так, то меняем местами
 if Length(Num1) >= Length(Num2) then
 begin
 N1 := Num1;
 N2 := Num2;
 end
 else
 begin
 N1 := Num2;
 N2 := Num1;
 end;
 L := Length(N1);
 L_CharSet := Length(CharSet);
 O := MyChr(0, CharSet); // 0 - в СИ, определяемой CharSet
 // Уравняем второе до длины первого нулями справа: 10 = 010
 for i := Length(N2) to L-1 do
 N2 := O + N2;
 Add := 0;
 // Суммирование с младших разрядов, Add - добавка от предыдущих разрядов
 // для следующего. Напр. для 10-чной СИ: 9+7 - Add = 1, 4+5 - Add=0
 for i := L downto 1 do
 begin
 Pos := MyOrd(N1[i], CharSet) + MyOrd(N2[i], CharSet) + Add;
 Add := 0;
 while Pos >= L_CharSet do
 begin
 Pos := Pos mod L_CharSet;
 Add := Add + 1;
 end;
 Res := MyChr(Pos, CharSet) + Res;
 end;
 if Add <> 0 then
 Result := MyChr(Add, CharSet) + Res
 else
 Result := Res;
end;
// Функция выполняет умножение двух чисел Num1 и Num2 в СИ, задаваемой CharSet
function MyMulti (Num1, Num2, CharSet: String): String;
var
 i, e, Res, N1, N2: String;
begin
 N1 := ShortNum(Num1, CharSet);
 N2 := ShortNum(Num2, CharSet);
 i := ;
 Res := ;
 // e - единица СИ, определяемая CharSet
 e := MyChr(1, CharSet);
 // Умножение Num1 на Num2 - это Num1 сложеное Num2 раз в СИ, определяемой CharSet
 while (i <> N2) do
 begin
 Res := MySum(Res, N1, CharSet);
 i := MySum(i, e, CharSet);
 end;
 Result := Res;
end;
// Функция выполняет преобразование одноразрядного числа A, заданного
// в СИ, определяемой SetIn, в число в СИ, определяемой SetOut
function f0(A: Char; SetIn, SetOut: String): String;
var
 Pos, j, L: Integer;
 Res: String;
begin
 L := Length(SetOut);
 Pos := MyOrd(A, SetIn);
 for j := 1 To Pos div (L-1) do
 Res := MySum(Res, MyChr(L-1, SetOut), SetOut);
 Result := MySum(Res, MyChr(Pos mod (L-1), SetOut), SetOut);
end;
// Функция выполняет преобразование числа Num, заданного
// в СИ, определяемой SetIn, в число в СИ, определяемой SetOut
function Convert(Num, SetIn, SetOut: String): String;
var
 Base, Multiplier, N, Res: String;
 i: Integer;
begin
 // Num = MultilplierN * Base^N + ... + Multiplier0 * Base^0
 // Base - основание СИ, это всегда <последний символ CharSet>+<нулевой символ> ~ 10
 // MultiplierI - множитель при соответствующей степени
 // Напр. для 10-чной СИ - 123 = 1 * 10^2 + 2 * 10^1 + 3 * 10^0
 // Тут Base = 10, Multiplier = {1, 2, 3}
 Base := MySum(f0(MyChr(Length(SetIn)-1, SetIn), SetIn, SetOut), MyChr(1, SetOut), SetOut);
 N := MyChr(1, SetOut); // = Base^0, потом будем домножать на Base (в соотв. СИ)
 Res := ;
 // Обрабатываем входящее число с хвоста
 for i := Length(Num) downto 1 do
 begin
 Multiplier := f0(Num[i], SetIn, SetOut);
 Res := MySum(Res, MyMulti(Multiplier, N, SetOut), SetOut);
 N := MyMulti(Base, N, SetOut);
 end;
 Result := Res;
end;
end.
Author: Zoobastik
Source: http://forum.sources.ru
ID: 04061
Category:Алгоритмы
Category:Математика