Форум «Всё о Паскале» _ Задачи _ Обработка прямоугольных матриц
Автор: ProtasSoft 12.08.2005 21:18
Задана большая матрица вещественных чисел размером 1000 на 2000 в текстовом файле.
Необходимо произвести попарную обработку обработку ее строк, т.е. для каждой пары СТРОКАi и СТРОКАj строк необходимо вычислить функцию от элементов этих строк, например, Ain - элементы СТРОКИi и Bjn - элементы СТРОКИj. Из результатов вычисления функции F(Ai1,...,Ai1000;Bj1,...,Bj2000) сформировать новую матрицу и записать в новый файл.
Подскажите как мне действовать. Насколько я понимаю с большими массивами Borland Pascal не работает.
Автор: kent 12.08.2005 21:27
Цитата(ProtasSoft @ 12.08.05 18:18)
Насколько я понимаю с большими массивами Borland Pascal не работает.
это почти 12Мб. Сможешь получить столько памяти в "куче"?
Автор: ProtasSoft 12.08.2005 21:51
У меня нет Free Pascal. Если поделитесь дистрибутивом, то буду благодарен и готов решать задачу на этом компиляторе.
Автор: volvo 12.08.2005 22:02
Последнюю версию (2.0.0) можно взять на официальном сайте (российское зеркало): http://www.freepascal.org/down-i386-win32-russia.html (21 Мб)
Ссылка на 1.0.10 - здесь: http://forum.pascal.net.ru/index.php?showtopic=3958&view=findpost&p=34754
Автор: Malice 12.08.2005 23:05
Цитата(ProtasSoft @ 12.08.05 17:18)
Насколько я понимаю с большими массивами Borland Pascal не работает.
Совсем не обязательно считывать сразу весь массив. Достаточно считать две строки, записать результат и продолжить в том же духе Есть и другие варианты.
Автор: volvo 12.08.2005 23:21
Цитата(Malice @ 12.08.05 19:05)
Есть и другие варианты.
... изобретения велосипеда. А зачем? Если на 32-битном компилере задача решается "влет", и нет ограничения на использование этих компиляторов?
Тем более, что придется как минимум 2000 раз проходить по файлу (и значительная часть проходов будет "холостыми"), потому как
Цитата
т.е. для каждой пары СТРОКАi и СТРОКАj строк необходимо вычислить функцию от элементов этих строк
. Я бы не заморачивался с построчным чтением...
Автор: Malice 12.08.2005 23:27
Согласен, не подумай, что я против FP, но вдруг это нужно по условию. Если нет, то нет, конечно же.
Автор: klem4 13.08.2005 14:05
А вот мое мнение что FPC тут не выход, так как наверняка задание пишется не "для себя" , а для препода в универе А в универах наших FPC пока не ставят, так что сдать такой код не получится...надо думать.
Автор: volvo 13.08.2005 15:01
klem4,
Цитата(ProtasSoft @ 12.08.05 17:51)
Если поделитесь дистрибутивом, то буду ... готов решать задачу на этом компиляторе.
Если бы тебе предложили тот компилятор, которого нет в институте, ты бы такое написал? Давайте все-таки будем исходить не из своих мнений, а из решений автора...
А поэтому - вопрос к автору топика, скачал ли он FPC и будет решать задачу с его помощью или все-таки нужно извращаться с TP?
Автор: ProtasSoft 15.08.2005 16:08
FPC я скачал и установил.
Вопрос следующий: подскажите как считывать матрицы из текстового файла, когда ее элементы расположены в строке и разделены пробелами. К примеру, файл может быть таким ================ 12,3 23,4 34,6 34,98 23,34 34,5 45,78 56,78 1,06 34,08 34,67 34,67 ================ :fire: :fire:
Автор: klem4 15.08.2005 16:09
Не очень ясен вопрос... могу предположить что тебе нужно следующее :
Считываешь из файла строку, разбиваешь её на числа (наборы символов между пробелами) если надо, сохраняешь в массиве с элементами типа string, и после сохранения или непосредственно после выделения очередного числа переводишь его в числовое представление и работаешь с ним.
Автор: volvo 15.08.2005 19:19
ProtasSoft, не путай такое (Паскаль не использует "," в вещественных числах, используется точка: ".")
j := 1; while not eof(f) do begin for i := 1 to {количество чисел в строке} do begin read(f, a[j]); inc(j); end; readln(f); end;
Автор: ProtasSoft 15.08.2005 20:32
procedure EnterMatrixFromFile (var Matr: Matrix);
const n=5; m=6; var i,j: integer; f:text; TextElem:string;
begin assign(f,'matrixdat.txt'); reset(f); i := 1; while not eof(f) do begin while not eoln(f)do begin j:=1; read(f, Matr[i,j]); inc(j); end; readln(f); inc(i); end;
Что здесь не так?
Автор: klem4 15.08.2005 20:55
у тебя файл текстовый и информация в нем записана в виде строк, а ты пытаешься прочитать число, да и вообще странно как-то твоя процедура выглядит ... тебе нужно либо менять файл на file of single (другой вещественный тип), либо делать то что я тебе писал выше, если хочешь оставить файл текстовым
Автор: Malice 15.08.2005 20:57
Цитата(ProtasSoft @ 15.08.05 16:32)
Что здесь не так?
j всегда равен 1 ? Поставь j=1 до цикла While.
Автор: klem4 15.08.2005 21:36
примерно это должно выглядеть вот так :
{$N+} uses crt;
const n=3;
type
TArr = array[1..n,1..n] of Extended; TFile = Text;
var f_: TFile; x_: TArr;
procedure ReadFromFile(var x: TArr; var f: TFile); var
while not(eof(f)) do begin readln(f, s); t:=1; while(t<=length(s)) do begin while(s[t]=#32) do inc(t);
if t<=length(s) then begin back:=t; while(t<=length(s))and(s[t]<>#32) do inc(t);
tempS:=copy(s, back, t-back);
Val(tempS,tempE,e);
if j=n then begin j:=1; inc(i); end else inc(j);
x[i,j]:=tempE;
end;
end;
end;
end;
Автор: volvo 15.08.2005 22:44
klem4, смысл читать содержимое, как строку? Внимательно читаем условие задачи:
Цитата
Задана большая матрица вещественных чисел размером 1000 на 2000 в текстовом файле.
И, если читать 2000 чисел строкой, то в какую строку это должно помещаться? Строка в FPC также ограничена 256 символами... Так не проще:
ix := 1; iy := 1; while not eof(f) do begin for i := 1 to {количество чисел в строке} do begin read(f, a[ix, iy]); inc(iy); end; readln(f); inc(ix) end;
?
ProtasSoft, в следующий раз, если ты приводишь фрагмент программы с введенными тобой типами, приводи и описания типов тоже. Как, например, я из поста №15 должен знать, что из себя представляет Matrix? И пользуйся тегами [CОDE][/CОDE]
P.S. Если хочется воспользоваться EoLn(f), то вот так:
ix := 1; iy := 1; while not eof(f) do begin while not eoln(f) do begin read(f, a[ix, iy]); inc(iy); end; readln(f); inc(ix) end;
Автор: Malice 15.08.2005 23:38
Цитата(volvo @ 15.08.05 18:44)
ix := 1; iy := 1; while not eof(f) do begin while not eoln(f) do begin read(f, a[ix, iy]); inc(iy); end; readln(f); inc(ix) end;
iy тоже, имхо, сбрасывать надо..
Автор: volvo 15.08.2005 23:48
Да, тогда iy := 1 между первым и вторым While-ом
Автор: ProtasSoft 16.08.2005 13:25
Вот этот код работает
program ReadMatrixFromFile; const NMAX = 100; MMAX = 100; type Matrix = array [1..NMAX, 1..MMAX] of real; var M: Matrix;
(*************************************************** Процедура ввода матрицы из файла ****************************************************) procedure EnterMatrixFromFile (Matr:Matrix);
var n,m,i,j: integer; f:text;
begin assign(f,'matrixdat.txt'); reset(f); i := 1;
while not eof(f) do begin j := 1 ; while not eoln(f) do begin read(f,Matr[i, j]); writeln('Matr[',i,',',j,']',Matr[i,j]); inc(j); end; n:=i; m:=j-1; writeln('n=',n,',','m=',m); readln(f); inc(i); end;
close(f); end;
begin EnterMatrixFromFile(M); readln; end.
[/quote]
Автор: volvo 16.08.2005 13:36
ProtasSoft, ТОЛЬКО приведенный тобой код работает? Я же просил тебя привести описание Matrix, иначе я не могу заставить программу работать так, как ТЫ этого хочешь, тут телепатов нет. Задавай вопросы корректно...
Кстати, чем тебе не понравился мой код? Что именно не работает в нем? И не надо говорить "ВСЕ" или "Просто не работает"... Если ты говоришь, что код нерабочий, будь добр привести пример программы, и файла, для которых произошла ошибка. Голословных утверждений я не принимаю.
Автор: ProtasSoft 16.08.2005 14:28
Если что-то не так сказал прошу прощения. Далее написал код вместе с функцией попарной обработки строк, но где-то в ней ошибки.
Код
program Matrix_Process; (****************************************************** * Демонстрация работы с двумерными массивами * * (матрицами) * ******************************************************) const NMAX = 100; MMAX = 100; type Matrix = array [1..NMAX, 1..MMAX] of real; var M: Matrix;
(*************************************************** Процедура ввода матрицы из файла ****************************************************) procedure EnterMatrixFromFile (Matr:Matrix);
var n,m,i,j: integer; f:text;
begin assign(f,'matrixdat.txt'); reset(f); i := 1;
while not eof(f) do begin j := 1; while not eoln(f) do begin read(f,Matr[i, j]); writeln('Matr[',i,',',j,']',Matr[i,j]); inc(j); end;
readln(f); inc(i); end; close(f); n:=i; m:=j-1; writeln('n=',n,',','m=',m); end; (***************************************************** Функция обработки всех пар строк матрицы ******************************************************) Function Funky(Matr:Matrix):Matrix; var i,j,k,p: integer; Sum1,Sum2,Sum3: real; begin for k:=1 to n do begin for p:=1 to n do begin Sum1:=0; Sum2:=0;Sum3:=0; for j:=1 to m do begin Sum1:=Sum1+Matr[k,j]; Sum2:=Sum2+Matr[p,j]; end;
for j:=1 to m do Sum3:=Sum3+1/(Matr[k,j]+Matr[p,j])*(Matr[k,j]/Sum1-Matr[p,j]/Sum2)*; end; Funky[k,p]:=Sum1*Sum2*Sum3; writeln('Funky[',k,',',p,']',Funky[k,p]); end; end;
end;
begin EnterMatrixFromFile(M); Funky(Matr); readln; end.
Автор: klem4 16.08.2005 14:40
Цитата
где-то в ней ошибки.
1) для функции funky не определены размеры прочтенного массива
2) непонятная рекурсия в той-же ф-и (вызываешь ф-ю в ней самой с совершенно непонятными параметрами)
3) синтаксические ошибки
Автор: klem4 16.08.2005 15:29
Я убрал все синтаксические ошибки, и кое-что добавил, но так как я не знаю что должна считать твоя ф-я, да и вообще она выглядит крайне странно, дальше разбирайся сам, теперь программа по крайней мере компилируется.
Исходный код
uses crt;
const NMAX = 1000; MMAX = 2000; type
Matrix = array [1..NMAX, 1..MMAX] of real;
var
M: Matrix;
row,col:integer;
procedure EnterMatrixFromFile (Matr:Matrix; var size1,size2:integer);
var
i,j: integer;
f:text;
begin
assign(f,'matrixdat.txt');
reset(f);
i := 1;
while not eof(f) do begin j := 1; while not eoln(f) do begin
Function Funky(var Matr:Matrix; size1,size2:integer):Matrix; var
i,j,k,p: integer; Sum1,Sum2,Sum3: real;
begin
for k:=1 to size1 do for p:=1 to size1 do begin
Sum1:=0; Sum2:=0;Sum3:=0;
for j:=1 to size2 do begin
Sum1:=Sum1+Matr[k,j]; Sum2:=Sum2+Matr[p,j]; end;
for j:=1 to size2 do Sum3:=Sum3+1/(Matr[k,j]+Matr[p,j])*(Matr[k,j]/Sum1-Matr[p,j]/Sum2); end;
Funky[k,p]:=Sum1*Sum2*Sum3;
writeln('Funky[',k,',',p,']',Funky[k,p]);
end;
Begin
EnterMatrixFromFile(M,row,col);
Funky(M,row,col);
readln;
End.
ЗЫ правильность чтения я не проверял, только исправил явные ошибки!
Автор: volvo 16.08.2005 16:52
klem4, как ты думаешь, что будет в массиве Matr после вызова этой процедуры? Ничего не забыл? ;) Var, например...
procedure EnterMatrixFromFile(Matr: Matrix; var size1, size2: integer);
Автор: klem4 16.08.2005 16:54
Да, это я проглядел :yes: ... ProtasSoft в заголовке этой ф-и перед Matr:Matrix поставь var
Автор: ProtasSoft 16.08.2005 19:48
Коллеги, вот что у меня получилось с учетом Ваших советов и вроде рабоает. Правда, я не смог справиться с глобальной переменной массива Matr в первой процедуре ввода массива из файла. Может чего подскажите.
Кстати, изменил размерность до 1000Х2000 программа перстала работать.
Исходный код
program Matrix_Process; (****************************************************** * Демонстрация работы с двумерными массивами * * (матрицами) * ******************************************************) const NMAX = 20; MMAX = 20; type Matrix = array [1..NMAX, 1..MMAX] of real; var Matr, M1,M2: Matrix; n,m: integer;
(*************************************************** Процедура ввода матрицы из текстового файла ****************************************************) procedure EnterMatrixFromFile;
var i,j: integer; f:text;
begin assign(f,'matrixdat.txt'); reset(f); i := 1;
while not eof(f) do begin j := 1; while not eoln(f) do begin read(f,Matr[i, j]); writeln('Matr[',i,',',j,']',Matr[i,j]); inc(j); end;
(****************************************************** Процедура печати матрицы реальной размерности (n,m) на экране, располагающая одну строку матрицы на одной строке экрана ******************************************************) procedure PrintMatrix (Matrix_: Matrix; nn, mm: integer); var i, j: integer; begin for i:=1 to nn do begin for j:=1 to mm do writeln('Matrix_[',i,',',j,']',Matrix_[i,j]); writeln; end; end;
(****************************************************** Процедура вывода квадратной матрицы размерности (n,n) в текстовый файл
******************************************************) procedure PrintMatrixToFile (Matrix_: Matrix; nn: integer); var i, j: integer; g:text; begin
assign(g,'matres.txt'); rewrite(g);
for i:=1 to nn do begin for j:=1 to nn do begin write (g,Matrix_[i,j]); end; writeln(g); end; close(g); end;
for k:=1 to nn do begin for p:=1 to nn do begin Sum1:=0; Sum2:=0; Sum3:=0; for j:=1 to mm do begin Sum1:=Sum1+Matrix_[k,j]; Sum2:=Sum2+Matrix_[p,j]; end;
for j:=1 to mm do begin If (Matrix_[k,j]+Matrix_[p,j])<>0 then Sum3:=Sum3 + 1/(Matrix_[k,j]+Matrix_[p,j])* (Matrix_[k,j]/Sum1-Matrix_[p,j]/Sum2)* (Matrix_[k,j]/Sum1-Matrix_[p,j]/Sum2) else Sum3:=Sum3; end; Funk[k,p]:=Sum1*Sum2*Sum3; writeln('Funk[',k,',',p,']',Funk[k,p]);
end; end; PrintMatrixToFile(Funk,nn); end;
begin EnterMatrixFromFile; readln; PrintMatrix (Matr,n,m); PrintMatrixToFile(Matr,n); readln; Funky (matr,n,m); readln;
end.
Автор: volvo 16.08.2005 20:35
Цитата(ProtasSoft @ 16.08.05 15:48)
Кстати, изменил размерность до 1000Х2000 программа перстала работать.
Насколько я вижу, эта программа и не должна работать при больших размерностях - здесь Var тоже был упущен, следовательно при изменении размерности до 1000х2000 программа отказывается работать - просто переполняется стек, так как массив передается не по ссылке, а по значению. Вот так измени:
(****************************************************** Процедура печати матрицы реальной размерности (n,m) на экране, располагающая одну строку матрицы на одной строке экрана ******************************************************) procedure PrintMatrix (Var Matrix_: Matrix; nn, mm: integer); var i, j: integer; begin for i:=1 to nn do begin for j:=1 to mm do writeln('Matrix_[',i,',',j,']',Matrix_[i,j]); writeln; end; end;
(****************************************************** Процедура печати матрицы размерности nn в текстовый файл ******************************************************) procedure PrintMatrixToFile (Var Matrix_: Matrix; nn: integer); var i, j: integer; g:text; begin
assign(g,'matres.txt'); rewrite(g);
for i:=1 to nn do begin for j:=1 to nn do begin write (g,Matrix_[i,j]); end; writeln(g); end; close(g); end;
(*********************************************** Процедура попарной обработки строк матрицы ************************************************) procedure Funky(Var Matrix_: Matrix; nn, mm: integer); var i,j,k,p: integer; Sum1,Sum2,Sum3: real;
begin
for k:=1 to nn do begin for p:=1 to nn do begin Sum1:=0; Sum2:=0; Sum3:=0; for j:=1 to mm do begin Sum1:=Sum1+Matrix_[k,j]; Sum2:=Sum2+Matrix_[p,j]; end;
for j:=1 to mm do begin If (Matrix_[k,j]+Matrix_[p,j])<>0 then Sum3:=Sum3+1/(Matrix_[k,j]+Matrix_[p,j]) *(Matrix_[k,j]/Sum1-Matrix_[p,j]/Sum2)* (Matrix_[k,j]/Sum1-Matrix_[p,j]/Sum2) else Sum3:=Sum3; end; Funk[k,p]:=Sum1*Sum2*Sum3; {writeln('Funk[',k,',',p,']',Funk[k,p]);}
end; end;
end;
(*********************************************** Процедура замены точки на запятую в текстовом файле ************************************************)
while not eoln(g) do begin read(g,char_); if char_='.' then write(f,',') else write (f,char_); end; readln(g); writeln(f); end; close(f); close(g); end;
begin EnterMatrixFromFile; readln; {PrintMatrix (Matr,n,m);} Funky (Matr,n,m); PrintMatrixToFile(Funk,n); RedactirFile; end.
Автор: ProtasSoft 18.08.2005 14:52
Коллеги, пробовал ниже приведенную программку на матрице размером 200Х200 результат был. Попробовал матрицу размером 600Х400 программа зависает, а если предложить переварить матрицу большего размера, выдается системная ошибка Windows. Есть подозрения, что память все же не хватает. Подскажите как выйти из положения. В качестве выхода хочу попровать очистить память от массива, который уже сохранен в файлю. Как это сделать (если возможно)?
Заархивируй свой исходник вместе с файлом данных и присоедини к сообщению. Тогда можно будет говорить об исправлении. Иначе - никак. Возможно что-то не то именно с файлом данных...
Автор: volvo 18.08.2005 15:39
ProtasSoft, та программа, которую ты привел, завершается ошибкой по очень банальной причине: ты объявил тип Matrix как матрицу из 700 строк, а в файле данных у тебя строк БОЛЬШЕ (конкретно - 1227), поэтому при попытке доступа к 701 строке программа и вылетает...
После увеличения количества строк в матрице до 1700 она нормально прочиталась, но в строке
(процедура Funky) происходит RunTime Error 207 (деление на 0) - ты хоть и проверяешь
If (Matrix_[k,j]+Matrix_[p,j])<>0 then ...
но у тебя нулю равно sum2, а на него ты делишь... Это тоже надо проверять... Так что проблемы не в недостатке памяти, просто будь внимательнее... :yes:
Автор: ProtasSoft 18.08.2005 16:18
Огромное спасибо. Заработало! :flowers: Сообщения разделены в тему http://forum.pascal.net.ru/index.php?showtopic=6060&view=findpost&p=45802
Снабдил программу Гаммой-функцией и процедурой интегрирования по симпсону. Возникли какие-то проблемы с компиляцией в старых процедурах. Подскажите где баг.
Если ты про проблему с компиляцией функции Simps, то там просто не определена переменная A, сделай что-то типа:
Function Simps(b:extended;m:integer):extended; var sum, h, a: extended; N, j:Integer; begin N:=1000; a := 0; { так как у тебя интервал начинается с 0 } h:=(b - a)/N; sum:=0.5*(power(b,-1+m/2)*exp(-b/2)); for j:=1 to N-1 do sum:=sum+(j mod 2+1)*power(j*h,-1+m/2)*exp(-j*h/2); Simps:=2*h*sum/3 end;
Больше явных багов не нашел... После этого изменения программа компилируется нормально...
Автор: ProtasSoft 19.08.2005 21:34
После запуска проги выскакивает системная ошибка. Исправленный исходник и файл данных в аттаче.
увеличивать не пробовал? У тебя же опять выход за пределы матрицы должен произойти (файл большой, а матрица - маленькая...)
Автор: volvo 19.08.2005 22:08
А вот и причина возникающей ошибки (RunTime Error 200 - "Деление на 0"):
function Gamma(x: extended): extended; { ... } begin { gamma function } If x=0 then gamma := 1; If x>0.0 then begin { ... } end else { x<0 } begin { ... } gam:=gamma(y);{ recursive call } for i:=0 to j-1 do gam:=gam/(x+i); { <--- Здесь !!! } Gamma:=gam end { x<0 } end; { gamma function }
В указанном мной месте при вычислении Funk[10, 10] у тебя одновременно i = 0 и x = 0 (да, да... При х = 0 ты только присваиваешь функции значение 1, но не выходишь из нее !!!)
P.S. Возможный путь решения проблемы:
If x = 0 Then Begin Gamma := 1; Exit End; { Далее - по тексту... }
Автор: ProtasSoft 19.08.2005 22:33
Можно это так обойти
function Gamma(x: extended): extended; const pi = 3.1415926;
var i,j : integer; y,gam : extended;
begin { gamma function } If x=0 then gamma:=1; if x>0.0 then begin y:=x+2.0; gam:=sqrt(2*pi/y)*exp(y*ln(y)+(1-1/(30*y*y))/(12*y)-y); Gamma:=gam/(x*(x+1)) end; if x<0 then begin {x<0} j:=0; y:=x; repeat j:=j+1; y:=y+1.0 until y>0.0; gam:=gamma(y); { recursive call } for i:=0 to j-1 do gam:=gam/(x+i); Gamma:=gam end; { x<0 } end; { gamma function }
Автор: klem4 19.08.2005 22:46
Так к слову : в паскале есть встроенная константа Pi
Автор: volvo 19.08.2005 22:50
Цитата(klem4 @ 19.08.05 18:46)
Так к слову : в паскале есть встроенная константа Pi
:yes: ProtasSoft, ты будешь смеяться, но и функция Power тоже есть (в модуле Math)