2012-03-02 4 views
7

я вижу какое-то странное поведение при округлении в SQL Server 2008. Учитывая следующий код:Округление проблемы с SQL Server и РЕАЛЬНЫМ типом данными

DECLARE @Value REAL 
SELECT @Value = .35 
SELECT ROUND(@Value, 1) 

Я бы ожидать, что значение будет 0,4, однако он выводит 0,3. Я должен предположить, что это потому, что хранимое значение на самом деле меньше 0,35, что-то вроде .34999999999999. Это так, или я делаю что-то неправильно? Есть ли способ гарантировать, что это ведет себя так, как ожидалось, по крайней мере, от видимой ценности?

+1

Что вы получаете, если '@ Value' имеет тип' DECIMAL (10,2) '? Помните, что 'REAL' - приблизительный тип данных, то есть он действительно может хранить 0,35 как .34999999999999 или что-то подобное. –

+0

Использование DECIMAL (10,2) дает ожидаемый результат. К сожалению, моя база данных уже использует REAL для этого. Возможно, мне нужно посмотреть на конвертацию. –

+0

Да, я бы предложил конвертировать. 'REAL' и' FLOAT' не являются типом данных, которые вы должны использовать, если вы ожидаете, что логическое (например, более приблизительное, чем то, что большинство из нас научит вам) округлить. –

ответ

7

При использовании значений с плавающей точкой, как реальные и FLOAT (то же самое), то SQL Server Функция ROUND() следует стандарту IEEE 754 и использует алгоритм «round up».

Но это означает разные вещи для разных значений с плавающей запятой. Некоторые значения «.5» заканчиваются тем, что они сохраняются как аппроксимация «.49999999999», другие - «.500000001» и т. Д. Он округляет значение, которое фактически хранится, а не значение, которое вы ему дали.

http://msdn.microsoft.com/en-us/library/ms187912.aspx

Если точные десятичный математические вопросы к вам, используйте DECIMAL, не FLOAT или РЕАЛ.

7

Плохо, что данные хранятся как РЕАЛЬНЫЕ, но не все надежды теряются. Преобразуйте REAL в DECIMAL (10,2), прежде чем округлить его. Таким образом, значение 0.3499999999999 (или какое-либо неточное значение сохраняется) будет округлено до 0,35, а затем вы округлите его до 0,4. Вы даже можете преобразовать его привести к DECIMAL (10,1), если вы хотите, чтобы отображаться как 0.4:

DECLARE @Value REAL 
SELECT @Value = .35 
SELECT CONVERT(DECIMAL(10,1), ROUND(CONVERT(DECIMAL(10,2), @Value), 1)) 
+0

Это, по-видимому, работает! Престижность! Интересно, насколько быстро эти преобразования. Если я просто заменю раунд этим расчетом, я задаюсь вопросом, как сильно это повредит мне. –