Страницы: 1 2 вся ветка
Форум: "Потрепаться";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 2002.04.04;
Скачать: [xml.tar.bz2];




Вниз

Весьма странное поведение программы 


olookin   (2002-02-21 18:09) [0]

Господа!
У меня возникла проблема, объяснить которую я совершенно не в состоянии. Она заключается в следующем. Есть программа, производящая математический расчет и использующая динамические массивы. Эта программа, скомпилированная на одной машине под NT 4 в Delphi 5 дает некий результат (условно правильный). Эта же программа (скопированный экзешник) под Win 2000 на второй машине дает другой результат. Наконец, эта же программа (без всяких внесенных изменений в код), скомпилированная на второй же машине под Win 2000 в Delphi 6 дает третий результат, отличный от двух предыдущих.
Возможные объяснения (из тех, что мне пришли в голову):
1. Втьорая машина более быстрая и имеет другую конфигурацию (т.е. первая машине - Pentium 3, а вторая - Pentium 4) - иными словами результат зависит от типа машины
2. Вторая машина более быстрая, а расчет идет с большим числом итераций - т.е. вторая машина просто не успевает считать правильно.
3. Все дело в распределении памяти и ошибке в программе (например, чтение несуществующего элемента массива и пр.), т.к. на разных машинах оно разное, то и результат разный.

P.S. Указателей и адресов я не использую, только динамические массивы.

Буду ВЕСЬМА благодарен за полезные советы.

Олег.



Digitman   (2002-02-21 18:22) [1]

приводи как минимум код, являющимся ключевым в расчетах, дающих неожиданный для тебя результат.
не забудь пояснить, в каком потоке он выполняется, используются ли объекты синхронизации, какие и каким образом



McSimm   (2002-02-21 18:30) [2]

Число итераций зависит от времени выполнения?



olookin   (2002-02-21 18:34) [3]

Уважаемые господа, код привести не могу, т.к. он слишком велик (расчеты супер-сложные - речь идет о моделировании физиологического процесса) и кроме того, не является свободным для распространения. Однако РУЧАЮСЬ, что этот код работает верно и ошибок В НЕМ нет.
Потоков и прочих вещей не используется - сплошная математика. Время выполнения напрямую зависит от числа просчетов (итераций), обратной же зависимости нет.
Уверен, что результат связан с операционной системой или структурой компьютера (см. первое письмо)

Заранее благодарен за любые советы.



Digitman   (2002-02-21 18:42) [4]

>>не успевает считать правильно

ну уж это точно - нонсенс ! если некий итерационный цикл не привязан никак к периферийному "железу", не прерывается ничем и завершается корректно, то как вообще можно повлиять на результаты его работы ?



Иван Шихалев   (2002-02-21 18:44) [5]

to olookin

Поскольку ты можешь сказать только то, что "ручаешься" и "уверен" разговора по делу состояться не может. На всякий случай проверь 17ю строку - чем черт не шутит.



olookin   (2002-02-21 18:50) [6]

Ивану Шихалеву

Может быть, вы и правы. Однако, видимо вы плохо прочитали мой самый первый вопрос. Я повторюсь. На одной машине результат один, на другой машине - результат другой. Если ошибка в 17 строчке, то какая она должна быть, чтобы так кардинально повлиять на работу программы ? Ведь ошибка или есть, или ее нет.

P.S. Еще раз напоминаю, что код содержит ТОЛЬКО математику.

Спасибо за ответ.



Иван Шихалев   (2002-02-21 18:55) [7]

Видимо, программа использует некорректное обращение к памяти. Хотя как его устроить без указателей, я не знаю. Совершенно очевидно, что в программе не ошибка, а лажа чистой воды. Без кода ее найти невозможно.



Иван Шихалев   (2002-02-21 18:56) [8]

Впрочем, возможны проблемы с ошибкой округления.



olookin   (2002-02-21 19:01) [9]

Ивану Шихалеву

Если вы действительно уверены в этом и если вы хотите посмотреть код, часть его я могу представить. Однако (учитывая то, что весь код слишком велик) это бесполезная трата вашего и моего времени. Я затем и обратился в форум, чтобы мне подсказали ВОЗМОЖНЫЕ (и главное РЕАЛЬНЫЕ) варианты решения проблемы. Может быть вы конкретизируете ваш ответ (какие еще, хотя бы теоретически, ошибки в ПРОГРАММНОМ КОДЕ могут вызвать такую реакцию).

Заранее благодарен.



olookin   (2002-02-21 19:04) [10]

Ивану Шихалеву

Округление я действительно использую и как раз в одном из самых важных мест. НО. Я округляю деление КОНСТАНТЫ на КОНСТАНТУ. Как может возникнуть ошибка в этом случае?

Заранее благодарен за ответ.



olookin   (2002-02-21 19:06) [11]

