Задача: На плоскости координатами своих вершин задан треугольник. Определить, к какому типу он принадлежит (остро- , тупо- или прямоугольный)
Const
eps = 10E-5;
{
Поскольку в стандартной библиотеке Паскаля функция вычисления арккосинуса
отсутствует, пишем ее самостоятельно ...
}
Function ArcCos(X: Double): Double;
Begin
If abs(X) < eps Then arccos := Pi / 2
Else
arccos := ArcTan(Sqrt(1 - Sqr(X)) / X) + Pi * Byte(X < 0);
End;
Type
{ Структура для хранения координат X, Y точки }
Point = Record
X, Y: double;
End;
Const
{ Переменная для хранения признака того, что один из углов треугольника - прямой ... }
is90: Boolean = False;
{
Процедура, запрашивающая у пользователя ввод координат X и Y определенной точки,
и возвращающая эту точку через Var-параметр...
}
Procedure GetCoord(Const s: string; Var P: Point);
Begin
WriteLn('Point ' + s);
Write('X = '); ReadLn(P.X);
Write('Y = '); ReadLn(P.Y);
End;
{
Функция для определения расстояния между двумя точками ...
(Зачем нужен Var-параметр dist - см. комментарии после программы)
}
Function GetDist(Var dist: Double; pA, pB: Point): Double;
Begin
dist := Sqrt(Sqr(pA.X - pB.X) + Sqr(pA.Y - pB.Y));
GetDist := dist;
End;
{
Функция, возвращающая угол (в градусах !!!) между двумя сторонами
треугольника, вычисленный из формулы теоремы косинусов
}
Function Angle(A, B, C: Double): Double;
Var value: Double;
begin
Value := ArcCos((Sqr(A) + Sqr(B) - Sqr(C)) / (2 * A * B)) * (180 / Pi);
If Abs(value - 90) < eps Then is90 := True;
Angle := value;
End;
Var
{
Переменные для хранения вершин треугольника
}
pA, pB, pC: Point;
{
Длины сторон треугольника:
A - длина стороны AB;
B - длина стороны BC;
C - длина стороны AC;
}
A, B, C: double;
{
Углы треугольника:
alpha - угол между AC и BC (противолежит AB)
beta - угол между AB и AC (противолежит BC)
gamma - угол между AB и BC (противолежит AC)
}
alpha, beta, gamma: double;
begin
{
Получаем координаты вершин треугольника
}
GetCoord('A', pA);
GetCoord('B', pB);
GetCoord('C', pC);
{
Вычисляем все углы в заданном треугольнике
}
alpha := Angle(
GetDist(B, pB, pC),
GetDist(C, pA, pC),
GetDist(A, pA, pB)
);
beta := Angle(A, C, B);
gamma := Angle(A, B, C);
{
И по вычисленным углам делаем вывод о том,
является ли данный треугольник остро- , тупо- или прямоугольным
}
If is90 Then WriteLn('Прямоугольный')
Else
If (alpha < 90) and (beta < 90) and (gamma < 90) then WriteLn('Остроугольный')
Else
If (alpha > 90) or (beta > 90) or (gamma > 90) then WriteLn('Тупоугольный')
end.
А теперь немного о том, зачем в функции GetDist понадобился еще один параметр...... A := GetDist(pA, pB); B := GetDist(pB, pC); C := GetDist(pA, pC); alpha := Angle(B, C, A); beta := Angle(A, C, B); gamma := Angle(A, B, C); ...Введением же одного дополнительного параметра я добился того, что одновременно с вычислением всех длин сторон найденные значения подставляются в первый вызов функции Angle (получилось нечто вроде C-шного:
alpha = Angle(
(B = GetDist(pB, pC)),
(C = GetDist(pA, pC)),
(A = GetDist(pA, pB))
);
, только средствами Паскаля. Иногда это действительно удобно)Задача: Определение принадлежности точки к многоугольнику
Ниже приведено простое решение проблемы, часто встречающейся в компьютерной графике, определение, лежит ли
точка (x,y) внутри или снаружи двумерного многоугольника. В частности, это может быть необходимо в задачах определяющих
пересечение нескольких полигонов.
Будем считать, что многоугольник состоит из N вершин (xi, yi) где i изменяется от 0 до N-1.
Последняя вершина (xN,yN) считается равной первой вершине (x0,y0),
то есть, многоугольник замкнут. Для того, чтобы определить положение точки (xp,yp),
представим горизонтельный луч, выходящий из (xp,yp), и уходящий вправо. Если количество
пересечений этого луча с отрезками, формирующими многоугольник, является четным, то точка лежит вне многоугольника.
Если же число пересечений нечетно, то точка (xp,yp) лежит внутри многоугольника. См. рисунок:


