InterBase & типа FLOAT

13 отговора 176 прегледа
#1

InterBase & типа FLOAT

C++ & Delphi

проблема е следния :

имам таблица X в която имам поле Y от тип FLOAT

при присвояване
....
S = "0.3249";
IBStoredProc->Params->Items[y]->AsFloat = StrToFloat(S);
...

в базата се записва числото 0.32490000128746
т.е. не се нулират последните 6 позиции в числото и при по нататашни изчисления имам проблем с точноста.

Някой има ли идея как се нулират тези послени позиции или как изобщо се решава този проблем.

благодаря предварително.

Отговор
в отговор на Efex #2

Re: InterBase & типа FLOAT

Ако искаш да работиш с числа с фиксирана точност ползвай NUMERIC()

Отговор
в отговор на NDeu #3

Re: InterBase & типа FLOAT

С NUMERIC нещата са още по зле защото при заявка :
..
X NUMERIC(15,6)
Y NUMERIC(15,6)
...
SELECT X * Y
...
се получава велик резултат от вида 14325245.31254

и спасението е SELECT CAST(X * Y AS FLOAT)
.....
но не си е работа....ако ме разбираш... :))))))))

Отговор
в отговор на Efex #4

Re: InterBase & типа FLOAT

От Что НЕ надо делать
20. Не надо использовать тип FLOAT
этот тип данных имеет длину 4 байта и точность всего 7 цифр. Эквивалентом в Delphi является single. Если хотите использовать вещественные числа, то сначала попробуйте перемножить и поделить два таких числа прямо в Delphi - так вы увидите точность вычислений, что исключит впоследствии проблемы с хранением и обработкой таких данных в базе.


вж. също
[линк]
[линк]

Редактирано от NDeu на

Отговор
в отговор на NDeu #5

Re: InterBase & типа FLOAT

ВСИЧКО ДОБРЕ НО!!!!!

ТБЛИЦА STOR;
//всички полета от NOMQNT1 до NOMPRICE3 са от тип NUMERIC(15,6)

IDSTOR | IDNOM | NOMQNT1 | NOMQNT2 | NOMQNT3 | NOMPRICE1 | NOMPRICE2 | NOMPRICE3

1 | 1 | 9 | 5 | 4 | 0.3 | 0.5 | 0.3


ПРИ UPDATE В КОНЗОЛАТА ИЛИ ЧРЕЗ IBQUERY :

=======================
UPDATE STOR
SET NOMQNT2 = NOMQNT2 + 5,
NOMPRICE3 = FORMATFLOAT( ( (NOMQNT1 + NOMQNT2 - NOMQNT3)*NOMPRICE3 + (5 * 0.43))/
((NOMQNT1 + NOMQNT2 - NOMQNT3)+5),4
),
NOMPRICE1 = 0.43
=======================
СЕ ПОЛУЧАВА РЕЗУЛТАТ NOMPRICE3= 0.3325 ?!?!?!?!?!?!?

<<<<<<<<<<>>>>>>>>>>>>>>

А ПРИ SELECT :
==================
select FORMATFLOAT( ( (NOMQNT1 + NOMQNT2 - NOMQNT3)*NOMPRICE3 +
(5 * 0.43)
)/((NOMQNT1 + NOMQNT2 - NOMQNT3)+5),4)
FROM STOR
==================
СЕ ПОЛУЧАВА РЕЗУЛТАТ 0.3433 КОЕТО Е КОРЕКТНИЯ РЕЗУЛТАТ !!!!!

дори и без използването на FORMATFLOAT положението е същото???

НЯКОЙ ЗНАЕ ЛИ ЩО ЗА ФЕНОМЕН Е ТОВА????

Всичко е зле когато завършва ЗЛЕ.

Отговор
в отговор на Efex #6

Re: InterBase &amp; типа FLOAT

Ами много просто - това не е феномен. Защо използваш FormatFloat и сигурен ли си, че някъде там не ти се объркват нещата? Изкарай си междинните резултати и виж къде ти се закръгля. Защо изобщо тези сметки ги правиш в SQL? Уверявам те, че в програмата също могат да се сметнат. Освен това изпълнения от вида s := '1.23456'; f := StrToFloat(s); нито са производителни, ното са точни. Не ти гарантирам, че StrToFloat ще ти върне 1.23456 а не примерно 1.2345597534232 или нещо такова...

Отговор
в отговор на Efex #7

Re: InterBase &amp; типа FLOAT

1. Този ФЕНОМЕН показва, че при update нe се гарантира изолираност на операциите.
След
NOMQNT2 = NOMQNT2 + 5,
в израза
NOMPRICE3 = ( (NOMQNT1 + NOMQNT2 - NOMQNT3)*NOMPRICE3 + (5 * 0.43))/((NOMQNT1 + NOMQNT2 - NOMQNT3)+5)
NOMQNT2 вече участва с новата си стойност.
Размени местата на NOMQNT2 и NOMPRICE3 в update-то и ще получиш каквото ти трябва.

2. Не препоръчвам използването на FORMATFLOAT в този случай. Просто не е необходимо

3. Не е добър стил ДА КРЕЩИШ ПО ФОРУМИТЕ. Говори за склонност към истерия Пък и трудно се чете

Успех

Отговор
в отговор на andrew_nikoloff #8

Re: InterBase &amp; типа FLOAT

andrew.....
не съм съгласен с теб !!!
т.е. << Защо изобщо тези сметки ги правиш в SQL? >>