Например, я использую такой код:

procedure Model1.Control_iso;
var k,c: integer;
begin
Fmax:=0; deltime:=0; t:=0;
if ncyc=0 then Init_Cond(0) else Cycle_cond(0);
for k:=0 to 511 do
for c:=0 to Trunc(2.0/TT)-1 do Takt(0); //константа TT = 0.1
end;

Как по вашему, может возникнуть ошибка в таком коде?

Заранее благодарен.



Иван Шихалев   (2002-02-21 19:17) [12]

Вместо деления константы на константу компилятор подставляет костанту.

Говоря об ошибках округления, я имел в виду не явное округление, а неявное, которое производит сопроцессор при любой операции над вещественными числами. Теоретически возможны расхождения на разных сопроцессорах (на практике я с таким не сталкивался). При компиляции другой версией Delphi также возможны расхождения, поскольку эта погрешность сильно зависит от оптимизации.



olookin   (2002-02-21 19:20) [13]

Ивану Шихалеву

Предположим, что (пусть даже теоретически) результат действительно зависит от сопроцессора (кстати, хоть я не знаток в этой области, но мне кажется единственно разумным именно такое предположение). Можно ли эту проблему как-то решить.

Заранее благодарен за ответ.



Alex Dobrushin   (2002-02-21 19:24) [14]

Конечно в таком коде ошибок быть не может. Ошибки могут быть в Init_cond(), Cycle_cond() или takt(). Вообще, если код содержит только математику, и результат - формула, пусть и итеративная, то итоговая цифра должна быть одинакова. Ошибка может быть только в коде, железо и ОС ни в коем случае не может быть виновата. Вы же не используете каких-то особых свойств ОС или железа? У меня когда-то были такие проблемы, когда возникало некое исключение, причем не всегда, и это исключение я не обрабатывал, т.е. пока я пошагово не оттрассировал код я так и не понял, что все время вызывалась исключительная ситуация...Оно (исключение) где-то перехватывалось и скрывалось...



Иван Шихалев   (2002-02-21 19:25) [15]

Иногда можно. Глубокой переработкой кода с тем, чтобы не уходить в машинный эпсилон и не складывать величины с сильными отличиями в порядке. Кстати, какой тип для вещественных чисел используется?



McSimm   (2002-02-21 19:28) [16]

Не используете ли вы в программе сравнений на равенство с участием значений с плавающей точкой?
Например:
if SomeValue = AnotherValue then ...
else ....

Можно предположить, что подобная конструкция на разных машинах отработает разные ветки.
Хотя тоже сомнительно



olookin   (2002-02-21 19:29) [17]

To Alex Dobrushin

Я целиком и полностью согласился бы с вами, если не то обстоятельство, которое я уже описывал. Результат программы зависит от того, на какой машине и под какой системой я ее выполняю. Значит (следуя логике) виновата либо система, либо железо. Я прекрасно понимаю, что это звучит смешно, но это так. Действительно, ведь не может же программный код (не использующий ничего, кроме математики) быть селекторным (т.е. самому решать, где вводить ошибку, а где нет). Поэтому я нахожусь, мягко говоря, в смятении, т.к. не знаю КАК ИМЕННО эта ошибка возникает. Не могу же я пользоваться трэйсами в коде из 5000 строк с кучей вложенных циклом.

Спасибо за ответ.



olookin   (2002-02-21 19:33) [18]

Ивану Шихалеву и McSimm

Я использую только double. Сравнения типа if A=B (A и B типа double) я также использую очень часто.
Кроме того, переработать заново программный код настолько сложно, что я не возьмусь за это.

Спасибо за ответы.
Вынужден покинуть конференцию, но жду советов.



McSimm   (2002-02-21 19:35) [19]

Подобные сравнения в машинных операциях с плавающей точкой некорректны.

Их использование вполне можно назвать ошибкой программирования.



Иван Шихалев   (2002-02-21 19:43) [20]

Совершенно верно относительно сравнений. И еще хорошо б заменить Double на Extended. В случае сравнений это ситуацию не исправит, но при вычислениях погрешность уменьшит.



Anatoly Podgoretsky   (2002-02-21 22:00) [21]

olookin (21.02.02 18:34)
Однако РУЧАЮСЬ, что этот код работает верно и ошибок В НЕМ нет.

Странное утвержедение, если работает верно, то какая проблема :-)



ProgMan   (2002-02-22 08:57) [22]

Дополняя Иван Шихалев © (21.02.02 19:43) и McSimm © (21.02.02 19:35)

Правильнее будет использовать
if (A-B < Epsilon) then
Epsilon - заданная точность сравнения.



ProgMan   (2002-02-22 09:28) [23]

Поторопился. Конечно, так правильнее:

if (Abs(A-B) < Epsilon) then



Abajun   (2002-02-22 10:40) [24]

