Страница 1 из 1
не правильно работает округление с Double Precision
Добавлено: 01 июл 2005, 10:08
break
У меня в базе есть UDF:
**************
function R_RoundTo(aValue: PDouble; aDigit: PInteger): Double; cdecl; export;
begin
Result := RoundTo(aValue^, aDigit^);
end;
**************
Если при передаче параметров тип переменной отличный от Numeric, то округление происходит неверно - а именно число на входе в процедуру приводится к числу с тремя знаками, то есть указываем в хранимой процедуре просто R_ROundTo(20.8335, -3) - все работает - округляет 20.834, если сделать то же через переменную:
Value Double Precision
...
Value = 20.8335;
...R_RountTo(Value, -3)...
...
Уже не будет работать - выдаст 20.833 и если константа смешивается с переменной тоже не работает - только если все выражение преобразовать к Numeric(15,10) , все это имеет место как ч понял только в хранимых процедурах - если вызывать функцию просто в запросе, то работает даже если передаваемый параметр заведомо преобразовать к Double Precision
Что делать??? У меня база в которой уже ведется работа и там много полей Double Precision а не Numeriс!!!
Добавлено: 03 июл 2005, 18:39
kdv
если претензии к функции - то возьми ее да отладь в Delphi. как это делать, описано в статье Кукарцева.
!!!!!!!
Добавлено: 04 июл 2005, 09:24
break
Я ЖЕ СКАЗАЛ НА ВХОДЕ В ПРЦЕДУРУ - КАК ОНА РАБОТАЕТ В ДЕЛФИ ЭТО УЖЕ ВТОРОЙ ВОПРОС СЕЙЧАС Я ДЕЛФИ НАПИСАЛ СВОЮ ПРОЦЕДУРУ, НО ЕСЛИ ПРИ ПЕРЕДАЧЕ ПАРАМЕТРОВ В ХРАНИМОЙ ПРОЦЕДУРЕ ИСПОЛЬЗОВАТЬ НЕ ЧИСЛОВЫЕ КОНСТАНТЫ И НЕ NUMERIC А НАПРИМЕР КОНСТАНТЫ СМЕШАННЫЕ С NUMERIC ИЛИ СМЕШАННЫЕ С DOUBLE PRECISION ИЛИ ПРОСТО DOUBLE PRECISION - то уже на входе в процедуру число неправильно округлено до тысячных - какого хрена оно там окгругляется вообще непонятно!!! Сейчас я везде в ХП перед передачей в процедуру округления присваиваю выражение которое нужно округлить в переменную NUMERIC - но это ж костыль а не панацея!! ЕЩЕ РАЗ ПОВТОРЯЮ - НА ВХОДЕ В ПРЦЕДУРУ ДЕЛЬФЕ ПЕРЕМЕННАЯ ПОПАДАЕТ ОКРУГЛЕННОЙ!!! ВОПРОС - КАКОГО ХРЕНА ОНА ОКРУГЛЯЕТСЯ - неявная особенность Interbase или ГЛЮК - а может я чего не знаю где-то устанавливается способ округления чисел. С числами приведенными в первом примере можете сами проверить - очень наглядно!!!
Добавлено: 04 июл 2005, 10:38
kdv
и чего так кричать? кто тебя знает, какой тип в результате ты передаешь в функцию. про numeric в третьем диалекте читал? Ну и ...
если думаешь что баг или не понимаешь в чем дело - опиши конкретный пример, с sql.
пример в SQL
Добавлено: 05 июл 2005, 10:36
break
Функцию R_RountTo можно брать любую - все равно результат меняется до нее, я сейчас использую не стандартную делфи, а свою которая округляет в большую сторону если 5 и в меньшую если до 5:
Фрагмент процедуры SQL:
as
ReturnValue DoublePrecision;
begin
...
ReturnValue = R_RountTo(20.8335, -3)...
...
end
/* так все работает в ReturnValue будет 20.834*/
as
Value Numeric(15,10);
ReturnValue DoublePrecision;
begin
...
Value = 20.8335;
ReturnValue = R_RountTo(Value, -3)...
...
end
/* так тоже в ReturnValue будет 20.834*/
as
Value DoublePrecision;
ReturnValue DoublePrecision;
begin
...
Value = 20.8335;
ReturnValue = R_RountTo(Value, -3)...
...
end
/* так не работает !!!! ReturnValue будет 20.833 - причем это значение уже на входе процедуры UDF */
Добавлено: 05 июл 2005, 11:42
kdv
Нехрен мешать целочисленные типы и вещественные.
Value = 20.8335;
опять не то. 20.8335 это numeric(6,4). Напиши
cast 20.8335 as double precision. В общем, см. выше - не смешивай целочисленную и вещественную арифметику, и все будет ОК.
Добавлено: 05 июл 2005, 12:01
break
как раз в том члучае который вы процетировали - все работает, а вот если использовать Double Precision - то не работает, я же подробно 3 примера описал, кстати если использовать Numeric(15, 10) - то никакого преобразования не происходит - точнее оно касается только 11 знака после запятой - а именно число округляется до 10 знака, СОВЕРШЕННО ТОЧНО что с Numeric(15, 10) все ОК, а вот Double Precision - не раб, что меня и удивило - изначально у меня в процедурах вообще не было Numeric(15, 10) - это уже после выявления непонятностей с округлением, так что мне нечего было мешать, или что нельзя мешать Double Precision - c целыми константами?, разве результирующее выражение не должно быть Double Precision? (... Value Double Precision ... Ret = Value * 1.5 *1.01)
Но даже если не мешать не работает даже если просто передавать переменную Double Precision причем только в ХП. Например если в IBExpert в построитель запросов передавать след SQL:
/***/
select r_roundto(20.8335, 3)
from ANY_TABLE
where 1 = 1
/***/
/***/
select r_roundto(cast(20.8335 as double precision), 3)
from ANY_TABLE
where 1 = 1
/***/
/***/
select r_roundto(cast(20.8335 as numeric(15,10, 3)
from ANY_TABLE
where 1 = 1
/***/
то во всех случаях ВСЕ РАБОТАЕТ htpekmnfn 20.834
Добавлено: 06 июл 2005, 10:13
break
Так я не пойму примеры данные в Посте кто-то проверяет или в виде ответов можно получить только - советы делай так-то и так-то - и все будет ОК! До сих пор - нет ответа по теме!!! даже намека!
Добавлено: 06 июл 2005, 12:06
Merlin
Нет, никто не проверяет. Потому что
а) все знают разницу между числами и арифметиками с плавающей и фиксированной точками, а также в чём разница округления по Гауссу и по церковно-приходской школе и какое выполняет сопроцессор.
б) никто не знает (и не интересуется) как и что ты округляешь в своей УДФ, тыкая ей на вход разные типы и включая этим неявные преобразования типов IB/FB, порядок выполнения которых зависит от порядка следования операндов в выражении и действующие по-разному для чисел с фиксированной и плавающей точкой.
Для общего развития очень рекомендую
http://www.delphikingdom.com/asp/viewit ... /reals.htm
Добавлено: 06 июл 2005, 12:58
kdv
Так я не пойму примеры данные в Посте кто-то проверяет
проверяю. использую round из rfunc.
Код: Выделить всё
CREATE PROCEDURE A
RETURNS (
RETVAL DOUBLE PRECISION)
AS
DECLARE variable val double precision;
begin
val=20.8335;
retval=round(val, 3);
suspend;
end
возвращает 20.834.
если вместо retval = round
написать retval = val, вернет 20.8335.
я правильно проверил? FB 1.5.2
Добавлено: 06 июл 2005, 13:09
kdv
и опять же.
Если при передаче параметров тип переменной отличный от Numeric, то округление происходит неверно
функция принимает double. объявлена наверняка как double. Но - ты в нее передаешь и double и numeric. Зачем? Это, как бы, повтор вопроса про смешивание целочисленной и вещественной арифметики.
function R_RoundTo(aValue: PDouble; aDigit: PInteger): Double; cdecl; export;
"я худею от радио ..."
почему нельзя написать
R_RoundTo(var AValue: double; var aDigit: PInteger).
? чего это за выкрутасы с приемом каких-то указателей... по человечески нельзя?
!!!
Добавлено: 07 июл 2005, 09:36
break
Во первых огромное спасибо за то что помогли разобраться, оказывается в Interbase имеет значение порядок множителей - то есть влияет на конечный результат. Как именно происходит преобразование типов в зависимости от порядка множителей - например в следующей процедуре:
CREATE PROCEDURE A
RETURNS (
QNT_NORM DOUBLE PRECISION,
QNT_PRODUCT DOUBLE PRECISION,
RAW_PERCENT DOUBLE PRECISION)
AS
begin
RAW_PERCENT = 4.1667;
QNT_PRODUCT = 500;
QNT_NORM = QNT_PRODUCT * RAW_PERCENT * 0.01;
/* QNT_NORM = 0.01 * QNT_PRODUCT * RAW_PERCENT;*/
/*в этой строке после перестановки множителей - результат 20.833*/
QNT_NORM = r_roundto(QNT_NORM, 3);
suspend;
end
Почему - именно после передачи параметров в UDF - происходит преобразование, ведь если не вызывать UDF - в обоих случаях результат будет одинаков. (20.8335) - Видимо меняется какой то бит - воторый означает конечный тип числа?
И еще - могу ли я вместо UDF для округления использовать присваивание из Double Precision в Numeric (в Numeric(15,3) - для округления до тысячных) - значение при этом округляется правильно, есть ли какие то особенности?
Добавлено: 07 июл 2005, 15:47
break
господа так как влияет на конечный тип перестановка множителей в выражении??? Очень интересно - мне же с этим работать
Добавлено: 07 июл 2005, 16:14
Merlin
На конечный - никак. На тип промежуточных результатов влияет в третьем диалекте. В твоём примере одни даблы, так что типы ни при чём. А при чём то, что в статье, которую я тебе рекомендовал, написано про плавающую точку.
Добавлено: 07 июл 2005, 16:55
kdv
Очень интересно - мне же с этим работать
если работать, то используй или только double, или только numeric, и не парь мозги. про особенности вещественных чисел тебе сказали, дали ссылки, да и на сайте есть нечто вроде статьи. Про numeric тоже есть английская статья, где преобразования тоже описаны. все в разделе "статьи".