A View Inside My Head

Jason's Random Thoughts of Interest
posts - 48, comments - 110, trackbacks - 4

Watch Those Numeric Data Types!

I received a support email yesterday for a system that I had written a few years ago. It seems that they were running year-end reporting, and total combined profit numbers were coming out in the quadrillions. It would have been a nice profit to report, but alas, not an accurate one.

When a number is magnitudes larger than what it should be, and there is division involved in a calculation somewhere, then that smells of floating point math issues. In this case, there was a SUM() being performed on a series of numbers, and instead of the result being a true zero, floating point math resulted in a number really, really, really close to zero, but not quite.

Note to the observant reader: If this sum came out to be a true zero, then the division would have been skipped by the CASE logic that is in place.

The worst part about troubleshooting systems that you wrote years before is trying to remember why certain design decisions came to be. In this case, a Net Sales column was stored as a FLOAT data type. If memory serves me correctly, this was the default type that DTS created when the data was migrated over from MSAccess.

Yeah, sure, a better data type in this case would have been the SQL Server DECIMAL type, which is an exact numeric value. But, for the most part, FLOAT had served its purpose quite nicely over the past several years, so I left it alone and wrapped the SUM() operation within a ROUND() function in order to reduce the number of possible side effects from changing the data type altogether.

The funniest thing is that this particular series of numbers were merely pennies in value, and were not even representative of actual sales! These numbers were very minor accounting adjustments made on paper to one account. But the resultant error came out in the quadrillions of dollars!

To demonstrate this particular case, here is a SUM() of those exact numbers in both a FLOAT and a DECIMAL.

Note: This sample uses the new SQL Server 2008 Row Constructor syntax to perform the INSERT as one statement, instead of individual INSERTs for each row.


declare @t table (f float, d decimal(18,2))

INSERT INTO @t VALUES
( 0.05, 0.05),
(-0.02, -0.02),
(-0.03, -0.03)

SELECT SUM(f) AS f,
SUM(d) AS d
FROM @t

Results:

f d
3.46944695195361E-18 0.00

Print | posted on Friday, January 25, 2008 10:21 AM | Filed Under [ Articles SQL ]

Feedback

# re: Watch Those Numeric Data Types!

Admit it, you chose floating points so you could run your superman scheme and trim the pennies which were being rounded out by the floating point math!

You've been busted!
1/25/2008 12:07 PM | John Chapman
Gravatar

# re: Watch Those Numeric Data Types!

Peter Gibbons: Um, the 7-Eleven, right? You take a penny from the tray.

Joanna: From the crippled children?

Peter Gibbons: No, that's the jar. I'm talking about the tray, the pennies for everybody. We're basically doing the same thing only we take it from a much bigger tray and we do it a couple of million times.

1/25/2008 12:59 PM | Jason
Gravatar

# re: Watch Those Numeric Data Types!

Do you get to "But the resultant error came out in the quadrillions of dollars! "?

3.46944695195361E-18 is 0.00000000000000000346944695195361

[)amien
1/28/2008 4:40 PM | Damien Guard
Gravatar

# re: Watch Those Numeric Data Types!

Ah, let me explain that part, because the story might be a little misleading.

This particular query was spreading a dollar amount among different line items. In simplified terms: When you spread a dollar amount, you calculate what percentage of the total sales the current line is, then multiply this fraction by the dollar amount to be spread (i.e., so that x% of the dollar amount gets allocated to that one line item).

In this case, that E-18 number was the denominator, causing the amount spread to be magnitudes higher than it should have been. In reality, logic would have spread zero into this line item (because the sum was supposed to be zero). But, instead, we had a quillion-dollar amount calculated instead.
1/28/2008 5:41 PM | Jason

Post Comment

Title  
Name  
Email
Url
Comment   
Please add 8 and 7 and type the answer here:

Powered by: