views:

492

answers:

5

I ran into an issue by introducing floating point columns in the MySQL database schema that the comparisons on floating point values don't return the correct results always.

1 - 50.12
2 - 34.57
3 - 12.75
4 - ...(rest all less than 12.00)

SELECT COUNT(*) FROM `users` WHERE `points` > "12.75"

This returns me "3".

I have read that the comparisons of floating point values in MySQL is a bad idea and decimal type is the better option.

Do I have any hope of moving ahead with the float type and get the comparisons to work correctly?

+1  A: 

It's a floating point, so what's the problem? 3 could be the correct result, depends on what the database thinks about 12.75. Is it 12.75 or just a little more?

Use DECIMAL if you want exact numbers.

Frank Heikens
Hi Frank, can you elaborate on what you mean by "what the database thinks about 12.75". Shall I be in trouble if I tried to compare a two digit precision value with a three digit precision.Like...SELECT COUNT(*) FROM `users` WHERE `points` > "12.751"
Sharief
+1  A: 

There is a problems with comparison of floats for equality. This may give unpredicted results. This is due to internal implementation of floating point arithmetics.

Andrey
A: 

Comparing a number with a string?

le dorfier
+1  A: 

Do you notice the problem below?

CREATE TABLE a (num float);

INSERT INTO a VALUES (50.12);
INSERT INTO a VALUES (34.57);
INSERT INTO a VALUES (12.75);
INSERT INTO a VALUES (11.22);
INSERT INTO a VALUES (10.46);
INSERT INTO a VALUES (9.35);
INSERT INTO a VALUES (8.55);
INSERT INTO a VALUES (7.23);
INSERT INTO a VALUES (6.53);
INSERT INTO a VALUES (5.15);
INSERT INTO a VALUES (4.01);

SELECT SUM(num) FROM a;
+-----------------+
| SUM(num)        |
+-----------------+
| 159.94000005722 | 
+-----------------+

There's an extra 0.00000005722 spread between some of those rows. Therefore some of those values will return false when compared with the value they were initialized with.

To avoid problems with floating-point arithmetic and comparisons, you should use the DECIMAL data type:

ALTER TABLE a MODIFY num DECIMAL(6,2);

SELECT SUM(num) FROM a;
+----------+
| SUM(num) |
+----------+
|   159.94 | 
+----------+
1 row in set (0.00 sec)
Daniel Vassallo
Hey Daniel! thanks. I am considering converting my column type to DECIMAL.
Sharief
@Sharief: If converting to `DECIAML` is impossible, the only option I see is to allow some tolerance for floating point comparisons, such that you could write your query as follows: `SELECT COUNT(*) FROM users WHERE points > (12.75 + 0.001);`... However if accuracy is paramount, fixed point `DECIMAL` is the way to go. Another alternative to `DECIMAL` could be using an integer value scaled up to represent your values in terms of hundredths: `5012` instead of `50.12`. There may be some situations where this might be appropriate.
Daniel Vassallo
I did try adding the tolerance already, exactly the way you mentioned, even then the results were never consistent.
Sharief
+1  A: 

I did face the similar issue once. Convert the 'float' field to 'decimal'. It'll definitely solve the problem.

intellidiot