Помощь - Поиск - Пользователи - Календарь
Полная версия: Матрица в типизированном файле
Форум «Всё о Паскале» > Pascal, Object Pascal > Задачи
iFool
Задача.
Пусть матрица А целых чисел размером 100*100 записана по строкам в файле. Определите, является ди она единичной.

Мне не понятно как запихнуть матрицу в типизированный файл и, самое главное, как потом проверить условие....
Помогите, пожалуйста...
volvo
Цитата
как запихнуть матрицу в типизированный файл
Это какой файл? Файл целых
var f: file of integer

или файл векторов
type vector = array[1 .. 100] of integer;
var f: file of vector;
? Оба - типизированные... Выбирай.
iFool
Ну пусть integer...
матрица получается выглядит в файле как строка??
Ввели..... а как эту самую пресловутую диагональ выделить???
volvo
А тебе надо не только диагональ выделять... Надо всю таблицу проверять:

...
  { открываешь файл }
  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 ...
Гость
А можно ещё вопрос....
как мне осуществить ввод...
Код

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

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

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

Добавлено через 2 мин.
P.S. Учи логические операции... В том коде, что я привел нет НИЧЕГО противоречащего ни синтаксису, ни логике...
Горсть
Хорошо, например все элементы матрицы равны 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'), что совершенно неверно, так как матрица явно не единичная.
Гость
Цитата(volvo @ 26.09.2007 2:38) *

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

Volvo, можно тогда увидеть весь исходник?
Neznaika
Вот, что получилось у меня:

 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 ).
volvo
Цитата(Гость @ 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
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
Цитата
условный оператор здесь тоже не нужен:
Угу... Если хочешь увеличить время работы программы - то так и сделай. Я где-то приводил тест скорости выполнения такой конструкции против If-а, полюбопытствуй...
Neznaika
volvo, извините, но мне кажется, что (Ord(I<>J) + K) <> 1 быстрее чем i mod (n + 1) = 0 + if.
Деление - последний оставшийся тормоз АЛУ.
Neznaika
слепил тест
Интересно, правда компилятор TP, для единичной матрицы лучше вариант с MOD(от volvo),
для не единичной с (Ord(I<>J) + K) <> 1).

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

if также может быть преобразован в CMOV...
-----------------------------------------------------------
Хмм, для TP почти нет никакой разницы.
volvo
Цитата
Наверно правильнее проверять на Delphi...
Только в соответствующем разделе smile.gif Я говорил именно о 16-битах... С 32-битными компиляторами кое-что меняется...
Neznaika
Тьфу, чёрт!
Если посмотреть в отладчике(Turbo Debugger), то можно увидеть, что
при трансляции Ord(I<>J) компилятор TP использует команды условных переходов,
то есть он фактически Ord превращает в IF.
Neznaika
Один вопрос, volvo. Ещё неделю назад хотел спросить.
Цитата
Я говорил именно о 16-битах... С 32-битными компиляторами кое-что меняется...

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

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

P.S.
div на моём PIII выполняется за 18 тактов. Очень медленно...
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.