Quantcast
Channel: BI Bits.co
Viewing all articles
Browse latest Browse all 15

Should I Use a Float Data Type?

$
0
0

My approach is to only use a float data type when I encounter calculations (and/or numerical values) where the decimal data type cannot handle the task. The decimal data type can handle calculations that use 38 digits or less. So in most instances, I use the decimal data type.

I recently entered into a discussion about using the float data type in SQL Server. Most third-party products that are purchased use the float data type for numeric columns. My co-worker was convinced that floats are a good option because they perform calculations faster and they use less space than other data types that are used to store numerical values. I agreed on those points, but I mentioned that in a typical commercial organization, the float data type can cause many more unexpected results than a decimal data type. The reason is that in several instances it only stores an approximation of the actual value. My friend pointed out that Microsoft Dynamics AX uses float as the data type for amounts and quantities. Again, I agreed. But I pointed out that the main issue with floats is that it uses a binary representation of the number. And in SQL Server there are many instances where a float data type will not provide the correct result. As an example, when the value in question is 1.5 or 1.25 or 1/3 or pi, float stores the exact value or a much better approximation than decimal. But there are other values that appear to be very simple, yet when you store the value as a float, float cannot return an exact value - it returns an approximation.

Decimal and Numeric data types store exact values (as opposed to how Float stores its values.) Decimal and Numeric are functionally equivalent data types. In using the Decimal data type, a value is defined as Decimal(p, s), where p stands for precision and s stands for scale. Another way to look at it is that p defines the total number of digits, and s defines how many decimal places, and s must be less than or equal to p. And it can store a value between (-10^38) + 1 and (10^38) - 1. If you try to create or update an attribute with a whole number where the number of digits exceeds p - s, the operation is aborted and an exception is raised; if the decimal part of the attribute is larger than the defined scale, the number is rounded. For example, if @TestDecimal is defined as Decimal(8,4) and you try to store 123.00047 in the field, the field will store 123.0005.

The behavior of float and real data types follows the IEEE 754 specification on approximate numeric data types. Float/real data type is used for numbers where the decimal point is not fixed. Because of the approximate nature of the float and real data types, they should not be used when exact numeric behavior is required, such as in financial applications, in operations involving rounding , or in equality checks. Also avoid using float and real data types in a WHERE clause, especially when used with the = or <> operators. If used, limit their use to the < and > operators.

And if you try to convert a float to a varchar, you can encounter some additional issues.

Here are some examples:

From Hugo Kornelis' blog.

DECLARE @Float1 float
        , @Float2 float
        , @Float3 float;

SET @Float1 = 54;
SET @Float2 = 0.03;
SET @Float3 = 0 + @Float1 + @Float2;

SELECT @Float3 - @Float1 - @Float2 AS 'Should be 0';

-- But it gives me 1.13797860024079E-15

And here is another example demonstrating an issue with Float data type:

SELECT 'FloatResult' = 777.2384 * CAST(100 AS Float(24)) / 100
        , 'DecimalResult' = 777.2384 * 100 / 100

-- The Float value is wrong - 777.2385, while the Decimal value is correct - 777.23840000

And this example demonstrates where Float gets the correct result and Decimal gets the wrong result.

DECLARE @DecimalResult Decimal(18,4)
SET @DecimalResult = 0.0003

SELECT SUM(d) * SUM(d) * 100
    FROM (
        SELECT @DecimalResult d
        UNION ALL
        SELECT @DecimalResult
        ) a
GO

DECLARE @FloatResult Float
SET @FloatResult = 0.0003

SELECT SUM(f) * SUM(f) * 100
    FROM (
        SELECT @FloatResult f
        UNION ALL
        SELECT @FloatResult
        ) a
GO
--The correct result is 0.000036. In order for a field defined as decimal to render the correct result, it must be defined with significantly more decimal places.
--And if you do not specify a suficient number of decimal places, you end up with 0 or 0.00004.

There are numerous articles about the pros and cons of using the float data type. My approach is to only use a Float data type when 38 digits will not do the job. So in most instances, I use the Decimal data type. And I will continue to avoid it unless I see a real need (for example the number of decimal places required makes the Decimal data type render invalid results.) If you are interested in further discussions on the topic, refer to this site here where Aaron Bertrand and Erland Sommarskog offer different views on the subject.


Viewing all articles
Browse latest Browse all 15

Trending Articles