Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2004.12.12;
Скачать: CL | DM;

Вниз

Ошибка в delphi 7   Найти похожие ветки 

 
KSergey ©   (2004-11-29 09:23) [120]

> [117] kostan ©   (29.11.04 09:12)

Может когда и было... Проверять лень, но сомнение меня разбирает...


 
kostan ©   (2004-11-29 09:37) [121]

<ЮЮ ©   (29.11.04 09:23) [119]
 код конечно -профонация (так для примера)

<KSergey ©   (29.11.04 09:23)

 чесное слово ...  :0) [Borland предупреждает  ;)]
 сам ловился (хватило одного раза , просидел в отладчике
 несколько часов - пока "умный" парень не помог)
 причем счет сбивается всегда с разных значений i
 (а бывает что выполняется успешно )


 
KSergey ©   (2004-11-29 09:44) [122]

> [121] kostan ©   (29.11.04 09:37)
>  чесное слово ...  :0) [Borland предупреждает  ;)]

О какой конкрентно версии речь?


 
kostan ©   (2004-11-29 09:49) [123]

ошибка была в Delphi5
щас специально "погонял" в Delphi7
че-то не вылазит (ошибка) - так что простите, наверно
убрали ее
[но все равно интересно:) ]


 
ЮЮ ©   (2004-11-29 09:55) [124]

>щас специально "погонял" в Delphi7
Включи оптимизацию и она вернется. Только не ошибка это. А вот вычислять незнамо что и незнамо зачем и анализировать это в отладчике - это ошибка :)


 
kostan ©   (2004-11-29 10:17) [125]

вот что "гонял" (это чтоб оптимизатор не с оптимизировал:)
 Memo1.clear;
 for dd:=10 to 1000 do
 begin
  rr:=dd*100;
  ff:=dd*rr;
  memo1.lines.add(floattostr(ff));
 end;

(это не ошибка компилятора - а глюк мат.сопроцессора-
был описан еще в книжке по DOS паскалю)


 
begin...end ©   (2004-11-29 13:17) [126]

> Defunct {[115] KSergey ©   (29.11.04 07:46)}

Расставим точки над "i".

1. Код Gero с for + Break:

> for i := 0 to High(Arr) do
>  begin
>   if IsError(Arr[i]) then Break;
>   <Код>
> end;

Производится проверка IsError для всех элементов массива, если массив вообще заполнен. При обнаружении элемента, для которого IsError = True, цикл заканчивается. Ошибок я тут не вижу. По крайней мере, для случая, когда Arr - это динамический массив, или это статический массив с нулевой нижней границей.

2. Ваш код с while:

> i := 0;
> CanGo := NoError(Arr[0]);

Введение дополнительной переменной. Это хорошо?

А в случае, если массив Arr пуст, эта строка вызовет ошибку. Добавьте соответствующую проверку, - и код станет ещё более многословным. Заметьте, в коде [17] эта проверка не нужна: если массив пуст, то цикл просто не выполнится ни разу.

> while CanGo do
> begin
>   <Код>
>   inc(i);
>   if i<High(Arr) then CanGo := NoError(Arr[i])
>                else CanGo := False
> end

Почему функцией NoError не проверяется последний элемент массива?

3. Ваш код с repeat:

> i := 0
> if i<High(Arr) then

Случай, когда массив Arr состоит из одного элемента, Вы игнорируете?

> Repeat
>   if not IsError(Arr[i]) then
>   begin
>     <Код>
>   end;
>   inc(i);
> Until (i>=High(Arr)) or IsError(Arr[i-1]);

Цикл дошёл до i = High(Arr). Тогда выделенное условие равно True. Следовательно, последний элемент массива не будет проверен. А ведь если этот непроверенный элемент массива дал бы IsError = False, то нужно было выполнить ещё и <Код>.

Итак, что мы имеем? Имеем ещё 2 неправильных варианта кода. Иначе говоря - лишнее подтверждение того, что безошибочный код без Break для данного случая написать сложнее, чем с Break; и того, что даже безошибочный код без Break будет выглядеть намного более громоздким, чем с Break.


 
KSergey ©   (2004-11-29 14:00) [127]

> [126] begin...end ©   (29.11.04 13:17)
> А в случае, если массив Arr пуст, эта строка вызовет ошибку.

