Столкнулся с одной проблемой, 2 дня уже бьюсь... что делать - не знаю... Если коротко, то дело вот в чем. Я написал процедуру для подсчета определителя матрицы любого порядка (методом Гаусса). И там над матрицей выполняются различные преобразования (складывания строк и т.д.). Причем - внимание - по условию задания матрица должна быть обязательно динамической! Процедура работает нормально, определитель находит, НО в то же время изменяет исходную матрицу, а этого нельзя допустить!! Происходит это, как мне кажется, из-за того, что такие матрицы - ссылки на память, поэтому передать ее в процедуру строго по значению нельзя...
Замучился я с этими динамическими структурами... Please, умные люди, help me!
ОК, ошибка "Floating divizion by zero" устранена... Мне надо ставить 2 за внимательность...
Но осталась 2-я ошибка - "Invalid floating point operation". Итак, код такой:
function Opred_Gauss(A:TDMAtr):real; // Описание переменных... var i,j,jk,ik,new:integer; tmp,mnoj,mn1,mn2:real; found:boolean; AC:TDMAtr; const eps = 1e-10; begin { Это то самое копирование матрицы } setlength(ac, length(a)); for i := 0 to pred(length(a)) do begin setlength(ac[i], length(a[i])); for j := 0 to pred(length(a[i])) do ac[i, j] := a[i, j] end; { А теперь - сам алгоритм } for i := 0 to high(AC) do begin if abs(ac[i,i])<eps then begin result :=0.0; exit end; for j := succ(i) to high(AC) do begin mnoj:=a[j,i]/a[i,i]; for jk:=i to high(AC) do a[j,jk]:=a[j,jk]-mnoj*a[i,jk]; end; end; result := 1.0; for i:=1 to high(AC) do result:=result*a[i,i]; end;
При данных
1 1 1 1 1 1 1 1 1
возникает вышеописанная ошибка в той же строке mnoj:=a[j,i]/a[i,i];
Немного помучившись и покапавшись в справочниках, нашел, что это бывает связано с проблемами сопроцессора, и устраняется путем добавления строчки
asm FINIT end;
тогда вместо ошибки возвращается константа NAN.
Окончательный вариант кода выглядит так:
function Opred_Gauss(A:TDMAtr):real; // Описание переменных... var i,j,jk,ik,new:integer; tmp,mnoj,mn1,mn2:real; found:boolean; AC:TDMAtr; const eps = 1e-10; begin asm FINIT end;
{ Это то самое копирование матрицы } setlength(ac, length(a)); for i := 0 to pred(length(a)) do begin setlength(ac[i], length(a[i])); for j := 0 to pred(length(a[i])) do ac[i, j] := a[i, j] end; { А теперь - сам алгоритм } for i := 0 to high(AC) do begin if abs(ac[i,i])<eps then begin result :=0.0; exit end; for j := succ(i) to high(AC) do begin mnoj:=a[j,i]/a[i,i]; for jk:=i to high(AC) do a[j,jk]:=a[j,jk]-mnoj*a[i,jk]; end; end; result := 1.0; for i:=1 to high(AC) do result:=result*a[i,i]; If Result = NAN then Result:=0; end;
Вот теперь (!) все работает без ошибок... УРА!
Но интересно, есть ли другие пути решения проблемы, без асмы? И отчего она все-таки, эта ошибка?
ОК, ошибка "Floating divizion by zero" устранена... Мне надо ставить 2 за внимательность...
Но осталась 2-я ошибка - "Invalid floating point operation". Итак, код такой:
function Opred_Gauss(A:TDMAtr):real; // Описание переменных... begin { Это то самое копирование матрицы } ... { А теперь - сам алгоритм } for i := 0 to high(AC) do begin if abs(ac[i,i])<eps then begin result :=0.0; exit end; for j := succ(i) to high(AC) do begin mnoj:=a[j,i]/a[i,i]; // **** !!! **** for jk:=i to high(AC) do a[j,jk]:=a[j,jk]-mnoj*a[i,jk]; // **** !!! **** end; end; result := 1.0; for i:=1 to high(AC) do result:=result*a[i,i]; end;
Вам надо еще раз поставить 2 за "внимательность"... Неужели нельзя было проверить все ли A заменены на AC? Ведь NaN появляется при той же самой ошибке - "деление на 0"... Почему? Проверяется на 0 значение AC, а операция производится с A !!!
В общем, окончательный вариант функции без всякого Асма:
Function Opred_Gauss(A:TDMatr):double; const eps=1E-10; var i,j,jk:integer; mnoj:real; AC:TDMAtr; begin setlength(ac, length(a)); for i := 0 to pred(length(a)) do begin setlength(ac[i], length(a[i])); for j := 0 to length(a[i]) do ac[i, j] := a[i, j] end;
for i := 0 to high(AC) do begin if abs(ac[i,i])<eps then begin result :=0.0; exit end; for j := succ(i) to high(AC) do begin mnoj:=ac[j,i]/ac[i,i]; for jk:=i to high(AC) do ac[j,jk]:=ac[j,jk]-mnoj*ac[i,jk]; end; end; Result:=1; For i:=0 to high(AC) do Result:=Result*aC[i,i]; end;