|
|
|
Cравнение Double Precision
|
|||
|---|---|---|---|
|
#18+
есть две хранимые процедуры, одна получает стоимость заказа, вторая оплаченную часть стоимости (данные хранятся в разных таблицах), в отчете необходимо вывести все частично или не оплаченные заказы. Т.е. необходимо произвести сравение выходных результатов обоих процедур на не совпадение, и если данные не равны - показать. Всё вроде бы просто, но почему-то иногда отображаются даже те заказы у которых сумма заказа и сумма оплаты полностью совпадают! Делаю проверку: SELECT OrderCost.summa, OrderPayment.Summa FROM OrderCost(166), OrderPayment(166) WHERE OrderCost.summa <> OrderPayment.Summa И чтоже? в ISQL вижу строчку с двумя полями - полностью идентичными! (121839.98 <> 121839.98) Вопрос, каким образом возможна такая ситуация? Выходные параметры обоих процедур имеют тип DOUBLE PRECISION... Примерно 1,2 заказа из 100 не проходят проверку, остальные - нормально. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.11.2003, 10:06 |
|
||
|
Cравнение Double Precision
|
|||
|---|---|---|---|
|
#18+
ИМХО дело в округлениях. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.11.2003, 10:17 |
|
||
|
Cравнение Double Precision
|
|||
|---|---|---|---|
|
#18+
Надо делать примерно так: SELECT OrderCost.summa, OrderPayment.Summa FROM OrderCost(166), OrderPayment(166) WHERE ABS(OrderCost.summa-OrderPayment.Summa)>=0.01 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.11.2003, 10:31 |
|
||
|
Cравнение Double Precision
|
|||
|---|---|---|---|
|
#18+
Acue никаких округлений я не делаю, да и Interbase тоже, т.к. чтобы получить число 121839.98 первая процедура пробегается по нужным таблицам и последовательно складывает: 15000+1000+20000+35156.85+7886+28677 тоесть никаких тысячных значений! (проверял всеми возможными способами :) Вторая хп в данном случае вообще ничего не складывает. Опять же, все поля во всех таблицах хранящих данные значения - double. Могун спасибо, это стало решением проблемы... Но вопрос всё-таки остается, или у Interbase что-то не в порядке с математикой или одно из двух ? ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.11.2003, 20:38 |
|
||
|
Cравнение Double Precision
|
|||
|---|---|---|---|
|
#18+
2 svtech DOUBLE PRECISION - формат с плавающей запятой. Числа такого типа нельзя сравнивать равенством, а только так как Могун написал. Для хранения денежных величин лучше использовать NUMERIC, это числа с фиксированой запятой, их можно сравнивать равенством. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 17.11.2003, 22:02 |
|
||
|
Cравнение Double Precision
|
|||
|---|---|---|---|
|
#18+
S.G. NUMERIC всего лишь виртуальный тип данных с фиксированной точностью, который в реальности переводит число в вещественный(действительный) DOUBLE PRECISION А то, что два действительных числа нельзя сравнить - это что то новое, так как действительные числа являются простыми числами, а значит для них применимы операции сравнения = и <> вот пример: var a: double; begin a:=0.01; if a=0.01 then showmessage('=') else showmessage('<>'); end; Ответ будет <>, потому что число в переменной А получает погрешность... а вот другой пример: var a,b: double; begin a:=0.01; b:=0.01 if a=b then showmessage('=') else showmessage('<>'); end; Здесь ответ будет = Делаем простые выводы - нельзя сравнивать переменные веществнных типов с константами, только с такими же переменными. Отсюда следует, что запрос select .... OrderCost(x).summa <> OrderPayment(x).summa должен, и просто обязан работать корректно. Вот если бы вместо одного из операндов стояло дробное число, тогда можно было бы объяснить ошибку. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.11.2003, 17:02 |
|
||
|
Cравнение Double Precision
|
|||
|---|---|---|---|
|
#18+
Теория конечно же красивая, но на практике происходит все иначе. Я тоже много раз сталкивался с такой проблемой и сделал вывод: НЕЛЬЗЯ СРАВНИВАТЬ НАПРЯМУЮ ВЕЩЕСТВЕННЫЕ ЧИСЛА. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.11.2003, 18:14 |
|
||
|
Cравнение Double Precision
|
|||
|---|---|---|---|
|
#18+
S.G. можно или нельзя с этим я уже разобрался, интересует другое - почему так происходит? как я уже говорил, у меня например только ~2% значений не сравниваются... Интерес к теме заставил меня выполнить еще пару тестов: Тест № 1: создаем таблицу с тремя полями a,b,c: double precision последовательно заносим туда 10.000 строк: a=0.1*i/10; b=0.1*i/10; c=a+b; это приводит к тому что в полях а и b числа от 0.01 до 100.00, в С соотв. от 0.02 до 200.00 выполняем sql запрос: select count(*) from test where c=a+b результат - 10.000 !, т.е все суммы сошлись. Тест № 2: всё остается точно так же, только с=StrToFloat(FloatToStr(a+b)) выполняю тот же запрос, результат - 7194.... тоесть 28% чисел не сошлось, по пока что непонятной мне причине :) 7,11,14,17,21,22,23,28,33 ... и т.д. числа не сходились, ясно что здесь есть опр.последовательность... (примечание: в обоих тестах select * from test показывал мне все 10.000 записей и ВИЗУАЛЬНО ТАБЛИЦЫ - НИЧЕМ НЕ ОТЛИЧАЛИСЬ) С уверенностью можно сказать только две вещи - 1) сравнивать вещественные числа напрямую можно и нужно ! 2) после применения любых функций форматирования таких чисел их уже нельзя заносить в базу данных, массивы или еще какие структуры, т.к. они будут уже не "настоящие" double, иначе говоря сравниваться они нормально не будут, хотя и выглядят как настоящие :). Признаюсь честно, сам использовал форматирование, каюсь, каюсь...... ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.11.2003, 19:55 |
|
||
|
Cравнение Double Precision
|
|||
|---|---|---|---|
|
#18+
2 svtech вообще-то полезно иногда читать литературу :) Напрямую сравнивать вещественные числа (на равенство) _нельзя_, это объясняется в любом учебнике по программированию. Найдите раздел про двоичное представление чисел и обратите внимание на двоичное представление десятичных дробей (типа 0.1, 0.2) Относительно: "NUMERIC всего лишь виртуальный тип данных с фиксированной точностью, который в реальности переводит число в вещественный(действительный) DOUBLE PRECISION " то это не так. Вот выдержка из Interbase 6.0 Data definition Guide: DOUBLE PRECISION 64 bits a 2.225 x 10–308 to 1.797 x 10308 IEEE double precision: 15 digits NUMERIC (precision, scale) Variable (16, 32, or 64 bits) • precision = 1 to 18; specifies exactly precision digits of precision to store • scale = 0 to 18; specifies number of decimal places and must be less than or equal to precision • Number with a decimal point scale digits from the right • Example: NUMERIC(10,3) holds numbers accurately in the following format: ppppppp.sss как видно, между этими типами - две большие разницы. ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 18.11.2003, 22:36 |
|
||
|
Cравнение Double Precision
|
|||
|---|---|---|---|
|
#18+
S.G. конечно, хранить бесконечное число невозможно, поэтому в двоичном или еще каком виде оно будет урезанным, но число например 0.1 вещественное можно сравнить с таким же вещественным 0.1 И вообще, давайте говорить не о возможности или не возможности сравнения, а о появлении погрешностей и потери точности, и что самое главное - в каких случаях они возникают. Сравнивать то можно, и никакие правила это не запрещают. Если бы это было не так, компилятор бы выдавал ошибку при попытке произвести подобное действие, или же в 100% случаев мы получали бы несовпадения! это же простая логика. Например сумма вещ. чисел ни при какой ситуации не может дать бесконечное число знаков после запятой (если оба числа естественно не бесконечные). А значит представлятся в памяти компьютера она должна нормально, значит и сравнение её с другими такими же числами не приведет к потере точности (пример теста №1). Чтобы использовать double precision в бух. системах необходимо корректно вводить данные и следить за правильностью кода, или использовать Numeric(15,2), котороый эту работу берет на себя. Почему лично я ипользовал тип double - потому что книжки читаю :)) (Мир Interbase, издание 2, стр.20) Ситуация с преобразованиями типов тоже понятна. На примере предыдущих тестов Функции FloatToStr и StrToFloat работают с типом Extended, который имеет более высокую точность чем double, поэтому при приведении числа добавляются "левые" цифры... Информация о том что типа NUMERIC , как в прочем и DECIMAL не существует вообще - взята с сайта www.ibase.ru (Округление вещественных чисел), в действительности есть только smallint, integer, float и double precision. Почему то я этому верю, а из выдержки справки по interbase по-моему совершенно не следует что тип NUMERIC не приводит числа к одному из четырех перечисленных выше... Кстати разрядность double precision тоже 18 знаков, а не 15 ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.11.2003, 12:11 |
|
||
|
Cравнение Double Precision
|
|||
|---|---|---|---|
|
#18+
2 svtech >> конечно, хранить бесконечное число невозможно, поэтому в двоичном или еще каком виде оно будет урезанным, но число например 0.1 вещественное можно сравнить с таким же вещественным 0.1 И вообще, давайте говорить не о возможности или не возможности сравнения, а о появлении погрешностей и потери точности, и что самое главное - в каких случаях они возникают. Сравнивать то можно, и никакие правила это не запрещают. ------- Можно, но увы, результат нам не понравится. Здесь неплохое объяснение: http://ltwood.hotbox.ru/scipro/float.htm http://www.delphikingdom.com/helloworld/reals.htm >>Почему лично я ипользовал тип double - потому что книжки читаю :)) (Мир Interbase, издание 2, стр.20) ----- да, там сказано: "если в базе данных предполагается хранить числа с плавающей точкой, (напр. в бухг.системах или в с-мах для научных расчетов) то лучшим выбором будет Double precision." вероятно, подразумевается, что мы _уже_ решили что нам потребуются именно числа с плавающей точкой. Тогда выбираем double precision. Но, если мы хотим получать корректное сравнение на равенство, то надо еще прочитать стр.21, а также 22 вверху, где говорится о целочислености представления Numeric, а потом написано: "рекомендуется хранить данные о денежных средствах в БД, созданых диалектом 3 с использованием механизма INT64". Кстати, спасибо за напоминание о книжке, я тоже перечитал эти страницы еще раз :)) >>Информация о том что типа NUMERIC , как в прочем и DECIMAL не существует вообще - взята с сайта www.ibase.ru (Округление вещественных чисел), в действительности есть только smallint, integer, float и double precision. Почему то я этому верю... -------- выходит, что преобразование numeric в double precision было характерно для диалекта 1 (т.е. в очень старых версиях IB) Сегодня этот диалект поддерживается только для совместимости. Рекомендуется диалект 3. Желаю успехов! ... |
|||
|
:
Нравится:
Не нравится:
|
|||
| 19.11.2003, 22:54 |
|
||
|
|

start [/forum/topic.php?fid=40&msg=32328044&tid=1579627]: |
0ms |
get settings: |
10ms |
get forum list: |
9ms |
check forum access: |
2ms |
check topic access: |
2ms |
track hit: |
232ms |
get topic data: |
8ms |
get forum data: |
2ms |
get page messages: |
46ms |
get tp. blocked users: |
1ms |
| others: | 270ms |
| total: | 582ms |

| 0 / 0 |
