Сумма с плавающей точкой в ​​SQL Server должна давать значение 1, но фильтр говорит иначе - PullRequest
4 голосов
/ 20 марта 2012

У меня есть таблица с типом данных поля, установленным в значение float.значения для данного набора записей должны давать сумму 1, а поле выбора возвращает 1, однако, предложение HAVING указывает иное.

Вот точные значения, которые у меня есть в моей таблицеМожно видеть, этот пример делает то же самое.Почему эта сумма составляет более 1?Я потерян!

with example as (
    SELECT 'Code' as Code, cast(0.462 as float) as perc
    UNION ALL
    SELECT 'Code' as Code, cast(0.116 as float) as perc
    UNION ALL
    SELECT 'Code' as Code, cast(0.181 as float) as perc
    UNION ALL
    SELECT 'Code' as Code, cast(0.053 as float) as perc
    UNION ALL
    SELECT 'Code' as Code, cast(0.188 as float) as perc
)

SELECT 
    Code,
    SUM(perc)
FROM
    example
GROUP BY Code
HAVING SUM(perc) > 1

Ответы [ 2 ]

8 голосов
/ 20 марта 2012

Я думаю, что вы неправильно понимаете поплавки.Я не имею в виду, что, к сожалению, большинство людей неправильно понимают числа с плавающей запятой.

Числа с плавающей запятой могут сами «масштабироваться».Возможность хранить огромные числа или крошечные числа в одном и том же типе данных.Это не значит, что они «бесконечно точны».Это просто означает, что у них есть экстремальный диапазон, который они могут охватить.Они, однако, платят цену за эту гибкость.У них есть ошибка округления из-за того, что они представляют собой двоичные аппроксимации десятичных чисел.

Если вы хотите узнать об этом больше, в Интернете есть много информации.Сначала это портит головы людей, но как только ты поймешь, ты станешь лучше, безопаснее и мудрее.

Итак, если вы хотите сохранить точное значение, не используйте тип данных с плавающей запятой.Вместо этого используйте тип данных с фиксированной запятой.

Если вы измените значение с FLOAT на что-то вроде DECIMAL(9,4), вы не получите ошибок округления, связанных с числами с плавающей запятой.

Вы выигралино вы не сможете хранить 0.12345, для этого вам нужно будет указать DECIMAL(9,5).Но вам всегда будет гарантировано, что любое число, которое вы можете сохранить в нем, будет сохранено точно, а не приблизительно.

3 голосов
/ 20 марта 2012

Поскольку FLOAT это не точный числовой тип, поэтому существуют приближения с плавающей запятой.Попробуйте использовать DECIMAL или NUMERIC:

with example as (
SELECT 'Code' as Code, cast(0.462 as NUMERIC(5,3)) as perc
UNION ALL
SELECT 'Code' as Code, cast(0.116 as NUMERIC(5,3)) as perc
UNION ALL
SELECT 'Code' as Code, cast(0.181 as NUMERIC(5,3)) as perc
UNION ALL
SELECT 'Code' as Code, cast(0.053 as NUMERIC(5,3)) as perc
UNION ALL
SELECT 'Code' as Code, cast(0.188 as NUMERIC(5,3)) as perc
)

SELECT 
    Code,
    SUM(perc)
FROM
    example
GROUP BY Code
HAVING SUM(perc) > 1
...