Сложение и умножение больших чисел с использованием динамической памяти - PascalABC.NET

Узнай цену своей работы

Формулировка задачи:

Задача такова: Используя динамическую память, организовать сложение и умножение двух заданных чисел. (т.к. данная задача является лишь подготовительной к более сложной, в которой 2 числа задаются заранее, организовывать считывание откуда бы то ни было в этой задаче так же не имеет смысла.) Мой код:
Проблемы: 1) Глобальные переменные

x

и

y

идентичны во всём (кроме, конечно, значения) и проходят через одни и те же процедуры и функции. НО если при изменении переменной

y

программа остаётся работоспособной, то при изменении

x

(в частности, при увеличении его до трёхзначного числа и более) в строке 95 обнаруживается ошибка (Ошибка времени выполнения: ссылка на объект не указывает на экземпляр объекта). 2) В функции умножения результат имеет 2 лишних нуля в конце. Я подозреваю, что это либо вызвано инициализацией пустых деков, либо просчетами с переменными

count

и

count0

. Но сколько-нибудь полноценно исправить это у меня не вышло. Прошу указать на причины данных ошибок и дать советы по их устранению.
Вопрос больше не актуален, исправила всё самостоятельно.

Решение задачи: «Сложение и умножение больших чисел с использованием динамической памяти»

textual
Листинг программы
type
  tDigit = class
    N : Byte;
    L, R : tDigit;
    
    constructor (N_ : Byte; L_ : tDigit := nil; R_ : tDigit := nil);
    begin
      (N, L, R) := (N_, L_, R_);
      if L_ <> nil then L_.R := Self;
      if R_ <> nil then R_.L := Self;
    end;
  end;
  
type
  bNumber = record
    Len : Integer; /// Длина числа
    Left, Right : tDigit; /// Ссылка на начало и конец числа
    
    /// Добавление цифры слева
    procedure LeftDigit(N : Byte);
    begin
      Len += 1;
      Left := New tDigit(N, nil, Left);
    end;
    
    /// Добавление цифры справа
    procedure RightDigit(N : Byte);
    begin
      Len += 1;
      Right := New tDigit(N, Right, nil);
    end;
 
    /// Создание числа из целого
    constructor (N : Integer);
    begin
      Len := 1;
      Right := New tDigit(N mod 10);
      N := N div 10;
      Left := Right;
      
      while N <> 0 do
        begin
          LeftDigit(N mod 10);
          N := N div 10;
        end;
    end;
    
    /// Создание числа из строки
    constructor (S : String);
    begin
      Len := 1;
      Right := New tDigit(Ord(S[S.Length])-48);
      Left := Right;
      
      for var Index := S.Length-1 downto 1 do
        LeftDigit(Ord(S[Index])-48);
    end;
    
    /// Создание из другого длинного числа
    constructor (n : bNumber);
    begin
      Len := 1;
      Right := New tDigit(n.Right.N);
      Left := Right;
      var Cur := n.Right.L;
      while Cur <> nil do
        begin
          LeftDigit(Cur.N);
          Cur := Cur.L;
        end;
    end;
    
    /// Преобразование числа в строку
    function toString : String; override;
    begin
      Result := '';
      var Cur := Left;
      while Cur <> nil do
        (Result, Cur) := (Result + Cur.N.ToString, Cur.R);
    end;
    
    /// Вывод числа
    function Print : bNumber;
    begin
      Write(toString);
      Result := Self;
    end;
    
    /// Вывод числа с переходом на новую строку
    function PrintLn : bNumber;
    begin
      WriteLn(ToString);
      Result := Self;
    end;
    
    /// Добавление длинного числа
    function Add(n : bNumber) : bNumber;
    begin
      var d : Byte := 0;
      var cCur := Right;
      var nCur := n.Right;
      // сложим все цифры по самой маленькой длине числа
      while (cCur <> nil) and (nCur <> nil) do
        begin
          d += cCur.N + nCur.N;
          cCur.N := d mod 10;
          d := d div 10;
          cCur := cCur.L;
          nCur := nCur.L;
        end;
      // если во втором числе больше знаков, то нужно добавить его
      while nCur <> nil do
        begin
          d += nCur.N;
          LeftDigit(d mod 10);
          d := d div 10;
          nCur := nCur.L;
        end;
      // если в первом числе больше знаков и остался перенос
      while (cCur <> nil) and (d > 0) do
        begin
          d += cCur.N;
          cCur.N := d mod 10;
          d := d div 10;
          cCur := cCur.L;
        end;
      // если ещё остался перенос, то и его добавим
      if d > 0 then
        LeftDigit(d);
        
      Result := Self;
    end;
    
    /// Увеличение числа в 10 раз
    function Mul10 : bNumber;
    begin
      Result := Self;
      
      // проверяем на self=0
      if (Len = 1) and (Left.N = 0) then
        Exit;
        
      RightDigit(0);
    end;
    
    /// Умножение на длинное число
    function Mul(n : bNumber) : bNumber;
    begin
      Result := Self;
      
      // проверяем на self=0
      if (Len = 1) and (Left.N = 0) then
        Exit;
 
      // это таблица умножения с 0 по 9
      var an : array of bNumber;
      SetLength(an, 10);
      an[0] := New bNumber(0);
      for var i := 1 to 9 do
        begin
          an[i] := New bNumber(an[i-1]);
          an[i].Add(Self);
        end;
      
      // исходное число обнуляем
      Left := Right;
      Left.L := nil;
      Left.N := 0;
      Len := 1;
      
      // проверяем на n=0
      if (n.Len = 1) and (n.Left.N = 0) then
        Exit;
      
      // умножаем
      var Cur := n.Left;
      repeat
        Self.Mul10;
        Self.Add(an[Cur.N]);
        Cur := Cur.R;
      until Cur = nil;
    end;
 
    /// Переопределение операций
    class function operator+(a, b : bNumber) : bNumber;
    begin
      Result := New bNumber(a); Result.Add(b);
    end;
 
    class function operator*(a, b : bNumber) : bNumber;
    begin
      Result := New bNumber(a); Result.Mul(b);
    end;
    
    class function operator implicit(n : String) : bNumber;
    begin
      Result := New bNumber(n);
    end;
    
    class function operator explicit(n : bNumber) : String;
    begin
      Result := n.toString;
    end;
 
  end;
  
