-
почему переменная цикла принимает значение выходящее за установленые пределы? заголовок:
interface
type
myVector2f = record
x, y: real;
end;
myVector2i = record
x, y: integer;
end;
myBCell = record
btm: real; pts: integer; mov: array [0..7] of integer; v: myVector2f; end;
myBHydro = object
cell: array of myBCell;
h, w: integer;
function idx_to_crd(i: integer): myVector2i;
function crd_to_idx(v: myVector2i): integer;
public
h_link, v_link: boolean; density: integer; min, max: real;
procedure init(width, height: integer);
procedure bottom(x, y: integer; el: real); procedure drop(x, y, n: integer); function liquid(x, y: integer): real; function ground(x, y: integer): real;
procedure flow(t: real); end;
реализация:
...
procedure myBHydro.flow(t: real);
var
a, elc, eln, sum: real;
c: integer;
i, j, k, idx: integer;
v, n: myVector2i;
M_DIST: array [0..7] of real; SHIFT_X: array [0..7] of integer; SHIFT_Y: array [0..7] of integer; FINAL: array [0..7] of real; begin
if t > 1
then a := 1
else a := t;
for i := 0 to 7 do
if (i mod 2) = 0
then M_DIST[i] := 1 / sqrt(2)
else M_DIST[i] := 1;
SHIFT_X[0] := -1; SHIFT_Y[0] := -1;
SHIFT_X[1] := 0; SHIFT_Y[1] := -1;
SHIFT_X[2] := 1; SHIFT_Y[2] := -1;
SHIFT_X[3] := 1; SHIFT_Y[3] := 0;
SHIFT_X[4] := 1; SHIFT_Y[4] := 1;
SHIFT_X[5] := 0; SHIFT_Y[5] := 1;
SHIFT_X[6] := -1; SHIFT_Y[6] := 1;
SHIFT_X[7] := -1; SHIFT_Y[7] := 0;
for i := 0 to high(cell) do begin
if cell[i].pts < 1 then continue;
c := round(a * cell[i].pts);
if c < 1 then continue;
v := idx_to_crd(i);
for j := 0 to 7 do begin
n.x := v.x + SHIFT_X[j];
n.y := v.y + SHIFT_Y[j];
if (n.x < 0) or (n.x >= w) or (n.y < 0) or (n.y >= h)
then FINAL[j] := 0
else FINAL[j] := 1;
end;
elc := cell[i].btm + cell[i].pts / density;
sum := 0;
for j := 0 to 7 do begin
if FINAL[j] = 0 then continue;
idx := crd_to_idx(Vector2i(v.x + SHIFT_X[j], v.y + SHIFT_Y[j]));
eln := cell[idx].btm + cell[idx].pts / density;
if eln > elc then begin
FINAL[j] := 0;
continue;
end;
FINAL[j] := (elc - eln) * M_DIST[j];
sum := sum + FINAL[j];
end;
for k := 0 to 7 do begin
try
FINAL[k] := FINAL[k] / sum;
except
FINAL[k] := i / i;
end;
end;
cell[i].v.x := 0; cell[i].v.y := 0;
for j := 0 to 7 do begin
cell[i].mov[j] := round(c * FINAL[j]);
cell[i].v.x := cell[i].v.x + FINAL[j] * SHIFT_X[j];
cell[i].v.y := cell[i].v.y + FINAL[j] * SHIFT_Y[j];
end;
end;
for i := 0 to high(cell) do begin
v := idx_to_crd(i);
for j := 0 to 7 do begin
if cell[i].mov[j] < 1 then continue;
idx := crd_to_idx(Vector2i(v.x + SHIFT_X[j], v.y + SHIFT_Y[j]));
cell[idx].pts := cell[idx].pts + cell[i].mov[j];
cell[i].pts := cell[i].pts - cell[i].mov[j];
end;
end;
if t > a then begin
t := t - a;
flow(t);
end;
end;
в выделеном цикле гарантировано возникает ошибка k = 8 при произвольном i полтора часа уже ковыряюсь - пока ни одной идеи откуда это и почему
-
маленькое уточнение: k изменяется от 8 до 1 о_О ошибка повторяется несколько раз в пределах цикла for i := 0 to high(cell) do begin
-
i/i ? деление на ноль там бывает?
-
> маленькое уточнение: k изменяется от 8 до 1
а тут FINAL: array [0..7] of real;
-
[2]теоретически возможно. но пока не случалось воткнул в except чтобы отследить при каком значении i происходит ошибка сначала думал, что на каком-то определённом но потом выяснилось. что с i связи нет никакой [3]именно! =) FINAL: array [0..7] of real; for k := 0 to 7 do begin
try
FINAL[k] := FINAL[k] / sum;
except
FINAL[k] := i / i;
end;
end; и в этом самом цикле k принимает значения от 8 до 1 как будто у меня for k := 8 downto 1 do
... вот этот момент меня и смущает
-
-
а какие параметры вводить нужно?
-
например
dim := 25;
mdl.init(dim, dim);
mdl.density := 1000;
for x := 0 to dim - 1 do
for y := 0 to dim - 1 do
mdl.drop(x, y, 4500 + random(1000)); тогда mdl.liquid(x,y) будет в пределах 4,5 - 5,5 а разрешение по высоте 1/1000
-
> [2] > теоретически возможно. но пока не случалось
да как не случается, если цикл начинается с нуля? у меня сразу выбило
-
а в mdl.flow() желательно от 0 до 1 по изначальному замыслу - время в секундах между кадрами
-
> [8] > да как не случается, если цикл начинается с нуля? у меня > сразу выбило
не случается, если не случается exception на первом шаге цикла хотя, если случается exception то какая уже разница =) можете убрать код из except ... end;
-
убрал и вставил диалог, показывает от 0 до 7, а с секцией только 0 показывал (диалог перед секцией)
-
убрал запускаю получаю Debugger fault notification "Project c:\delphi7\projects\wasser\dbg.exe raised too many consecutive exceptions: 'floating point invalid operations a 0x00408d9b'. Process stoped. Use Step or Run to continue." зменённый код цикла for k := 0 to 7 do begin
writeln(k);
FINAL[k] := FINAL[k] / sum;
end;
Writeln;
результат выполнения кода Microsoft Windows [Version 6.1.7601]
(c) Корпорация Майкрософт (Microsoft Corp.), 2009. Все права защищены.
C:\Delphi7\Projects\wasser>dbg
model size: 5
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
1
2
3
4
5
6
7
0
Exception EInvalidOp in module dbg.exe at 0004D24E.
Invalid floating point operation.
-
сделал больше вывода. получилось cell #6
pts = 4578
c = 262
elevation = 4.57800000000000E+0000
eln #0 = 5.11400000000000E+0000
ignoring this direction
eln #1 = 5.47800000000000E+0000
ignoring this direction
eln #2 = 5.23000000000000E+0000
ignoring this direction
eln #3 = 5.39600000000000E+0000
ignoring this direction
eln #4 = 5.32100000000000E+0000
ignoring this direction
eln #5 = 5.19300000000000E+0000
ignoring this direction
eln #6 = 4.99500000000000E+0000
ignoring this direction
eln #7 = 5.23100000000000E+0000
ignoring this direction
normalizing mask: 0Exception EInvalidOp in module dbg.exe at 0004D61E.
Invalid floating point operation. т.е. там. где цикл // заполняем ненулевые позиции разницей наша отметка - соседская отметка не выполняется происходит ошибка...
-
-
k изменяется от 8 до 1Это оптимизатор так работает, ошибки там нет. Протрассируй цикл и посмотри как меняются значения FINAL - от первого к последнему, как и полагается. Если смущают такие вещи, отключи Optimization в настройках компилятора. Чтобы изменения были заметны - надо пересобрать или переоткрыть проект. Вообще для симулятора воды как-то всё сложно (и вероятно медленно). Для "похожего на правду" распространения волн достаточно двух буферов и морфологического фильтра:
NewVal = (Src[x-1,y-1] + Src[x, y-1] + Src[x+1, y-1] +
Src[x-1, y] + + Src[x+1, y] +
Src[x-1, y+1] + Src[x, y+1] + Src[x+1, y+1]) * 0.25 - Dst[x,y];
Dst[x,y] := NewVal - (NewVal * FadeFactor);
FadeFactor - коэфф. затухания (если оно нужно), 0..1. На следующей итерации Dst и Src меняются местами.
-
k в цикле напрямую не используется - компилятор просто делает действия над всеми элементами массива в том порядке, как ему удобно. А ошибки твои - из за деления на нулевую sum
-
убрал код нормализации маски ошибка исчезла
включил мозг =) при нулевой сумме весов уравнивать нечего. всем спасибо, извините за беспокойство
-
> [15]
нет, там не волны, там распространение на неровной поверхности, стекать с возвышенностей, скапливаться во впадинах и всё такое.
> [16]
вы совершенно правы, просто зациклился на цикле =)
-
не понравилась мне эта модель медлительная, неправдоподобная сделал другую, с учётом ошибок и недостатков получилось на порядок лучше главный и пока неустранимый недостаток такой же как в the dust - водопады получаются совершенно невзрачные.
исходники и визуализация там же (визуализация очень топорная и потому тормозная, без отрисовки 1000-1400fps с отрисовкой - 40-60)
|