Позор мне!
Я действительно проглядел самое главное... Из-за чего я так долго "давил" (прошу прощения за термин) Defunc"а... Но так и "не выдавил", увы...

Ну да ладно ;)


 
Gero ©   (2004-11-29 17:06) [128]

i := 0;
if Length(Arr) > 0 then
 while (i <= High(Arr)) and not IsError(Arr[i]) do
   begin
     <Код>
     Inc(i);
   end;


При условии {$B-}.
Это наиболее простой код, который смог написать я для данного случая.
Вроде как без ошибок, при условии что
Здесь 7 строк.
В коде [15] их 5.
Нам приходится инициализировать переменную i и еще к тому же проверять, содержит ли массив элементы.

И неужели после этого товарищ Defunct будет утверждать, что без Break проще?


 
Gero ©   (2004-11-29 17:07) [129]


> Вроде как без ошибок, при условии что

Эта строка лишняя.


 
begin...end ©   (2004-11-29 17:28) [130]

> [128] Gero ©   (29.11.04 17:06)

> if Length(Arr) > 0 then

Раз уж {$B-}, то эту строку в Вашем случае всё же можно убрать, т.к. для пустого массива High(Arr) = -1.

Однако, разумеется, необходимость слежения за {$B-}/{$B+} уже сама по себе является существенным недостатком.


 
Gero ©   (2004-11-29 17:53) [131]


> begin...end ©   (29.11.04 17:28)

Да, ты прав, она лишняя.


 
Gero ©   (2004-11-29 17:59) [132]

Итак,

i := 0;
while (i <= High(Arr)) and not IsError(Arr[i]) do
 begin
   <Код>
   Inc(i);
 end;

Непонятно только, зачем Defunct городил невесть что.

Хотя даже этот код хуже примера с for.
Как уже было сказано, необходимость слежения за {$B} + необходимость инициализации i + вычисление индекса последнего элемента массива в каждой итерации цикла.


 
Defunct ©   (2004-11-30 07:01) [133]

Gero ©   (29.11.04 17:59) [132]
> Непонятно только, зачем Defunct городил невесть что.
Что этой фразой вы хотели сказать?
Втянули меня в дурацкий спор, и теперь еще спрашиваете что я городил. Надо было сразу написать лично вам этот код, потому как вам было виднее, что делает ваш код с циклом for.

> Хотя даже этот код хуже примера с for.
Он лучше хотя бы тем, что не используется break.

> + необходимость инициализации
Плюс возможность изменения индекса в произвольном порядке и с произвольным шагом. Как по мне это плюс.

{B-} всегда установлен по-умолчанию.

> + вычисление индекса последнего элемента массива в каждой итерации цикла.
не городите чепухи. посмотрите asm код этого цикла.

для цикла вашего цикла for:

 for i:=0 to High(Arr) do
 begin
   if IsError(Arr[i]) then break;
 end;


mov eax,[ebp-$04]
call @DynArrayHigh
mov  esi, eax
test esi, esi
jl   +$16
inc  esi
xor  ebx, ebx
mov  eax,[ebp-$4]
mov  eax,[eax+ebx*4]
call IsError
test al,al
jnz  +$4    <<--- вот он ваш break
inc  ebx
dec  esi
jnz  -$13
-->> выход из цикла (14 команд)



теперь сравним с циклом while (без break который)
 i := 0;
 while (i <= High(Arr)) and not IsError(Arr[i]) do
 begin
    Inc(i);
 end;


xor  ebx, ebx   <-- i:=0
jmp  +1
inc  ebx              <-- inc(i)
mov  eax, [ebp,-$4]
call @DynArrayHigh
cmp  ebx, eax
jnle +$F
mov  eax,[ebp-$4]
mov  eax,[eax+ebx*4]
call IsError
test al,al
jz   -$1c

--->> выход из цикла (12 команд)


Думаю теперь нет смысла спорить дальше.


 
Defunct ©   (2004-11-30 07:14) [134]

Defunct ©   (30.11.04 07:01) [133]

Подведу итог.
Каждый break добавляет дополнительный условный jmp, а как вы знаете число конвееров в процессоре ограничено. Если сильно много условныз ветвлений, то блок предсказания ветвлений неминуемо ошибается, что приводит к сбросу конвеера и замедлению выполнения цикла.


 
Verg ©   (2004-11-30 09:17) [135]


> для цикла вашего цикла for:
>
>  for i:=0 to High(Arr) do
>  begin
>    if IsError(Arr[i]) then break;
>  end;
>
> mov eax,[ebp-$04]
> call @DynArrayHigh
> mov  esi, eax
> test esi, esi
> jl   +$16
> inc  esi
> xor  ebx, ebx

> mov  eax,[ebp-$4]
> mov  eax,[eax+ebx*4]
> call IsError
> test al,al
> jnz  +$4    <<--- вот он ваш break
> inc  ebx
> dec  esi
> jnz  -$13

> -->> выход из цикла (14 команд)


Вот все тело цикла (жирным). Состоит оно из восьми команд. Содержит ровно столько же "ветвлений" условных. Но не содержит вызова call @DynArrayHigh (ветвление безусловное) на каждой итерации цикла. Оптимизатор выкинул из тела цикла инварантный код High(Arr).

Какой из циклов будет выполнен быстрее?


 
begin...end ©   (2004-11-30 09:41) [136]

> [133] Defunct ©   (30.11.04 07:01)

> > Хотя даже этот код хуже примера с for.
> Он лучше хотя бы тем, что не используется break.

Очень веский аргумент.

> > + необходимость инициализации
> Плюс возможность изменения индекса в произвольном порядке
> и с произвольным шагом.

Произвольный порядок - downto к Вашим услугам. Насчёт произвольного шага - согласен, но для данного случая, когда проверяется каждый элемент массива, шаг как раз должен быть равен 1.

> > + вычисление индекса последнего элемента массива в каждой
> итерации цикла.
> не городите чепухи. посмотрите asm код этого цикла.

И что - этот asm код показывает, что для while НЕ происходит вычисление High(Arr) для каждой итерации?

И вообще - мы говорили не о вопросах производительности, а о вопросах прозрачности и лёгкости безошибочного написания. Так что asm код тут вообще ничего не докажет.

А насчёт производительности - вот, пожалуйста:

function IsError(Item: Integer): Boolean;
begin
 Result := Item < 0
end;

var
 I, J, K: Integer;
 T1, T2: Cardinal;
 Arr: array of Integer;
begin
 
 // Заполнение массива
 SetLength(Arr, 1000000);
 Randomize;
 for I := 0 to High(Arr) - 1 do
   Arr[I] := Random(100);
 Arr[High(Arr)] := -1;

 // Подсчёт времени выполнения for с Break
 T1 := GetTickCount;
 for J := 0 to High(Arr) do
 begin
   if IsError(Arr[J]) then Break;
 end;
 T1 := GetTickCount - T1;

 // Подсчёт времени выполнения while без Break
 T2 := GetTickCount;
 K := 0;
 while (K <= High(Arr)) and not IsError(Arr[K]) do
 begin
   Inc(K);
 end;
 T2 := GetTickCount - T2;

 // Результаты
 ShowMessage(Format("For с Break: %d; while без Break: %d", [T1, T2]))

end.


Выполните этот код, можете запостить сюда результат.
У меня получилось вот что: "For с Break: 30; while без Break: 60".

> Думаю теперь нет смысла спорить дальше.

Вот и последуйте своему же совету.


 
begin...end ©   (2004-11-30 09:44) [137]

Дополнение к [136]:

Результат "For с Break: 30; while без Break: 60" - это при включённом Range Checking. Если Range Checking выключить, то у меня получается: "For с Break: 40; while без Break: 50". Т.е. всё равно код с while проигрывает.


 
Gero ©   (2004-11-30 13:19) [138]


> не городите чепухи. посмотрите asm код этого цикла

Простите, а вы сами-то его смотрели?
В [135] все сказано, повторяться не буду.



Страницы: 1 2 3 4 вся ветка

Текущий архив: 2004.12.12;
Скачать: CL | DM;

Наверх




Память: 0.78 MB
Время: 0.032 c
14-1100796664
matt
2004-11-18 19:51
2004.12.12
InterBase 6


8-1095414104
Гость
2004-09-17 13:41
2004.12.12
GDI+. Как правильно работать с MeasureCharacterRanges


1-1101692605
che
2004-11-29 04:43
2004.12.12
Создание нескольких текстовых файлов


9-1092494837
Макс
2004-08-14 18:47
2004.12.12
Алгоритм объезда препятствий


1-1101491736
AlexHawk
2004-11-26 20:55
2004.12.12
Как сделать титры