Версия для печати темы

Нажмите сюда для просмотра этой темы в обычном формате

Форум «Всё о Паскале» _ Задачи _ Матрица в типизированном файле

Автор: iFool 26.09.2007 0:09

Задача.
Пусть матрица А целых чисел размером 100*100 записана по строкам в файле. Определите, является ди она единичной.

Мне не понятно как запихнуть матрицу в типизированный файл и, самое главное, как потом проверить условие....
Помогите, пожалуйста...

Автор: volvo 26.09.2007 0:17

Цитата
как запихнуть матрицу в типизированный файл
Это какой файл? Файл целых
var f: file of integer

или файл векторов
type vector = array[1 .. 100] of integer;
var f: file of vector;
? Оба - типизированные... Выбирай.

Автор: iFool 26.09.2007 0:23

Ну пусть integer...
матрица получается выглядит в файле как строка??
Ввели..... а как эту самую пресловутую диагональ выделить???

Автор: volvo 26.09.2007 0:57

А тебе надо не только диагональ выделять... Надо всю таблицу проверять:

...
{ открываешь файл }
ok := true;
i := 1;
while not eof(f) do begin

read(f, X);
if pred(i) mod (n + 1) = 0 then ok := ok and (X <> 0)
else ok := ok and (X <> 1);

if not ok then break;
inc(i)
end;

if ok then writeln('yes')
else writeln('no');
{ закрываешь файл }
...


P.S. Понятно что N - это размер строки, т.е., в данном случае N = 100 ...

Автор: Гость 26.09.2007 1:22

А можно ещё вопрос....
как мне осуществить ввод...

Код

for i:=1 to n do
     for j:=1 to n do
       begin
         read(a[i,j]);
         write(f,a[i,j]);
       end;

так я думаю не правильно будет...

Автор: Горсть 26.09.2007 5:56


while not eof(f) do begin

read(f, X);
if pred(i) mod (n + 1) = 0 then ok := ok and (X <> 0)
else ok := ok and (X <> 1);


if not ok then break;
inc(i)
end;


Красиво конечно, но оно не будет работать. Перебор blink.gif

Это должно работать:

while not eof(f) do begin

read(f, X);

if pred(i) mod (n + 1) = 0 then { Diagonal element }
ok := X = 1
else
ok := X = 0;

if not ok then break;
inc(i)
end;



Автор: volvo 26.09.2007 6:38

Цитата
Красиво конечно, но оно не будет работать. Перебор
Понимаешь, в чем дело... Если б оно не отработало (представь себе) - я бы не запостил это... И если ты не смог правильно это вызвать - это только твоя проблема... dry.gif

Добавлено через 2 мин.
P.S. Учи логические операции... В том коде, что я привел нет НИЧЕГО противоречащего ни синтаксису, ни логике...

Автор: Горсть 26.09.2007 8:43

Хорошо, например все элементы матрицы равны 2.
Тогда ok := ok and (X <> 0) == ok and (2 <> 0) = ok and TRUE = ok
и
ok := ok and (X <> 1) == ok and (2 <> 1) = ok and TRUE = ok
Так как до while ok=TRUE, то в данном случае после while также будет ok=TRUE
и далее writeln('yes'), что совершенно неверно, так как матрица явно не единичная.

Автор: Гость 26.09.2007 18:15

Цитата(volvo @ 26.09.2007 2:38) *

Понимаешь, в чем дело... Если б оно не отработало (представь себе) - я бы не запостил это...

Volvo, можно тогда увидеть весь исходник?

Автор: Neznaika 27.09.2007 15:04

Вот, что получилось у меня:


program My_TEST2; { Проверка единичной матрицы 100x100. }
const
N = 100;
var
F : File of Integer;
I, J, K : Integer;
label
LabelMatrixIsNotE, LabelCloseFile;
begin
if ParamCount <> 1 then
begin
Write('Необходимо имя файла!');
Exit
end;
Assign(F,ParamStr(1));
Reset(F);
for I := 1 to N do
for J := 1 to N do
begin
Read(F,K);
if (Ord(I<>J) + K) <> 1 then
goto LabelMatrixIsNotE
end;
Write('Матрица единичная.');
goto LabelCloseFile;
LabelMatrixIsNotE:
Write('Матрица НЕ единичная!');
LabelCloseFile:
Close(F)
end.



Объяснение "(Ord(I<>J) + K) <> 1":
I и J изменяются от 1 до 100. Для диагональных элементов матрицы I = J. K - соответствующий элемент матрицы.
Возможны два ПРАВИЛЬНЫХ варианта:
1) I = J, K = 1.
2) I <> J, K = 0.
Первые условия могут быть либо TRUE, либо FALSE и отрицают друг друга.
Пусть (I=J) будет эквивалентно FALSE, тогда (I<>J) будет эквивалентно TRUE. Получим
1) FALSE, K = 1.
2) TRUE, K = 0.
Здесь уже видна СИММЕТРИЯ(которая собственно и нужна для создания подобных выражений), а именно
порядковые номера FALSE и TRUE равны соответственно 0 и 1(Ord(FALSE) = 0, Ord(TRUE) = 1). Получили
1) 0, K = 1.
2) 1, K = 0.
Видно, что когда матрица ЕДИНИЧНАЯ, то (0 + 1) = (1 + 0) = 1. Когда матрица НЕ ЕДИНИЧНАЯ, то
складывая 0(для 1)) или 1(для 2)) с K получить 1 не удастся. Следовательно
if (Ord(I<>J) + K) <> 1 then МАТРИЦА НЕ ЕДИНИЧНАЯ