Според теб защо изобщо съществува SQL ако не се използва едно от най силните му преимущества да спестиш 70% код от сметки!!!
//и това разбира се не е всичко но не мисля да споря на тази тема :)))
А и какъв е смилсъла да използвам SQL само за банка-данни
все пак благодаря за съдейтвието..

Отговор
в отговор на NDeu #9

Re: InterBase &amp; типа FLOAT

Very very 10x NDeu....

Разбира се почти винаги грешката е в питащия...
Наистина се оказа че "РЕДА" на изпълнение в UPDATE има значение което аз до сега не го знаех...

Относно крещенето .... не е точно това което си "видял"...:)))
част от навиците ми, е да пиша с големи букви... но не че не виждам и не че крещя... а просто навик...
// и аз не обичам да пушат около мен защото нямам навика да пуша :))))

Още веднъж много благодаря за помоща ти защото ми беше вери спешъл.....

но има още един не толкова "BIG" проблем...

========
X NUMERIC(15,6); //5
Y NUMERIC(15,6); // 0.43

заявка в QUERY :

SELECT X * Y ми връща 2 955.8141

а при

SELECT CAST(X * Y AS FLOAT) ми връща 2.1500 //което е вярното...


10x

Отговор
в отговор на Efex #10

Re: InterBase &amp; типа FLOAT

Не знам защо си мислиш, че ще спестиш 70% код от сметки, когато изнесеш сметките от по-високопроизводителна система като компилираната ти програма на делфи, в SQL заявката ти, която определено се изпълнява по-бавно, определено се поддържа по-трудно и определено като гледам ти е доста децентрализирана...
Много по-ясно и по-продуктивно, а и значително по-универсално за теб (а и от там по-кодоспестяващо) ще е вместо

UPDATE STOR
SET NOMQNT2 = NOMQNT2 + 5,
NOMPRICE3 = FORMATFLOAT( ( (NOMQNT1 + NOMQNT2 - NOMQNT3)*NOMPRICE3 + (5 * 0.43))/
((NOMQNT1 + NOMQNT2 - NOMQNT3)+5),4
),
NOMPRICE1 = 0.43

да си напишеш

update stor set
nomqnt1 = :nomqnt1,
nomqnt2 = :nomqnt2,...

и да си използваш сметките в ехе-то или поне в сторедпроцедура, отколкото да пишеш магически изрази като горния, които дори ти не успя да разбереш какво всъщност вършат.

А по-въпроса за или против използването на SQL само за банка-данни (предполагам всъщност имаш предвид ползването на базата данни само за банка данни, защото не виждам как можеш да съхраниш каквито и да е данни в SQL) - бизнес логиката не се съхранява в базата данни под формата на SQL заявки, записани в пропъртитата на Query-то ти е делфи, а като сухранени процедури, тригери и други подобни неща в самата база например...

Отговор
в отговор на andrew_nikoloff #11

Re: InterBase &amp; типа FLOAT

Казах че не искам да влизам този спор за SQL и сметки но се изкушавам да ти отговоря :

БЕСПОРНО :
========
update stor set
nomqnt1 = :nomqnt1,
nomqnt2 = :nomqnt2,...
========
е много по кратко но как се стига до :nomqnt1 и :nomqnt2 не си написал...

не се имам за велик програмист но аз разполагам с едно ID и два параметъра ":nomqnt1/2" и си свършвам работата само с една заявка ... а иначе ако се придържам към твоя съвет трябва да направя следното

1.Да извлека полетата които ми трябват за сметката със заявка...
т.е ( NOMQNT1/2/3 ,, NOMPRICE1/3 )
2.Да си декларирам още n променливи за горните полета
3. Да натоваря клиентския процесор със сметки вместо сървъра
// според мен идеята е сървъра да се товари и се предполага че клиента е слаб //
4.Да направя нова заяква за UPDATE
// до тук комуникациите станаха 2 ...


Не мисля че някой от нас двамата е по ПРАВ защото всеки си има стил и виждане за програмиране но ще се радвам да науча и нещо ново от теб...

и все пак аз все още преоткривам SQL-а така че ако греша ще се радвам да ме поправите....:)))

Отговор
в отговор на Efex #12

Re: InterBase &amp; типа FLOAT

А прочете ли частта за съхранените процедури?

CREATE PROCEDURE UPDATE_STORE_WITH_NEW_QUANTITY(StoreID Integer, NewQuantity Double Precision)
AS
BEGIN
....

На това се вика бизнеслогика в базата... 1 комуникация.... 1 място.... Лесна поддръжка...

Отговор
в отговор на Efex #13

Re: InterBase &amp; типа FLOAT

>SELECT X * Y ми връща 2 955.8141
Грешката е на клиента, който ползваш (вероятно IBConsole). Физическото представяне на този тип е Int64, а по-старите клиенти не умеят да работят добре с него.
Workaround:
1. За да нямаш подобни проблеми cast-вай до char. Тогава интерпретирането го прави сървъра, а клиента си работи само със символи.
2. Смени си клиента. На мен ми допада IB Expert.

Отговор
в отговор на NDeu #14

Re: InterBase &amp; типа FLOAT

Ок .
имам и двата клиента и също предпочитам братушките
но в момента съм с конзолата и забелязвам че се пръкват тук там и други бъгчета :)))

ше направим един drop на конзолата...

10x

Отговор