Floating-point numbers sometimes cause confusion because they
are approximate and not stored as exact values. A
floating-point value as written in an SQL statement may not be
the same as the value represented internally. Attempts to
treat floating-point values as exact in comparisons may lead
to problems. They are also subject to platform or
implementation dependencies. The
`FLOAT`

and
`DOUBLE`

data types are subject
to these issues. For `DECIMAL`

columns, MySQL performs operations with a precision of 65
decimal digits, which should solve most common inaccuracy
problems.

The following example uses
`DOUBLE`

to demonstrate how
calculations that are done using floating-point operations are
subject to floating-point error.

mysql>mysql>`CREATE TABLE t1 (i INT, d1 DOUBLE, d2 DOUBLE);`

->`INSERT INTO t1 VALUES (1, 101.40, 21.40), (1, -80.00, 0.00),`

->`(2, 0.00, 0.00), (2, -13.20, 0.00), (2, 59.60, 46.40),`

->`(2, 30.40, 30.40), (3, 37.00, 7.40), (3, -29.60, 0.00),`

->`(4, 60.00, 15.40), (4, -10.60, 0.00), (4, -34.00, 0.00),`

->`(5, 33.00, 0.00), (5, -25.80, 0.00), (5, 0.00, 7.20),`

mysql>`(6, 0.00, 0.00), (6, -51.40, 0.00);`

->`SELECT i, SUM(d1) AS a, SUM(d2) AS b`

+------+-------+------+ | i | a | b | +------+-------+------+ | 1 | 21.4 | 21.4 | | 2 | 76.8 | 76.8 | | 3 | 7.4 | 7.4 | | 4 | 15.4 | 15.4 | | 5 | 7.2 | 7.2 | | 6 | -51.4 | 0 | +------+-------+------+`FROM t1 GROUP BY i HAVING a <> b;`

The result is correct. Although the first five records look
like they should not satisfy the comparison (the values of
`a`

and `b`

do not appear to
be different), they may do so because the difference between
the numbers shows up around the tenth decimal or so, depending
on factors such as computer architecture or the compiler
version or optimization level. For example, different CPUs may
evaluate floating-point numbers differently.

If columns `d1`

and `d2`

had
been defined as `DECIMAL`

rather
than `DOUBLE`

, the result of the
`SELECT`

query would have
contained only one row—the last one shown above.

The correct way to do floating-point number comparison is to first decide on an acceptable tolerance for differences between the numbers and then do the comparison against the tolerance value. For example, if we agree that floating-point numbers should be regarded the same if they are same within a precision of one in ten thousand (0.0001), the comparison should be written to find differences larger than the tolerance value:

mysql>->`SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1`

+------+-------+------+ | i | a | b | +------+-------+------+ | 6 | -51.4 | 0 | +------+-------+------+ 1 row in set (0.00 sec)`GROUP BY i HAVING ABS(a - b) > 0.0001;`

Conversely, to get rows where the numbers are the same, the test should find differences within the tolerance value:

mysql>->`SELECT i, SUM(d1) AS a, SUM(d2) AS b FROM t1`

+------+------+------+ | i | a | b | +------+------+------+ | 1 | 21.4 | 21.4 | | 2 | 76.8 | 76.8 | | 3 | 7.4 | 7.4 | | 4 | 15.4 | 15.4 | | 5 | 7.2 | 7.2 | +------+------+------+ 5 rows in set (0.03 sec)`GROUP BY i HAVING ABS(a - b) <= 0.0001;`

Floating-point values are subject to platform or implementation dependencies. Suppose that you execute the following statements:

CREATE TABLE t1(c1 FLOAT(53,0), c2 FLOAT(53,0)); INSERT INTO t1 VALUES('1e+52','-1e+52'); SELECT * FROM t1;

On some platforms, the `SELECT`

statement
returns `inf`

and `-inf`

. On
others, it returns `0`

and
`-0`

.

An implication of the preceding issues is that if you attempt
to create a replication slave by dumping table contents with
**mysqldump** on the master and reloading the
dump file into the slave, tables containing floating-point
columns might differ between the two hosts.

In PHP, I calculated a value that arrives at the amount 20072.64 and I wrote this into a mysql field of type FLOAT.

Strangely (despite the technical specs indicating a large range), the number that got stored was 20072.6 - note truncation!

Solution: I changed the field type to DOUBLE and this was resolved.

Alternatives that did not work: Even type-casting in PHP did not do any good since ultimately the values had to be stored by MySQL.

Happy coding!

Khalid

Anyway I will try double fields

This is not a mystery. The problem is that Float columns only store 4-bytes per entry. This means that the precision available to the decimal portion of your number depends on the size of the non-decimal portion of your number. The more bytes are requires to represent the non-decimal portion of your number, the fewer bytes are available to represent the approximate decimal value of your number. If you store a sufficiently large number, your entire decimal value will be truncated to 0. You have solved the problem by increasing your per-entry storage to 8 bytes instead of 4.

var yourNumber = some floating point value

max decimal precision = 10 ^ (-5 + floor(yourNumber log 10))

So:

0 < x < 10 -> max precision is 0.00001

10 <= x < 100 -> max precision is 0.0001

100 <= x < 1000 -> max precision is 0.001

etc.

Selecting a tolerance level is not good, because the tolerance level differs from value to value depending on the number. As I inspected duplicates in my db for example two float stored values both 13442 compared as NOT EQUAL to each other when using too high (0.01) tolerance level, however they were EQUAL when I used lower (0.1) tolerance level.

Therefore I also recommend to change the documentation because the recommended solution (compare the difference to a selected threshold) is not safe.

I translated the equation of Geoffrey Downs to MySQL as follows for FLOAT values:

IF(ABS(yourFloat1-yourFloat2)<POW(10,FLOOR(LOG10(GREATEST(ABS(yourFloat1),ABS(yourFloat2)))-5)),"E Q U A L","N O T - E Q U A L")