![]() |
| ||
|
|
Новости |
Поиск |
FAQ |
Статьи |
Книги |
Новости VCL
| | Форумы ЧАТ |
Орешник |
|
| |||
| |||
« предыдущая ветвь | форум | следующая ветвь »
Принтер "портит" выполнение программы? [D2005, XP]
Abcdef123 © (2010-12-22 06:31:00)Здравствуйте, Мастера. Заранее извиняюсь, если мой вопрос послан не по теме данного форума.
Столкнулась с такой проблемой. Программа очень давняя, работала нормально, проблема возникла только у клиента сейчас, когда они купили новый принтер (HP). В одном месте программы дает ошибку Number out of range. Если проигнорировать ошибку и попробовать запустить то же самое (не перезагружая проект), то второй раз выполняется номально. Со старым принтером вообще нормально работает!!!
Вот сейчас детали:трассировка ошибки показала место, где получается "большое" число. В процедуре объявлена переменная типа Currency и ей присваивается некое значение, вычисляемое по формуле, на основе данных таблицы. Так вот, первый раз похоже значение это не вычисляется (это я так полагаю), поскольку интересное значение этой переменной получается: –922337203685477.5808 (то есть минимальное значение, которое может иметь этот тип). Знаний насчет драйвера принтера у меня недостаточно. Вот и думаю, возможно ли, что драйвер принтера каким то образом "портить" программу? И если да, то каким образом второй раз ошибки нет, присваивается нужное рассчитанное значение этой переменной. Пожалуй, на этом описание закончу, если что-то нужно подробнее сообшить - спросите. Возможно, что кто-то встречался с подобной проблемой. Может я вообще не там ищу причину? Буду рада любому дельному совету. Заранее спасибо!
12 (2011-01-18 16:21:00) [1]еще раз тему перечитал - тогда так: Компьютер портит.
Без компьютера же программа не лажает?!
Вот.. :)
А чтоб программа не лажала - ее надо отлаживать (с)
12 (2011-01-18 15:51:00) [2]да-да
var
R:Single;
begin
R:=0.1;
if R=0.1 then
Label1.Caption:='Равно' else
Label1.Caption:='Не равно'
end;
При нажатии кнопки мы увидим надпись «Не равно». На первый взгляд это кажется абсурдом.
(с) Антон Григорьев
из этой же серии, имхо
Amoeba_ (2011-01-18 11:47:00) [3]
> Григорьев Антон, "Невероятные особенности вещественных чисел"
> , как-то так, гуглите, короче
Неочевидные особенности вещественных чисел
http://www.delphikingdom.com/asp/viewitem.asp?catalogid=374
12 (2011-01-18 09:48:00) [4]
> когда
> в функции идет деление на ноль, то программа не идет на
> except, а присваивает результату вот такое больше разрядное
> значение.
Вероятно, там не 0, а несколько больше(меньше).
function CalcProportionAsAmount(rlTotal, rlSubTotal, rlAmount : Currency) : Currency;
const
Eps = 0.0001;
begin
try
if (rlTotal > Eps) then
result:= rlAmount * (rlSubTotal / rlTotal)
else
result:= 0;
except
result:= 0;
end;
end;
Григорьев Антон, "Невероятные особенности вещественных чисел" , как-то так, гуглите, короче
Abcdef123 (2011-01-18 08:50:00) [5]Здравствуйте, Мастера.
Докладываю - наконец-то у клиента всё протестировали, но, ничего не помогло. Проблема существует.
А вот, что произошло на моем компе! Как я писала, что у меня на компе программа работает нормально.
Но, как только я протестировала идею [19], у меня вылетает такая же ошибка! Хотя предложение использовать asm FINIT end; должно бы наоборот - помочь!
Я прошла пошагово, и нашла, что когда
в функции идет деление на ноль, то программа не идет на except, а присваивает результату вот такое больше разрядное значение.
Если я добавлю перед применением формулы проверку на ноль, то ошибки нет.
В общем, чтобы уж точно было понятно привожу описываемые варинты: работаютщие:
function CalcProportionAsAmount(rlTotal, rlSubTotal, rlAmount : Currency) : Currency;
begin
try
result:= rlAmount * (rlSubTotal / rlTotal);
except
result:= 0;
end;
end
function CalcProportionAsAmount(rlTotal, rlSubTotal, rlAmount : Currency) : Currency;
begin
asm FINIT end;
try
if rlTotal <> 0 then
result:= rlAmount * (rlSubTotal / rlTotal)
else
result:= 0;
except
result:= 0;
end;
end
А ЭТО НЕРАБОТАЮЩИЙ:
function CalcProportionAsAmount(rlTotal, rlSubTotal, rlAmount : Currency) : Currency;
begin
asm FINIT end;
try
result:= rlAmount * (rlSubTotal / rlTotal);
except
result:= 0;
end;
end
На моем компе я проверяю с моим принтером. То есть всё также много вопросов - всё те же.
Прошу прокомментировать.
Ega23 (2010-12-24 06:20:00) [6]
> вы за использование использование проверки на нуль или
> за использование except?
Дурная постановка вопроса.
Abcdef123 (2010-12-24 05:54:00) [7]To [40]: Красиво написано, но не поняла, вы за использование использование проверки на нуль или за использование except?
han_malign (2010-12-23 12:35:00) [8]
> Не всё так просто
- с currency - просто(ε=0.0001)
>> А деление проверяется на зеро заранее.
> ты не погорячился?
- подразумевался пост 12 © (23.12.10 10:20) [30], и тут надо исходить из вероятности возникновения ситуации...
Если это исключительная, крайне редкая ситуация - то лишнее ветвление(не убирающее необходимости защищенной секции) - избыточно.
Но учитывая:
> {Здесь некотовый код, определены значения переменных rlBase, rlMulti, rlBaseDM, rlMultiDM. Кстати, значение rlBaseDM, rlMultiDM порой бывают равны нулю}
- ситуация вполне нормальная, и ветвление обосновано, т.к. нормальные входные данные не должны порождать исключение(которое дает значительное пенальти производительности)...
12 (2010-12-23 11:21:00) [9]Raise; - ну тут варианты..
12 (2010-12-23 11:19:00) [10]вообщем, я б так написал
function TryCalcProportionAsAmount(const rlTotal, rlSubTotal, rlAmount : Currency; var MyResult: Currency) : Boolean;
begin
Result := true;
try
if rlTotal <> 0 then
MyResult := rlAmount * (rlSubTotal / rlTotal) else
MyResult := 0;
except
result:= false;
Raise;
end;
end;
....
if TryCalcProportionAsAmount(блаблабла, Variable) then
Do(Variable);
Ega23 (2010-12-23 11:12:00) [11]
> А деление проверяется на зеро заранее.
Не всё так просто
brother (2010-12-23 11:12:00) [12]> А деление проверяется на зеро заранее.
ты не погорячился?
try там вполне подходит...
12 (2010-12-23 11:10:00) [13]
> Range Check Error
> currency(1E13)/0.0001
так это надо оставить для обработчика выше,
чтоб потом не ломать голову откуда такие числа при прогоне.
А деление проверяется на зеро заранее.
han_malign (2010-12-23 11:01:00) [14]
> ну так и писать надо
> if rlTotal <> 0 then ...
> else Result := 0;
- а вот тут ты не совсем прав - currency(1E13)/0.0001, хотя это конечно экстремальный случай...
Ega23 (2010-12-23 10:54:00) [15]
> а какой тут Except?
> кроме /0
Divizion By Zero
Range Check Error
Abcdef123 (2010-12-23 10:52:00) [16]To [31]: Огромное спасибо за ответ. Мне это было важно знать! Теперь спокойно не боясь за последствия могу это использовать!
han_malign (2010-12-23 10:40:00) [17]
> Если остается, то я боюсь, а вдруг это сбрасывание повредит работу других приложений у клиента?
- нет, состояние процессора/сопроцессора изменяется только в контексте текущего процесса/потока(при переключении между потоками состояние регистров сохраняется и соответственно восстанавливается).
Но некоторые нехорошие драйвера и/или сторонние библиотеки, к которым ваше приложение явно или неявно(например они могут цеплять system-wide hook-и, а сейчас еще каждая собака балуется rootkit-ами(из лучших побуждений конечно)) обращается - могут запарывать состояние регистров именно в контексте вашего процесса...
12 (2010-12-23 10:20:00) [18]кстати
try
rlPercent := (rlSubTotal / rlTotal);
except
rlPercent := 0;
end;
а какой тут Except?
кроме /0
ну так и писать надо
if rlTotal <> 0 then ...
else Result := 0;
12 (2010-12-23 10:17:00) [19]Поставить левый принтер. из стандартных, назначить печать в файл, напечатать.
Ошибка повторилась?
showmessage все параметры в CalcProportionAsAmount(rlTotal, rlSubTotal, rlAmount
или числитель большой или знаменатель маленький
Abcdef123 (2010-12-23 07:54:00) [20]To [27]. Почему? А что на [24] вопрос никто не знает ответа?