begin
  var a := New bNumber(123);
  WriteLn('a = ' + a.toString);
  
  var b := New bNumber('12345');
  Write('b = '); b.PrintLn;
  
  WriteLn('сумма: ' + a.toString + ' + ' + b.toString + ' = ' + String(a+b));
  WriteLnFormat('произведение: {0} x {1} = {2}', a, b, a*b);
  
  var b1 := bNumber('12345678901234567890');
  var b2 := '98765432109876543210';
  WriteLn(String(b1*bNumber(b2)));
  
  WriteLn('end.');
end.

Объяснение кода листинга программы

  1. Объявление типа tDigit и его полей N, L и R.
  2. Создание конструктора для класса tDigit.
  3. Объявление методов LeftDigit и RightDigit для класса bNumber.
  4. Создание конструктора для класса bNumber, который создает число из целого числа.
  5. Создание конструктора для класса bNumber, который создает число из строки.
  6. Создание конструктора для класса bNumber, который создает число из другого длинного числа.
  7. Объявление метода toString для класса bNumber.
  8. Объявление метода Print для класса bNumber.
  9. Объявление метода PrintLn для класса bNumber.
  10. Объявление метода Add для класса bNumber.
  11. Объявление метода Mul10 для класса bNumber.
  12. Объявление метода Mul для класса bNumber.
  13. Объявление оператора + для класса bNumber.
  14. Объявление оператора * для класса bNumber.
  15. Объявление оператора implicit для класса bNumber.
  16. Объявление оператора explicit для класса bNumber.
  17. Пример использования методов и операторов класса bNumber.
  18. Создание переменной b1 типа bNumber с текстовым значением '12345678901234567890'.
  19. Создание переменной b2 типа string с текстовым значением '98765432109876543210'.
  20. Пример использования метода Mul для переменной b1 и переменной b2.

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

14   голосов , оценка 3.786 из 5
Похожие ответы