Вычисление логических выраженний.

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

ПЕРВАЯ ГРУППА ЗАДАЧ: Вычисление константных (не содержащих переменных) логических выражений.

Задача1. Описать три реализующие основные булевы операции функции:
Function _or(x,y: Char): Char; //дизъюнкция (например, Writeln( _or(‘0’,’1’) ) выводит 1.
Function _and(x,y: Char): Char; //конъюнкция (например, Writeln( _and(‘0’,’1’) ) выводит 0.
Function _not(x: Char): Char; //отрицание (например, Writeln( _and(’1’) ) выводит 0.

Написать главную программу, которая на основе указанных функций вычисляет значение заданной в виде стринга элементарной константной ФБФ любого из следующих трёх видов: ‘a&b’, ‘a|c’, ‘-a’, где a,b - константы ‘0’ или ‘1’, а знаки &, |, - означают конъюнкцию, дизъюнкцию и отрицание, соответственно (в формуле нет переменных, поэтому она называется константной). Например, если входная строка имеет вид ‘1|0’, то результатом должно быть ‘1’.

При этом, программа должна только вводить исходную строку и выводить результат её вычисления. А для самого вычисления определить функцию:
function LogCalc0(S:String):Char, где S-исходная формула.
Например Writeln( LogCalc0(‘1|0’)) выведет 1.

Задача2. Расширить условие предыдущей задачи, разрешив входные строки в виде константных логических формул произвольной (в пределах стринга) длины. Скобки внутри строки не используются, а порядок операций определяется с учётом их приоритетов (отриц-конъюн-дизъюн).

Эту версию логического калькулятора оформить как функцию: function LogCalc1(S:String):Char.

Например Writeln( LogCalc1( ‘-0|-0&0’ ) ) выведет 1.

Задача3. Расширить условие предыдущей задачи, разрешив использование внутри логических выражений круглых скобок (произвольной «правильной» структуры вложенностей).

Соответствующую версию калькулятора назвать LogCalc2.

Например Writeln( LogCalc2( ‘(-0|-0)&0’ ) ) выведет 0.

ВТОРАЯ ГРУППА ЗАДАЧ: Вычисление логических выражений с переменными.

Будем теперь считать, что заданное логическое выражение (формула булевой функции) содержит в качестве операндов не только константы (0,1), но также, возможно, переменные, обозначенные латинскими малыми буквами. Одна и та же буква может входить в формулу многократно.
Например, логической формулой теперь является стринг: 'a&1&((-b|a)&z)'

Задача4. Описать и протестировать процедуру procedure vars(fbf:String; var vlst: String);, которая по заданной формуле булевской функции fbf формирует упорядоченный список входящих в неё переменных vlst.

Задача5. Описать и протестировать процедуру procedure inargs(vlst: String; var arglst:String);, которая по заданному списку переменных vlst вводит список соответствующих им двоичных значений arglst. При этом, элементы списка arglist должны запрашиваться с клавиатуры, как значения соответствующих переменных из списка vlst.

Например, вызов процедуры inargs('xy',s) должен привести к выводу подсказки:
x=
Затем, после ввода, например 0, должно последовать:
y=
После ввода на этот раз, например, 1, процедура должна завершиться, сформировав результат s='01' .

Задача6. Описать и протестировать процедуру procedure toConst(var fbf: String; vlst: String; arglst:String);, которая по заданной формуле fbf, заданному списку её переменных vlst и списку значений этих переменных arglst заменяет переменные в формуле их значениями, формируя, тем самым, константную логическую формулу.

Например, в результате выполнения:
s:= 'x&(1|-b&x';
toConst( s, 'xb','10') );
получим s= '1&(1|-0&1'

Задача7. Используя выше приведённые подпрограммы, "собрать" из них логический калькулятор - функцию function LogCalc(fbf: String), которая вычисляет значение логического выражения fbf, запрашивая при необходимости значения содержащихся в ней переменных.

ФИНАЛЬНЫЙ ШАГ:

Задача8. Используя необходимые модули из набора задач 1-7 построить процедуру:
procedure TabIst(fbf:String); которая строит таблицу истинности для заданной формулы fbf.

