Форум: "Основная";
Текущий архив: 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