Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Основная";
Текущий архив: 2004.12.12;
Скачать: [xml.tar.bz2];

Вниз

Ошибка в 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;
Скачать: [xml.tar.bz2];

Наверх




Память: 0.77 MB
Время: 0.039 c
6-1096821871
Agent-Smith
2004-10-03 20:44
2004.12.12
Реализация работы между сегментами сети


3-1100178736
Layner
2004-11-11 16:12
2004.12.12
Люди добрые, поможите вставить аппостоф в SQL таблицу.


6-1096771160
Klopan
2004-10-03 06:39
2004.12.12
Каталогизатор


1-1101642989
Frozzen
2004-11-28 14:56
2004.12.12
Копирование свойств объекта


1-1101608757
Bobby Digital
2004-11-28 05:25
2004.12.12
Listbox pt.2





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский