Урок 18. Задача 11.

Урок 18. Задача 11.

Задана последовательность символов, имеющая следующий вид: p1q1p2q2p3...qn–1pn , где pi — число, а qi — знак арифметического действия из набора {+, –, *}. Вычислите значение выражения, предполагая, что действия выполняются согласно правилам арифметики.
Входные данные: На вход программе подается строка указанного вида, состоящая не более чем из 9 чисел, разделенных символами арифметических операций.
Выходные данные: Выведите значение арифметического выражения.
Как решать: Посчитайте результат за одно прочтение строки, без использования массивов (в нашем курсе решение в таком стиле для этой задачки было впервые добавлено участником slavina036).
(условие задачи взято из книги Е. В. Андреевой)

Var i, result, num_mul, vl_I, vl_C :integer;
    s, str, chr :string;
    fl_mul, fl_minus :boolean;

begin
  s := '2*2*1-4-4+4+2*4';
  chr := '';  // знак
  result := 0;  // ответ
  num_mul := 0;  // число из предыдущей итерации
  fl_mul := false;  // флаг умножения
  fl_minus := false;  // флаг для получения отрицательного числа 
  str := '';  // строка с актуальным числом

  for i := 1 to length(s) + 1 do
  begin
    if i = length(s) + 1  then
      s[i] := '+';

    val(s[i], vl_I, vl_C);
    if vl_C = 0 then  // ищет число
      str := str + s[i]
    else
    begin
      chr := s[i];  // находит знак
      val(str, vl_I);
      str := '';

      if fl_mul then  // умножает
      begin
        fl_mul := false;
        vl_I := num_mul * vl_I;
      end
      else
        if fl_minus then  // делает число отрицательным
        begin
          fl_minus := false;
          vl_I := vl_I * (-1);
        end;

      if chr = '*' then
      begin
        fl_mul := true;
        num_mul := vl_I;
      end
      else
      begin
        if chr = '-' then
          fl_minus := true;
        result := result + vl_I;
      end;
    end;
  end;
  write(s, ' = ', result);
  readln();
end.
vedro-compota's picture

Переписать так, чтоб val(s[i], vl_I, vl_C); вызовалось только когда действительно ожидается что там число, и когда уже сформировано, т.е. напр. если выражение:

2+444

-- для '444' операция val() должна быть вызвана 1 раз

_____________
матфак вгу и остальная классика =)

Var i, result, num_mul, vl_I, vl_C :integer;
    s, str, chr :string;
    fl_mul, fl_minus :boolean;
 
begin
  s := '2*2*1-4-4+4+2*4';
  chr := '';  // знак
  result := 0;  // ответ
  num_mul := 0;  // число из предыдущей итерации
  fl_mul := false;  // флаг умножения
  fl_minus := false;  // флаг для получения отрицательного числа 
  str := '';  // строка с актуальным числом
 
  for i := 1 to length(s) + 1 do
  begin
    if i = length(s) + 1  then
      fl_minus := false;
 
    if (s[i] >= '0')  and (s[i] <= '9') then  // ищет число
      str := str + s[i]
    else
    begin
      chr := s[i];  // находит знак
      val(str, vl_I);
      str := '';
 
      if fl_mul then  // умножает
      begin
        fl_mul := false;
        vl_I := num_mul * vl_I;
      end
      else
        if fl_minus then  // делает число отрицательным
        begin
          fl_minus := false;
          vl_I := vl_I * (-1);
        end;
 
      if chr = '*' then
      begin
        fl_mul := true;
        num_mul := vl_I;
      end
      else
      begin
        if chr = '-' then
          fl_minus := true;
        result := result + vl_I;
      end;
    end;
  end;
  write(s, ' = ', result);
  readln();
end.
vedro-compota's picture

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

_____________
матфак вгу и остальная классика =)

Var i, result, remember, number :integer;
    s, str, chr :string;

function result_int(int_1, int_2 :integer; chr :string) :integer;
begin
  if chr = '*' then
    result_int := int_1 * int_2
  else
    if chr = '-' then
      result_int := int_1 - int_2
    else
      result_int := int_1 + int_2;
end;

begin
  s := '-2*2*1*1+0+8-2-2+0-0';
  chr := '';  // знак
  result := 0;  // ответ
  remember := 0;  // число из предыдущей итерации
  str := '';  // строка с актуальным числом

  for i := 1 to length(s) + 1 do
  begin
    if i > length(s) then
      s[i - 1] := s[i - 1];

    if (s[i] >= '0')  and (s[i] <= '9') then  // ищет число
      str := str + s[i]
    else
    begin
      val(str, number);
      str := '';
      result := result_int(remember, number, chr);
      writeln(result);
      chr := '';

      if s[i] = '*' then
      begin
        remember := result;
        chr := '*';
      end
      else
      begin
        if s[i] = '-' then
          chr := '-';
        remember := result;
      end;
    end;
  end;
  write(s, ' = ', result);
  readln();
end.   
В виде функции
Var i, result, remember, number :integer;
    s, str, chr :string;

function result_int(int_1, int_2 :integer; chr :string) :integer;
begin
  if chr = '*' then
    result_int := int_1 * int_2
  else
    if chr = '-' then
      result_int := int_1 - int_2
    else
      result_int := int_1 + int_2;
end;

function calculator(s :string; i :integer) :integer;
begin
  while i < length(s) do
  begin
    if (s[i] >= '0')  and (s[i] <= '9') then  // ищет число
    begin
      str := str + s[i];
      i += 1;
    end
    else
    begin
      val(str, number);
      str := '';
      result := result_int(remember, number, chr);
      chr := '';

      if s[i] = '*' then
      begin
        remember := result;
        chr := '*';
        i += 1;
      end
      else
      begin
        if s[i] = '-' then
          chr := '-';
        i += 1;
        remember := result;
      end;
    end;
  end;
  calculator := result;