Uses Crt;
Function min(a, b: Double): Double;
Begin
min := a;
If b < a Then min := b;
End;
Function max(a, b: Double): Double;
Begin
max := a;
If b > a Then max := b;
End;
{
Структура, описываюшая тип точки
}
Type
Point = Record
x, y: Double;
End;
Function InsidePolygon(Var polygon: Array Of Point;
Const n: Integer; p: Point): Boolean;
Var
i, counter: Integer;
xinters : Double;
p1, p2 : Point;
Begin
counter := 0;
p1 := polygon[0];
For i := 1 To n Do Begin
p2 := polygon[i mod n];
If p.y > min(p1.y, p2.y) Then Begin
If p.y <= max(p1.y, p2.y) Then Begin
If p.x <= max(p1.x, p2.x) Then Begin
If p1.y <> p2.y Then Begin
xInters := (p.y - p1.y)*(p2.x - p1.x) / (p2.y-p1.y) + p1.x;
If (p1.x = p2.x) or (p.x <= xInters) Then Inc(counter);
End;
End;
End;
End;
p1 := p2;
End;
If (counter mod 2) = 0 Then InsidePolygon := False
Else InsidePolygon := True;
End;
Const
{ Максимально возможное количество вершин полигона }
maxPoints = 24;
Var
P : Point; { Проверяемая точка }
Poly: Array[0 .. 24] of Point; { Массив вершин многоугольника }
{
Функция ввода данных (возвращает количество точек, образующих полигон)
Внимание !!! Порядок ввода точек, образующих многоугольник - против часовой стрелки...
}
Function EnterData: Integer;
Var
i, count: integer;
Begin
Write('Enter poly`s vertex number: '); ReadLn(count);
For i := 0 To Pred(count) Do Begin
Write('X[',i,']: '); ReadLn(Poly[i].x);
Write('Y[',i,']: '); ReadLn(Poly[i].y);
End;
WriteLn;
Write('Point X: '); ReadLn(P.x);
Write('Point Y: '); ReadLn(P.y);
End;
Var
count: Integer; { Количество точек в многоугольнике }
Begin
ClrScr;
count := EnterData;
WriteLn;
If InsidePolygon(Poly, count, P) Then
WriteLn('Точка внутри многоугольника')
Else
WriteLn('Точка ВНЕ многоугольника');
ReadLn;
End.
Задача:
В строке данных записаны 30 чисел от 1 до 8, показывающих, в каком направлении дул ветер в соответствующий день месяца
(1-северный, 2-северо-восточный, 3-восточный, 4-юго-воточный, 5 южный, 6-юго-западный, 7-западный, 8-северо-западный).
Вывести на экран “розу ветров” - многоугольник, вершинами которого лежат на 8-лучах, выходящих из общего центра с равным углами,
расстояния от вершины до этого центра пропорционально дней месяца, в который дул соответствующий ветер.
Для отображения результата данной задачи идеально подходит полярная система координат: лучи выходят из общего центра, на них
нужно откладывать расстояние, пропорциональное количеству... неважно чего, главное - что на них...
Вот как решается данная задача (есть вопросы по решению - задаем сюда: Форум "Интересные задачи для программистов"):
uses graph;
type
Dir = (
E, NE, N, NW, W, SW, S, SE
);
arrType = array[Dir] of integer;
const
titles: array[Dir] of string = (
'E', 'NE', 'N', 'NW', 'W', 'SW', 'S', 'SE'
);
start = ord(low(Dir));
finish = ord(high(dir));
amount = finish - start + 1;
sector = (360 div amount) * (Pi / 180);
function read_data(var arr: arrType): integer;
var
i, X, max: integer;
ix: Dir;
begin
for ix := low(Dir) to
high(Dir) do arr[ix] := 0;
for i := 1 to 30 do begin
read(X);
if X <= 3 then X := 4 - X else X := 12 - X;
inc(arr[Dir(pred(X))]);
end;
max := 0;
for ix := low(Dir) to high(Dir) do
if arr[ix] > max then max := arr[ix];
read_data := max;
readln;
end;
var
center_x, center_y: integer;
const
mult = 20;
function get_x(r, phi: real): integer;
begin
get_x := center_x + trunc(mult * r * cos(phi));
end;
function get_y(r, phi: real): integer;
begin
get_y := center_y - trunc(mult * r * sin(phi));
end;
procedure line_polar(phi_st, r_st, phi_fn, r_fn: real);
begin
line(
get_x(r_st, phi_st), get_y(r_st, phi_st),
get_x(r_fn, phi_fn), get_y(r_fn, phi_fn)
);
end;
procedure text_polar(phi, r: real; const T: string);
begin
outtextxy(
get_x(r, phi), get_y(r, phi), T
);
end;
procedure circle_polar(phi, r: real; radius: integer);
begin
circle(
get_x(r, phi), get_y(r, phi), mult * radius
);
end;
var
arr: arrType;
i, j,
max_val: integer;
{
Это - только для того, чтобы программа запускалась как на Турбо, так и на Free-Паскале...
}
gDriver, gMode, errCode:
{$ifdef FPC}
smallint
{$else}
integer
{$endif}
;
begin
max_val := read_data(arr);
initgraph(gDriver, gMode, '');
errCode := graphresult;
if errCode <> grOk then begin
writeln('error: ', grapherrormsg(errCode));
readln; halt(100);
end;
center_x := getmaxx div 2;
center_y := getmaxy div 2;
for i := start to finish do begin
setcolor(white);
line_polar(0, 0, i * sector, 10);
text_polar(i * sector, 11, titles[Dir(i)]);
if i = finish then j := start else j := i + 1;
setcolor(red);
line_polar(i * sector, arr[Dir(i)], j * sector, arr[Dir(j)])
end;
setcolor(darkgray);
for i := 1 to max_val do
circle_polar(0, 0, i);
readln;
closegraph;
end.После компиляции и запуска этой программы вводим массив чисел (я вводил такой:
1 2 3 4 5 6 7 8 1 2 2 2 2 3 4 5 5 4 2 6 5 5 3 4 7 1 1 2 3 4), получаем вот такую "Розу ветров" (нажмите на картинку для ее увеличения):
Задача: Написание программы для создания и проведения тестов.
Программа должна уметь работать с вопросами нескольких типов:
{ максимально возможное количество ответов на вопрос ... }
const
max_answers = 10;
type
{ здесь описываем 5 типов ответов, каждый из них будет обрабатываться по-своему }
QuestType = (ans1, ans2, ans3, ans4, ans5);
{ промежуточная структура, для хранения соответствий между двумя вариантами - для 4-го типа }
TS = record
first, second: integer;
end;
{ это - сама запись с вариантами... }
TTest = record
quest: string[50];
ans_count: 0 .. max_answers;
answers: array[1 .. max_answers] of string[50];
case qType: QuestType of
ans1: (
good_ans1: string[50];
);
ans2: (
good_ans2: integer;
);
ans3: (
good_count3: 1 .. max_answers;
good_ans3: array[1 .. max_answers] of integer;
);
ans4: (
good_count4: 0 .. max_answers;
good_ans4: array[1 .. max_answers] of TS;
);
ans5: (
good_ans5: array[1 .. max_answers] of integer;
);
end;
Основная сложность возникает при обработке первого типа вопросов: как заставить программу понимать, что и "Л. Н. Толстой" и "Лев Толстой",
и даже "Толстой Л. Н." являются правильными ответами.{
Тип данных для разбиения строки на слова
}
type
TWordStr = string[100];
TDelimiter = set of Char;
PTItem = ^TItem;
TItem = record
Data: TWordStr;
next: PTItem;
end;
TWordList = record
first, last: PTItem;
end;
{
Процедура, помещающее очередное найденное слово в список
}
procedure InsertWord(var L: TWordList; s: string);
var p: PTItem;
begin
New(p);
p^.Data := s;
p^.next := nil;
if L.first = nil then L.first := p
else L.last^.next := p;
L.last := p
end;
{
Собственно процедура разбиения на слова
}
function GetWords(s: string; var L: TWordList; delimiters: TDelimiter): Byte;
var i, p: Byte;
begin
for i := 1 to Length(s) do
if s[i] In delimiters then s[i] := #32;
repeat
p := Pos(' ', s);
if p > 0 then Delete(s, p, 1)
until p = 0;
if s[1] = ' ' then Delete(s, 1, 1);
if s[Length(s)] = ' ' then Delete(s, Length(s), 1);
i := 0;
repeat
p := Pos(' ', s); Inc(i);
if p > 0 then begin
InsertWord(L, Copy(s, 1, Pred(p)));
Delete(s, 1, p)
end
else InsertWord(L, s)
until p = 0;
GetWords := i
end;
const
{ Максимально допустимое число ответов на вопрос }
max_answers = 10;
type
{ Типы вопросов - выделены в отдельное перечисление для структуризации программы }
QuestType = (ans1, ans2, ans3, ans4, ans5);
{ Тип - "пара значений", для вопросов 4-ой группы }
TS = record
first, second: integer;
end;
{ Запись с вариантами - основная структура, используемая в программе }
TTest = record
{ Сам вопрос, на который предстоит ответить тестируемому }
quest: string[50];
{ Количество вариантов ответа на вопрос }
ans_count: 0 .. max_answers;
{ Собственно, варианты ответа на вопрос }
answers: array[1 .. max_answers] of string[50];
case qType: QuestType of
{ тип №1: непосредственный ввод - Храним шаблонную строку ответа }
ans1: (
good_ans1: string[50];
);
{
тип №2: один правильный из нескольких.
Храним индекс правильного ответа
}
ans2: (
good_ans2: integer;
);
{
тип №3: несколько правильных из нескольких.
Храним массив индексов правильных ответов и их число
}
ans3: (
good_count3: 0 .. max_answers;
good_ans3: array[1 .. max_answers] of integer;
);
{
тип №4: вопросы на соответствие.
Храним массив правильных соответствий индексов
}
ans4: (
good_count4: 1 .. max_answers;
good_ans4: array[1 .. max_answers] of TS;
);
{
тип №5: вопросы на сортировку.
Храним индексы в правильно отсортированном виде
}
ans5: (
good_ans5: array[1 .. max_answers] of integer;
);
end;
{ Заодно описываем и тип файла для хранения подобных записей }
TestFile = file of TTest;
const
{ сообщения для пользователя - для разгрузки текста программы выделены в отдельный массив }
msg: array[QuestType] of string = (
'type #1 - enter the answer: ',
'type #2 - enter the good answer index: ',
'type #3 - enter the good answer index: ',
'type #4 - enter the pairs (first - second): ',
'type #5 - enter the good-sorted indexes: '
);
{
Процедура, запрашивающая у составителя теста вопрос, и заполняющая запись R
всеми данными, необходимыми для правильной обработки ответа на него
}
procedure get_quest(var R: TTest);
{
Вспомогательная функция - получение от пользователя целого числа в заданном интервале
}
function get_integer(const title: string;
range_start, range_finish: integer): integer;
var X: integer;
begin
write(title + '[', range_start, ' .. ', range_finish, '] ');
repeat
readln(X);
until (X >= range_start) and (X <= range_finish);
get_integer := X;
end;
var
i, X: integer;
begin
{ Для любого типа вопросов небоходимо ввести сам вопрос }
write('question: '); readln(R.quest);
{ Теперь запросим у составителя, какой тип у этого вопроса и приведем его к QuestType }
R.qType := QuestType(get_integer('test', 1, 5) - 1);
{ В зависимости от того, к какому типу относится вопрос, его обработка осуществляется по-разному }
case R.qType of
{ тип №1 - количество правильных ответов не нужно, вводится только шаблонный ответ }
ans1:
begin
R.ans_count := 0;
write(msg[ans1]); readln(R.good_ans1);
end;
{ Все остальные типы: запрашивается количество вариантов ответа, и затем - сами варианты }
ans2 .. ans5:
begin
R.ans_count := get_integer('answers count', 1, max_answers);
for i := 1 to R.ans_count do begin
write('answer #', i:2, '':2); readln(R.answers[i]);
end;
{
Запрос правильных ответов необходим только для этих типов вопросов,
но не для первого, поэтому информационная строка печатается здесь,
а не в основном теле процедуры
}
writeln('good answers:');
end;
end; { Case }
{
Теперь переходим ко вводу правильных ответов.
Также в зависимости от выбранного типа вопроса
}
case R.qType of
{ Тип №2: вводим один индекс правильного ответа }
ans2:
begin
R.good_ans2 := get_integer(msg[ans2], 1, R.ans_count);
end;
{ Тип №3: вводим несколько (пока не будет введен 0) индексов правильных ответов }
ans3:
begin
R.good_count3 := 0;
i := 1;
repeat
X := get_integer(msg[ans3] + ' (0 to finish) ', 0, R.ans_count);
{ Что-то было введено, кроме 0 - дописать это в массив ответов }
if X <> 0 then begin
R.good_ans3[i] := X;
inc(R.good_count3);
inc(i);
end;
until X = 0; { Ввели 0 - надо выходить из цикла }
end;
{ Тип №4: ввод пар соответствий }
ans4:
begin
write(msg[ans4]);
for i := 1 to R.ans_count do begin
R.good_ans4[i].first := get_integer('first', 1, R.ans_count);
R.good_ans4[i].second := get_integer('second', 1, R.ans_count);
end;
end;
{ Тип №5: ввод правильно отсортированной последовательности индексов }
ans5:
begin
write(msg[ans5]);
for i := 1 to R.ans_count do begin
write('will be #', i);
R.good_ans5[i] := get_integer('', 1, R.ans_count);
end;
end;
end; { Case }
end;
{
Функция получает из основной программы структуру R с вопросом, прочитанную из файла,
задает пользователю записанный в структуре вопрос, в соответствии с типом вопроса
запрашивает ответ.
Возвращает True в случае, если ответ совпадает с записанным в R; иначе возвращает False
}
function get_answer(const R: TTest): boolean;
{
Дополнительная процедура: вывод на экран всех вариантов ответа на вопрос
}
procedure print_options;
var i: integer;
begin
for i := 1 to R.ans_count do begin
write(i:2, ') ', R.answers[i] + ' ');
end;
end;
var
{ Для типа №1 }
s: string;
L: TWordList;
p: ptitem;
count, positive, negative: integer;
{ Для типа №2 }
i, choice: integer;
{ Для типа №4 }
pair: TS;
j: integer;
begin
{ Вывод сообщения о типе вопроса, и самого текста вопроса }
writeln(msg[R.qType]);
writeln(R.quest);
{ Обработка будет различной в зависимости от типа }
case R.qType of
{
Тип №1: запрашваем у отвечающего строку, разбиваем ее на слова,
и проверяем наличие каждого слова в шаблонной строке, хранящейся в R...
Если число совпадений больше числа НЕсовпадений, то считаем ответ правильным
}
ans1:
begin
readln(s);
L.first := nil;
count := GetWords(s, L, [#32]);
{ Начинаем проход по списку слов }
p := L.first;
positive := 0; negative := 0;
while p <> nil do begin
if pos(p^.Data, R.good_ans1) > 0 then inc(positive)
else inc(negative);
p := p^.next;
end;
get_answer := (positive > negative);
end;
{
Тип №2: выводим варианты ответов, и запрашиваем ввод
одного индекса. Если он совпадает с тем, что хранится в R
как правильный, то ответ засчитывается, иначе - нет
}
ans2:
begin
print_options;
writeln;
write('your choice: '); readln(choice);
get_answer := (choice = R.good_ans2);
end;
{
Тип №3: Выводим варианты ответов, и запрашиваем ввод одного индекса.
После чего проверяем, содержится ли он в массиве индексов, помеченных
как правильные (R.good_ans3). Если да - ответ засчитывается
}
ans3:
begin
print_options;
writeln;
write('your choice: '); readln(choice);
get_answer := false;
for i := 1 to R.good_count3 do
if choice = R.good_ans3[i] then get_answer := true;
end;
{
Тип №4: Вывод вариантов ответов и запрос пользователю:
"введи правильные соответствия между элементами первого
и второго столбцов". Если в массиве правильных ответов содержатся
ВСЕ такие же соответствия (причем в любой последовательности,
порядок не важен) - то ответ засчитывается.
}
ans4:
begin
print_options;
writeln;
writeln('answer:');
count := 0;
for i := 1 to R.ans_count do begin
write('C1) '); readln(pair.first);
write('C2) '); readln(pair.second);
for j := 1 to R.ans_count do begin
if
(R.good_ans4[j].first = pair.first) and
(R.good_ans4[j].second = pair.second)
then inc(count);
end;
end;
get_answer := (count = R.ans_count);
end;
{
Тип №5: выводим варианты ответа, и запрашиваем ввод индексов
в правильном порядке. Если ВСЕ введенные индексы совпадают с
соответствующими элементами массива правильных индексов,
то ответ засчитывается
}
ans5:
begin
print_options;
writeln;
writeln('answer (sorted index array)');
get_answer := true;
for i := 1 to R.ans_count do begin
write('-> '); readln(choice);
if choice <> R.good_ans5[i] then get_answer := false;
end;
end;
end; { Case }
end;
var
Rec: TTest;
F: TestFile;
i, n: integer;
b: boolean;
begin
assign(F, 'quest.dat');
{$i-}
reset(F);
{$i+}
if ioResult <> 0 then begin
rewrite(F);
write('questions to enter: '); readln(n);
for i := 1 to n do begin
get_quest(Rec);
write(F, Rec);
end;
reset(F);
end
else begin
while not eof(F) do begin
read(F, Rec);
b := get_answer(Rec);
writeln('result = ', b);
end;
end;
close(F);
end.
"Звездное небо" (ООП-реализация):
Скачать программу можно отсюда:
starf.rar
Новогодняя елка + снегопад (версия для FPC начиная с 2.2.0):

Скачать программу можно отсюда:
elka_fpc.zip
Решение уравнений различных степеней:
Очень часто при решении задач необходимо находить корни уравнений различных порядков (квадратных, кубических и т.д.)
Вместо того, чтобы писать свое решение этой задачи, можно воспользоваться функциями, которые содержатся в присоединенном
модуле Equation:
Function solveQuadratic(Var x, y: Array Of Double): Byte;Решение квадратного уравнения вида: x[0] * x[sup]2[/sup] + x[1] * x + x[2] = 0
{$n+}
Uses Equation;
Const
ax: Array[0 .. 2] Of Double =
(24, -50, 25 );
Var
ay: array[0 .. 2] Of Float;
roots, i: Integer;
Begin
roots := solveQuadratic(ax, ay);
Writeln( 'number of roots = ', roots );
For i := 0 To Pred(roots) Do
WriteLn( 'root #', i + 1, ' = ', ay[ i ] :10 :5 );
End.
Function solveCubic(Var x, y: Array Of Double): Byte;Решение кубического уравнения: x[0] * x[sup]3[/sup] + x[1] * x[sup]2[/sup] + x[2] * x + x[3] = 0
{$n+}
Uses Equation;
Const
ax: Array[0 .. 3] Of Float =
(1, 0, -9, 4 );
Var
ay: array[0 .. 3] Of Float;
roots, i: Integer;
Begin
roots := solveCubic(ax, ay);
Writeln( 'number of roots = ', roots );
For i := 0 To Pred(roots) Do
WriteLn( 'root #', i + 1, ' = ', ay[ i ] :10 :5 );
End.
Function solveQuarticAlgebra(Var x, results: Array Of Double): Byte;
Function solveQuarticVieta(Var x, results: Array Of Double): Byte;
Function PolySolve(Const order: Integer;
Var coeffs, roots: Array Of Double): Integer;
, позволяющая решать алгебраические уравнения практически любого порядка (порядок задается константой maxOrder,
и изначально установлен равным 12) при помощи последовательности Штурма.{$n+}
Uses Equation;
Const
Order = 4;
coeffs: Array[0 .. Order] Of Double = (
1, 0, -25, 60, -36
);
Var
roots: array[0 .. maxOrder] Of Double;
nroots, i: Integer;
begin
WriteLn('Vieta method :');
nroots := solveQuarticVieta(coeffs, roots);
{ nroots := solveQuarticAlgebra(coeffs, roots); }
Writeln( 'number of roots = ', nroots );
For i := 0 To Pred(nroots) Do
WriteLn( 'root #', i + 1, ' = ', roots[ i ] :7 :4 );
WriteLn;
WriteLn('Sturm sequence method :');
nroots := PolySolve(Order, coeffs, roots);
If nroots = 0 Then Begin
WriteLn('solve: no real roots'); Halt(0)
End
Else Begin
WriteLn(nroots, ' distinct real root(s) for x: ');
For i := 0 To Pred(nroots) Do
WriteLn('root #', i + 1, ' = ', roots[ i ] :7 :4);
End;
end.
Сам модуль можно взять здесь: equation.pasЗадача: Построить таблицу истинности логического выражения.
{
Функция, переводящая десятичное число в другую систему счисления
}
function fromdec(n, radix: longint): string;
var s: string;
const
digit: string[16] = '0123456789ABCDEF';
begin
s := '';
repeat
s := digit[(n mod radix) + 1] + s;
n := n div radix;
until n = 0;
while length(s) < 2 do s := '0' + s;
fromdec := s;
end;
{
Функция, дополняющая строку до длины N нулями спереди
}
function wide_to(s: string; n: integer): string;
begin
while length(s) < n do s := '0' + s;
wide_to := s;
end;
{
Тестовые функции
}
const
{
s: string = 'A*/B+/A*/C*/D+B*/C*D';
}
s: string = 'A*/B+/A*C';
var
i, j, p, pp, vars_count: integer;
ch: char;
log_val, st, sub_s, params: string;
b_sum, b_mult: boolean;
begin
{ считаем количество переменных (vars_count) и заполняем список параметров (params) }
vars_count := 0; params := '';
for ch := 'A' to 'Z' do begin
if pos(ch, s) > 0 then begin
inc(vars_count);
params := params + ch;
end;
end;
{
Для построения таблицы истинности нужно перебрать все возможные значения
для всех параметров. Сделаем это простейшим способом: просто в цикле пройдем
от 0 до (2^vars_count) - 1, эти числа в двоичной системе счисления (дополненные
нулями до vars_count цифр) как раз и будут представлять собой комбинации True/False
на данной итерации цикла. Например:
0 = 000 (все параметры = False )
1 = 001 (gthdst 2 = False, третий = True)
...
7 = 111 (все параметры = True)
}
for i := 0 to pred(1 shl vars_count) do begin
log_val := wide_to(fromdec(i, 2), vars_count); { <--- текущая комбинация }
st := s + '+'; { Чтобы не портить исходную строку - работаем с копией }
b_sum := false; { эта переменная предназначена для хранения СУММЫ логических произведений }
repeat
p := pos('+', st); { <--- Есть ли еще знак суммы, другими словами - есть ли группа конъюнкций? }
if p > 0 then begin
sub_s := copy(st, 1, pred(p)); { <--- Да... Выделяем ее в переменную sub_s }
{
переменная предназначена для вычисления значения текущего произведения,
поэтому изначально равна True
}
b_mult := true;
{ Перебираем все параметры, смотрим, есть ли какой-то из них в текущей группе }
for j := 1 to length(params) do begin
pp := pos(params[j], sub_s);
if pp > 0 then begin { <--- Есть, pp хранит его позицию в строке }
{
далее возможны 2 варианта развития событий:
1. параметр присутствует с отрицанием (для этого позиция должна быть
БОЛЬШЕ 1, и предыдущим символом должен быть '/');
2. Параметр присутствует без отрицания...
}
if (pp > 1) and (sub_s[pp - 1] = '/') then begin { <--- Есть отрицание? }
{
Да, текущее логическое значение устанавливается в ОТРИЦАНИЕ
соответствующего значения из текущей комбинации параметров
}
b_mult := b_mult and not(log_val[j] = '1');
end
else begin
{ Нет, текущее значение берется без отрицания }
b_mult := b_mult and (log_val[j] = '1');
end;
end;
end;
delete(st, 1, p); { <--- удаляем обработанную группу конъюнкций из строки }
b_sum := b_sum or b_mult; { <--- дизъюнкция конъюнкций :) }
end
until p = 0; { повторять до тех пор, пока есть еще "+" в строке }
{ выводим результат: для (такой-то комбинации) значение функции равно (тому-то) }
writeln(log_val, ' = ', b_sum:5);
end;
end.