Интересно, а какое расхождение в результатх может в этом случае получаться? Я также занимаюсь исключительно математ. расчетами и сталкивалась не раз с такой ситуацией: один и тот же экзешник выдавал разные значения на разных машинах, но расхождение было в 5-6 знаке после запятой. Я понимаю, что дело в различных сопроцессорах, так ведь?



EAlexander   (2002-02-22 10:47) [25]

Я читал о таком клюке в D5 - произвольное значение типизированной константы, т.е.
в проге const I : Double =1.2;
а в другом модуле данная константа м.б. равна 1.3 или 1.1, т.е. близкое значение, но не то.



Иван Шихалев   (2002-02-22 10:49) [26]

Вот как раз для типизированной константы такое в принципе невозможно.



EAlexander   (2002-02-22 11:44) [27]

Это почему же ?:)



McSimm   (2002-02-22 12:19) [28]

>Abajun © (22.02.02 10:40)
Я потому и предположил вариант с проверкой на равенство, т.к. если накапливаемая погрешность хоть и может иметь место, но наверняка незначительна. А вот если программа выполнит другую ветку условия, результат может поменяться кардинально.

>EAlexander © (22.02.02 10:47)
>Иван Шихалев © (22.02.02 10:49)
Подтверждаю, что такой глюк имел место быть. Я с ним сталкивался и экспериментировал. Но это было очень давно, не помню версию Делфи и подробностей. Помню, возникал глюк при использовании типизированной константы Double, описанной в другом модуле. Результаты были гораздо хуже, чем привел EAlexander.
Я тогда вывел для себя правило - не использовать
const X: Double = Value;



EAlexander   (2002-02-22 12:23) [29]