end;

begin
  s := '-2*2*1+0+8-2-2*1+0-0';
  i := 1;
  chr := '';  // знак
  result := 0;  // ответ
  remember := 0;  // число из предыдущей итерации
  str := '';  // строка с актуальным числом
  result := calculator(s, i);
  write(s, ' = ', result);
  readln();
end.  
vedro-compota's picture

  1. Проверить работоспособность в целом для примера 1+2*2+1
  2. Функция должна принимать на вход только переменные, которые действительно нужно передавать снаружи, для всего остального есть локальные переменные подпрограммы см. например http://fkn.ktu10.com/?q=node/15820
  3. Убрать обращения к глобальным переменным
  4. Убрать дублирование инкрементирования счетчика позиции в строке, или объяснить почему это не возможно
  5. Дублирование remember := result;
  6. Т.к. стока считается корректной - смысла проверять что за символ операции мы встретили нет:
          if s[i] = '*' then
          begin
            remember := result;
            chr := '*';
            i += 1;
          end
          else
          begin
            if s[i] = '-' then
              chr := '-';
            i += 1;
            remember := result;
          end;
    

_____________
матфак вгу и остальная классика =)

Var i, result, remember, number :integer;
    s, str, chr :string;

function result_int(int_1, int_2 :integer; chr :string) :integer;
begin
  if chr = '*' then
    result_int := int_1 * int_2
  else
    if chr = '-' then
      result_int := int_1 - int_2
    else
      result_int := int_1 + int_2;
end;

function calculator(s :string) :integer;
begin
  chr := '';  // знак
  result := 0;  // ответ
  remember := 0;  // число из предыдущей итерации
  str := '';  // строка с актуальным числом
  while i < length(s) do
  begin
    if (s[i] >= '0')  and (s[i] <= '9') then  // ищет число
      str := str + s[i]
    else
    begin
      val(str, number);
      str := '';
      result := result_int(remember, number, s[i]);
    end;
    i += 1;
  end;
  calculator := result;
end;

begin
  s := '1+2*3+1';
  result := calculator(s);
  write(s, ' = ', result);
  readln();
end.
vedro-compota's picture

0+  1+2+2
0+  1+2*2*2-4+6*4*5+

- обрабатываем умножение

_____________
матфак вгу и остальная классика =)

Var i, j, result, remember, number, multy :integer;
    s, str, chr :string;
    fl :boolean;

function calculator(s :string) :integer;
begin
  j := 1;
  i := 1;
  chr := '+';  // знак
  result := 0;  // ответ
  remember := 0; // число из предыдущей итерации
  multy := 0;
  number := 0;
  fl := false;
  str := '';  // строка с актуальным числом
  while i < length(s) + 2 do
  begin
    if i > length(s) then
    begin
      s[i - j] := s[i - j];
      j += 1;
    end;

    if (s[i] >= '0')  and (s[i] <= '9') then  // ищет число
      str := str + s[i]
    else
    begin
      val(str, number);
      str := '';

      if fl then
      begin
        number := remember * number;
        fl := false;
      end;

      if s[i] = '*' then
      begin
        remember := number;
        fl := true;
      end
      else
      begin
        if chr = '-' then
          result := result - number
        else
          result := result + number;
        chr := s[i];
      end;
      writeln(result, '_res ', chr, '_chr ', remember, '_rem ', number, '_num ', multy, '_mul ', i, '_i ');
    end;
    i += 1;
  end;
  calculator := result;
end;

begin
  s := '-1+3*3+1+1*1*1';
  result := calculator(s);
  write(s, ' = ', result);
  readln();
end.   
vedro-compota's picture

нельзя уходить от декомпозиции в пользу более длинного блока

_____________
матфак вгу и остальная классика =)

Var i, j, result, remember, number, multy :integer;
    s, str, chr :string;
    fl :boolean;



function result_int(int_1, int_2 :integer; chr :string) :integer;
begin
  if chr = '*' then
    result_int := int_1 * int_2
  else
    if chr = '-' then
      result_int := int_1 - int_2
    else
      result_int := int_1 + int_2;
end;

function calculator(s :string) :integer;
begin
  j := 1;
  i := 1;
  chr := '+';  // знак
  result := 0;  // ответ
  remember := 0; // число из предыдущей итерации
  multy := 0;
  number := 0;
  fl := false;
  str := '';  // строка с актуальным числом
  while i < length(s) + 2 do
  begin
    if i > length(s) then
    begin
      s[i - j] := s[i - j];
      j += 1;
    end;

    if (s[i] >= '0')  and (s[i] <= '9') then  // ищет число
    begin
      str := str + s[i];
      writeln(result, '_res ', chr, '_chr ', remember, '_rem ', number, '_num ', multy, '_mul ', i, '_i ');
    end
    else
    begin
      val(str, number);
      str := '';

      if fl then
      begin
        number :=  result_int(remember, number, chr);
        fl := false;
        multy := number;
        chr := s[i];
      end;

      if s[i] = '*' then
      begin
        remember := number;
        fl := true;
      end
      else
        result :=  result_int(result, number, chr);
      chr := s[i];

    end;
    i += 1;
  end;
  calculator := result;
end;

begin
  s := '-1+2*3*1+1';

  result := calculator(s);
  write(s, ' = ', result);
  readln();
end.