Подсказка. Для генерации в естественном порядке всех двоичных наборов заданной длины (по одному набору на каждую строку), возможно, будет полезно построить 2-3 простенькие подпрограммки. В частности подпрограмму procedure next(var args:String), которая на стринге имитирует прибавление единицы к числу, представленному своим двоичным значением (т.е. переход от одного "двоичного набора" к следующему).
И еще. Здесь наверное удобней воспользоваться top-down подходом к разработки программ - сначала напишите код нужной вам процедуры TabIst, используя как существующие, так и не существующие пока, но желательные для вас подпрограммы, а уж потом, займитесь тем, чего ещё нет.

Асхад

Строка 6 Вашей программы 4 (for x in letters do begin //Пробегаем переменной x по все буквам)
не может компилироваться НИ В КАКОЙ ВЕРСИИ Паскаля.

Чтобы убедиться в этом, попробуйте у себя свой код хотя бы с пустым телом:

  1.  
  2. const letters =['a'..'z']; //Ìíîæåñòâî áóêâ.
  3. procedure vars(fbf: string; var vlst: string);
  4.   var x: char;
  5. begin
  6.   vlst:=''; //Ïóñòàÿ ñòðîêà.  ïîñëåäñòâèè â íå¸ áóäåì êèäàòü áóêâû.
  7.   for x in letters do begin //Ïðîáåãàåì ïåðåìåííîé x ïî âñå áóêâàì.
  8.     if Pos(x,fbf) > 0 then vlst:=vlst+x
  9.   end; //for
  10. end
  11. begin
  12.   { TODO -oUser -cConsole Main : Insert code here }
  13. end.

Ваши неадекватные реакции на указываемые Вам ошибки, в очередной раз ставя Вас в неловкое (мягко говоря) положение, не оставляют у меня надежд хоть на какой-нибудь конструктивный с Вами диалог (прописная буква "Я" в Ваших текстах не так уж безобидна, как показалось вначале).
И, пожалуйста, не упоминайте по всякому поводу "Studio ...", он-то как раз, ни при чём.

Должок.

Построив логический калькулятор, мы всё же не решили ещё одной важной задачи - не написали процедуры, умеющей строить таблицу истинности для заданной ФБФ. Вот я и предлагаю сделать этот финальный в данном разделе шаг. См. задачу8.

Задача 8

  1. function stepen(x,n:byte):word; // данная функция необходима чтобы узнать количество строк в нашей таблице
  2. begin                      //  количество строк определяется по формуле M=N^2 , где N количество аргументов
  3.  if n=0 then stepen:=1
  4.  else stepen:=x*stepen(x,n-1);
  5. end;

  1. procedure buildup(s:string;var value:string);  // данная процедура создает первый набор (состоит из '0' )
  2.  var i:byte;
  3. begin
  4.  value:='';
  5.  for i:=1 to length(s) do value:=value+'0';
  6. end;

  1.  procedure next(var args:string); //процедура перехода от одного "двоичного набора" к следующему
  2.   var a,b:string;
  3.     i:byte;
  4.   begin
  5.   b:=args; //здесь хранится старый набор
  6.   a:='';
  7.   for i:=1 to length(args) do a:=a+'1';
  8.   repeat
  9.     i:=length(args);
  10.     while (b[i]<>'0') do begin  //пока b[i]<>'0'
  11.       b[i]:='0';   //присваиваем '0'
  12.       dec(i);  // уменьшаем индекс
  13.     end;
  14.     b[i]:='1'; // присваиваем '1'
  15.     args:=b; //новый набор
  16.     break; //выходим из цикла
  17.  until(a=b);
  18. end;

  1. procedure gap(var s:string);  //формируем список аргументов с пробелами
  2.  var i:byte;
  3.     temp:string;
  4. begin
  5.  temp:='';
  6.  for i:=1 to Length(s) do begin
  7.    temp:=temp+s[i]+' ';
  8.  end;//for
  9.  s:=temp;
  10. end;

  1. procedure head; //заголовок таблицы
  2. begin
  3.   writeln('arg|rez');
  4.   writeln('---------');
  5. end;

  1. procedure TabIst(fbf:string);  //процедура, которая строит таблицу истинности для заданной формулы fbf.
  2.  var  i,amount:byte;
  3.       vl,row,args,cfbf:string;
  4. begin
  5.  row:='';
  6.  cfbf:=fbf; // будем работать с копией fbf
  7.  vars(fbf,vl);//формируем список переменных   
  8.  amount:=stepen(2,length(vl)); //вычисляем  количество строк
  9.  i:=0;
  10.  buildup(vl,args); // в args записываем первый набор(состоит из '0')
  11.  head; // заголовок таблицы
  12.  while i<>amount do begin // пока i<>amount  ...
  13.   if i<>0 then next(args); //если i=0 то мы не вызываем next что бы не изменить первый набор
  14.   toConst(cfbf,vl,args); // замена переменных их значениями(наборами)
  15.   row:=args;
  16.   gap(row); //формируем список аргументов с пробелами
  17.   writeln(row,' ',LogCalc2(cfbf)); // строка таблицы (в LogCalc2(cfbf) вычисляется значение на каждом  наборе args)
  18.   inc(i); // увеличиваем индекс
  19.   cfbf:=fbf; // cfbf:=fbf
  20.  end;//while
  21. end;

Никита - задача8.

На пользовательском уровне вроде бы всё так, кроме странного заголовка таблицы. А вот реализация, на мой взгляд, должна быть проще. Не зря я предложил начать с главного модуля, который я оформил бы, например, так:

  1. procedure TabIst(fbf: String);
  2.   Var vl, args, last, fbf1: String;
  3. Begin
  4.   vars(fbf, vl);  // создали список переменных
  5.   WriteLn(vl, ' F'); // напечатали заголовок таблицы
  6.   makeFstLst(vl, args, last); // создали первый (из '0') и последний (из '1') наборы
  7.   Repeat
  8.       fbf1:=fbf;  //взяли исходную формулу
  9.       toConst(fbf1, vl, args); // заменили в ней переменные константами
  10.       Writeln(args, ' ', LogCalc2(fbf1)); //вывели строку таблицы
  11.       If args=last then break; //если строка последняя, закончили, иначе ...
  12.       next(args); // перешли к следующему набору значений аргументов
  13.  until false; //выход только по break
  14. End;  

При желании, можно было бы использовать Вашу gap (и для заголовка тоже). Реализация makeFstLst очевидна, а вот next можно сделать проще, чем у Вас.

P.s. Ваше письмо я не получил. Не ошиблись ли адресом? (tlyusten@gmail.com)

нет

не ошибся, сейчас попробую ещё раз отправить

А вот что касается заголовка

А вот что касается заголовка таблицы, если добавить вот такую процедуру

  1. procedure zag(s:string);
  2.    var i:byte;
  3.    k,y:string;
  4. begin
  5.   k:='';//строка, от которой будет зависеть, где будет находиться rez
  6.   y:='';
  7.   for i:=1 to length(s) do begin
  8.      k:=k+' ';
  9.   end;
  10.   for i:=1 to Length('arg|rez'+k) do begin
  11.       y:=y+'-';
  12.   end;
  13.   writeln('arg',k,'|rez');
  14.   writeln(y);
  15. end;

Валерий Шахамболетович,

Валерий Шахамболетович, извините,может я что-то упустила, но что за процедура makeFstLst?

Виктория

1. Вы (как впрочем и Никита) забыли, что в заголовке нормальной таблицы истинности прописаны имена переменных и имя ф-ции. Мой оператор WriteLn(vl, ' F') всё это (как и длину заголовка) обеспечивает.
2. Я же указал в комментарии к makeFstLst что она формирует значения двух переменных - args из одних нулей (первая строка значений аргументов) и last из одних единиц (последняя строка). Да и название процедуры говорит о том же!

Спасибо, впредь буду

Спасибо, впредь буду внимательнее:-)

Валерий Шахамболетович

Я заново Вам отправил задачи 5м-7м (наверное, какие-то неполадки с почтой)

Next для наших целей

Next для наших целей предлагаю таким:

  1. procedure next(args: String);
  2.   Var i: Byte;
  3. Begin
  4.     i:=Length(args);
  5.     While args[i] <>'0' do Begin
  6.            args[i]:='0';  Dec(i);
  7.     End;
  8.     args[i]:='1';
  9. End;

а вместо: amount:=stepen(2,length(vl)); //вычисляем  количество строк в решении Никиты, думаю, будет лучше обойтись и вовсе без подпрограммы:  amaunt:= 1 shl length(vl)
Последняя почта, Никита, у меня от 2 марта. Не переживайте, с завтрашнего дня можете слать как обычно на сайт по одному: задача - решение.

Ок

ну конечно, сдвиг влево удобен для быстрого умножения на 2 (как то я об этом сразу не подумал )