В архиве простенькая программа генерации единичной матрицы и программа "простой" проверки(My_TEST1).

P.S.
Так используются два цикла for и оба они прерываются при первой ошибке(при появлении первого "неправильного" элемента матрицы), Break для выхода из циклов применить нельзя, поэтому
используется оператор GOTO. Даже целых два GOTO(бонус smile.gif ).


Прикрепленные файлы
Прикрепленный файл  EMATRIX.rar ( 30.07 килобайт ) Кол-во скачиваний: 225

Автор: volvo 27.09.2007 15:27

Цитата(Гость @ 26.09.2007 13:15) *

Volvo, можно тогда увидеть весь исходник?

Можно... В качестве бонуса Незнайке - здесь Goto на фиг не сдался, даже один, а уж тем более - два.

Вот исходник вместе с матрицей, на которой тестировался:
(*
const
n = 10;
arr: array[1 .. n * n] of integer = (
1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 1, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 1, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 1, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 1, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 1, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 1
);
*)
var
i, X: integer;
ok: boolean;
f: file of integer;
begin
assign(f, 'test.dat');
reset(f);

ok := true;
i := 1;
while not eof(f) do begin

read(f, X);
if pred(i) mod (n + 1) = 0 then ok := ok and (X = 1)
else ok := ok and (X = 0);

if not ok then break;
inc(i)
end;

if ok then writeln('yes')
else writeln('no');

close(f);

end.



Добавлено через 4 мин.
Кстати, можно и вообще без Break-а обойтись:

while (not eof(f)) and ok do begin ...

Автор: Neznaika 27.09.2007 16:03

volvo, так бы сразу и написали


ok := true;
i := 0;
while (not eof(f)) and ok do begin

read(f, X);
if i mod (n + 1) = 0 then
ok := X = 1
else
ok := X = 0;
inc(i)
end;


а раньше было (X <>... кажется

условный оператор здесь тоже не нужен:

OK := TRUE;
I := 0;
while (not Eof(F)) and OK do
begin
Read(F, X);
OK := (Ord(I mod (N + 1) <> 0) + X) = 1;
Inc(I)
end;



P.S.
Просто мне деление на каждом шаге не нравится.
Кажется только через 2 года Intel обещает ускорение выполнения команд div/idiv.

Автор: volvo 27.09.2007 16:08

Цитата
условный оператор здесь тоже не нужен:
Угу... Если хочешь увеличить время работы программы - то так и сделай. Я где-то приводил тест скорости выполнения такой конструкции против If-а, полюбопытствуй...

Автор: Neznaika 27.09.2007 17:21

volvo, извините, но мне кажется, что (Ord(I<>J) + K) <> 1 быстрее чем i mod (n + 1) = 0 + if.
Деление - последний оставшийся тормоз АЛУ.

Автор: Neznaika 27.09.2007 17:43

слепил тест
Интересно, правда компилятор TP, для единичной матрицы лучше вариант с MOD(от volvo),
для не единичной с (Ord(I<>J) + K) <> 1).

Наверно правильнее проверять на Delphi...

if также может быть преобразован в CMOV...
-----------------------------------------------------------
Хмм, для TP почти нет никакой разницы.


Прикрепленные файлы
Прикрепленный файл  RDTSC.rar ( 26.76 килобайт ) Кол-во скачиваний: 224

Автор: volvo 27.09.2007 17:49

Цитата
Наверно правильнее проверять на Delphi...
Только в соответствующем разделе smile.gif Я говорил именно о 16-битах... С 32-битными компиляторами кое-что меняется...

Автор: Neznaika 27.09.2007 18:26

Тьфу, чёрт!
Если посмотреть в отладчике(Turbo Debugger), то можно увидеть, что
при трансляции Ord(I<>J) компилятор TP использует команды условных переходов,
то есть он фактически Ord превращает в IF.

Автор: Neznaika 6.10.2007 15:12

Один вопрос, volvo. Ещё неделю назад хотел спросить.

Цитата
Я говорил именно о 16-битах... С 32-битными компиляторами кое-что меняется...

Можно узнать, что Вы имеете в виду.

Turbo Debugger мне подсказал, что TP компилирует
boolA := intB = intC и if intB = intC then boolA := TRUE else boolA := FALSE
в почти одинаковый набор команд.

P.S.
div на моём PIII выполняется за 18 тактов. Очень медленно...