Страница 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 тоже есть английская статья, где преобразования тоже описаны. все в разделе "статьи".