>>McSimm
Это вроде было с D1-5, и м.б. есть в D6 - не знаю :(
Серьзнейший глюк идет на всем протяжении, но borland молчит :(



olookin   (2002-02-22 14:51) [30]

Уважаемые господа!

Я прочитал все ваши послания.
Хочу добавить новые наблюдения.
1. Под Win 2000 я воткнул все вычисления в поток, затем сделал потоку Idle, а в момент начала расчетов стал запускать разные приложения (с целью резко затормозить работу процессора). УДИВИТЕЛЬНО, но результат изменился и стал правильным.
2. Проверив работу программы на системах Win98, NT4 и Win2000 я получил, что программа правильно работает на той машине, где НЕ установлена Win2000. Выборка была из 6 машин, 1 - Win 98 (Pentium 2), 2 - NT 4 (Pentium 2 и 3), 3 - Win2000 (Pentium 3 и две машины Pentium 4).

В итоге пришел к выводу, что виновата система. Более того, я слышал, что Win2000 использует некую "конвейерную" систему расчета, при которой выполняет предсказание (я это понимаю так - если какая-то величина остается постоянной на протяжении длительного интервала времени, то система подставляет это значение, а не вычисляет его каждый раз). САМОЕ ВАЖНОЕ, что ошибка возникает именно на стационарном участке расчетов.

Может быть именно это является причиной?

Заранее спасибо за ответы.



McSimm   (2002-02-22 15:19) [31]

>при которой выполняет предсказание
Это точно не относится к вашей проблеме. Предсказание выполняется для загрузки в конвеер очередной порции инструкций.

>на стационарном участке расчетов.
Поясните



PVOzerski   (2002-02-22 15:31) [32]

А все ли хорошо с Hardware: нет ли глючного FPU, сбойной памяти и т.п.?



olookin   (2002-02-22 15:41) [33]

To McSimm и PVOzerski

1. Стационарный участок расчета - моделированная система выходит на стационарный участок, т.е. вычисляемые величины не зависят от входной функции (в моем случае - от времени, естественно условного времени, не связанного с таймерами и пр.).
2. Hardware отличное и не сбоит (по крайней мере нет внешних признаков).

Спасибо за ответы.



McSimm   (2002-02-22 16:02) [34]

Используются ли в программе обработка исключительных ситуаций?
try
...
except end;

Я имею в виду не может ли произойти исключение, которое вы не увидите.

Надо все-же попытаться переписать код, исключив из него сравнения величин с плавающей точкой на равенство. Это неправильно в любом случае, т.к. непредсказуемо будет ли, например, выражение 5/2 = 2.5 истинным или ложным. Есть вероятность, что истинность или ложность подобных конструкций зависит от посторонних факторов.

Возможно придется расставить в программе сохранение в файл величин в ключевых моментах вычислений. Это позволит сравнить такие файлы, полученные на разных машинах и локализовать место возникновения расхождения.



Юрий Зотов   (2002-02-22 16:17) [35]

> ...ошибка возникает именно на стационарном участке расчетов.

Насколько я понял, речь идет о решении системы дифф. уравнений. Если используется автоматический выбор шага, то обычно он выбирается как раз исходя из "машинных" привязок (эпсилон и т.п.), причем на стационарных участках шаг выбирается довольно большим и точность решения снижается (а при достаточно жесткой системе решение даже может начать "болтаться"). Это приводит к накоплению погрешности, а в итоге мы и получаем разные результаты на разных платформах.

Похоже, у Вас происходит что-то подобное. Попробуйте ограничить максимальную величину шага и/или повысить требования к точности.




VictorT   (2002-02-22 16:38) [36]

>т.е. вычисляемые величины не зависят от входной функции
А зачем они тогда вычисляются?



olookin   (2002-02-22 16:56) [37]

Уважаемые господа!

1. По поводу сравнений величин с плавающей точкой полностью согласен (особенно с примером 5/2=2.5) и попытаюсь убрать все такие случаи.
2. Обработки исключений стркутруой try ... except не производится.
3. Действительно, я решаю систему диф. уравнений (методом Эйлера - неявным). И дейстивительно, при изменении шага результат становится правильным (причем, при увеличении или уменьшении шага). НО, мне необходимо либо автоматически изменять этот шаг (без участия пользователя), либо менять алгоритм расчетов (не могу так как нужен быстрый расчет).
4. Моделирующийся процесс требует задания большого диапазона времени, в том числе и той части, где модель стационарна.

Большое спасибо за ответы.



Юрий Зотов   (2002-02-22 17:19) [38]

Похоже, диагноз угадан :о)

Я бы посоветовал использовать метод более высокого порядка с автоматическим выбором шага. Чем, скажем, RKF45 не подходит?



olookin   (2002-02-22 17:24) [39]

Уважаемые господа!

Теряясь в догадках, я сделал небольшую (и как кажется не имеющую значения модификацию) в программе. Именно, часть кода:

procedure Duplet1.Control_iso;
var k,c: integer;
begin
for k:=0 to 511 do for c:=0 to trunc(2.0/TT)-1 do Takt(0);
end;

заменяется на:

procedure Duplet1.Control_iso;
var k,c: integer;
begin
for k:=0 to 511 do for c:=0 to trunc(2/TT)-1 do Takt(0);
end;

Обратите внимание на то, что вместо величины 2.0 я использую 2.
Как это не смешно, результат работы программы СТАЛ ПРАВИЛЬНЫМ.



VictorT   (2002-02-22 17:41) [40]

Теперь обьясните мне, глупому, в чём тут дело. Я понимаю, что если бы это был Си, то компилятор 2 бы считал целым типом, а 2.0 вещественным. А Паскалю имхо, всё равно. Или нет?



DieHard   (2002-02-22 17:56) [41]

Вот именно, что так же не всё равно



olookin   (2002-02-22 18:32) [42]

т.Е. все-таки это может играть какую-то роль?



McSimm   (2002-02-22 18:49) [43]

В принципе может. Зависит от компилятора.
Но у меня для обоих вариантов компилятор сгенерировал абсолютно одинаковый код.



Digitman   (2002-02-22 18:52) [44]

именно при декларации
const TT = 0.1
- абсолютно - никакой разницы.
Проверено в Д5.5.

выражения 2.0/TT и 2/TT вычисляются на этапе компиляции, результат вычисления - целое число = $14 (как при включенном, так и при выключенном оптимизаторе)

т.е., цикл
for c:=0 to trunc(2/TT)-1 do ..
именно при такой декларации всегда выглядит как цикл
for c:=0 to 20 do ..



olookin   (2002-02-22 19:22) [45]


Значит никакой разницы нет?



McSimm   (2002-02-22 19:39) [46]

Если TT - константа, то разницы нет однозначно. Если только не имеет место ситуация, обсуждаемая в
EAlexander © (22.02.02 10:47)
McSimm © (22.02.02 12:19)
EAlexander © (22.02.02 12:23)


Если TT - вычисляемое, то разницы нет для моего компилятора (6.0 Build 6.163). Другой компилятор, возможно, воспримет эти записи по-разному




Страницы: 1 2 вся ветка
Форум: "Потрепаться";
Поиск по всему сайту: delphimaster.net;
Текущий архив: 2002.04.04;
Скачать: [xml.tar.bz2];




Наверх





Память: 0.84 MB
Время: 0.029 c
3-9422            vlad2                 2002-03-04 09:29  2002.04.04  
dBase


3-9379            KPOT                  2002-03-12 12:30  2002.04.04  
TIBDatabase iz DLL


1-9447            Fran                  2002-03-24 17:15  2002.04.04  
Нужен компонент типа TrxCalcEdit, но вместо цифр - английские буквы.


14-9635           AL Greko              2002-02-23 17:40  2002.04.04  
Помогите народ с работой с графикой!


14-9604           Olgerd                2002-02-21 20:25  2002.04.04  
BAT-файлы