float precision problem in mysql - mysql

Can anybody, given example below, make to me an explanation how FLOAT works in mySQL? I know that float is approximative, but really, such a difference? And there is only 9 digits, so it is not overflow problem, isn't it?
mysql> create table t(f FLOAT(15,2), db DOUBLE);
mysql> insert into t(f,db) VALUES (512659663, 512659663);
mysql> select * from t;
+--------------+-----------+
| f | db |
+--------------+-----------+
| 512659648.00 | 512659663 |
+--------------+-----------+
(mysql Ver 14.14 Distrib 5.1.44, for Win32 (ia32) on Windows XP)

FLOAT is a 32-bit type with, as the name suggests, floating point. The higher is the value, the less is the absolute precision.
512659648 is large enough to introduce errors in tens.
Update:
In IEEE-754 (that's what FLOAT is), the data are stored in 32 bits: 1-bit sign, 8-bit binary exponent and 23-bit significand.
The exponent shows you the closest least power of 2 (28 in your case, or 268435456).
The significand is a binary fraction. It can store numbers from 1 to 2 with precision up to 2^-23. In your case, it's 1.11101000111010010000110, or ~ 1.9098060 in decimal notation.
The number is calculated as a product of the exponent and the significand.
Given all this, precision is 2 ^ (28 - 23) = 2 ^ 5 = 32 for the numbers of that order (2^28 to 2^29).

Actually, in MySQL, FLOAT and DOUBLE are both approximate floating-point numbers. MySQL uses four bytes for single-precision values and eight bytes for double-precision values.
So, both columns are approximate - it's just that your FLOAT column only gets 4 bytes to try to approximate your number.

The mantissa of a single precision floating point number is 22 bits in length. It therefore cannot accurately store an integer number greater than 2^22, 4194304.

Related

Binary and Bits

Here's a question I've come across:
Assume each X represents one bit, either 0 or 1. Consider the 8-bit unsigned binary numbers A = 1XXX XXXX and B = 0XXX XXXX. Which of the following are true (you may tick more than one answer):
A B > A
B A > 127
C Can't tell which one A or B is larger
D B < 127
E A > B
Explanations needed (0 understanding on this). Thanks!
The key to the answer is in the word unsigned. This means that the MSB (left most bit) is not being used to indicate the results sign. Processors perform mathematical operations such as add, subtract and comparison on numbers using twos compliment, this means that to know what the numeric value of a binary word is we must know if it is signed (can contain negative values) or unsigned (positive numbers only).
So in the above case the values are unsigned, which means A is always greater than B and that A has the MSB of an 8 bit value set to 1 so must be at least 128.
In the same way that we count in units of 10s binary works in units of two:
Binary
128 64 32 16 8 4 2 1
Decimal
1000 100 10 1
However if the binary value were signed the left most bit would be used to express positve (0) or negative (1) and when negative we need to invert the value and add one to get back to the (Negative) result.

casting a floating to decimal in mysql

I am not quite understanding the cast function and decimal here. What does decimal(7,2) actually mean?. The first part and the second part arg of the function.
Why do i need to cast/convert my floating point to decimal here?.
mysql> SELECT productCode, MAX(price), MIN(price),
CAST(AVG(price) AS DECIMAL(7,2)) AS `Average`,
CAST(STD(price) AS DECIMAL(7,2)) AS `Std Dev`,
SUM(quantity)
FROM products
GROUP BY productCode;
+-------------+------------+------------+---------+---------+---------------+
| productCode | MAX(price) | MIN(price) | Average | Std Dev | SUM(quantity) |
+-------------+------------+------------+---------+---------+---------------+
| PEC | 0.49 | 0.48 | 0.49 | 0.01 | 18000 |
| PEN | 1.25 | 1.23 | 1.24 | 0.01 | 15000 |
+-------------+------------+------------+---------+---------+---------------+
Below is a sql fiddle for the same?.
http://sqlfiddle.com/#!2/1ed51b/1/0
My Questions again repeated:
What does decimal(7,2) actually mean?. The first part and the
second part arg of the function.
Why do i need to cast/convert my floating point to decimal here?.
DECIMAL(7,2) means a number with a fixed decimal point, having 7 digits altogether, with 2 of them to the right of the decimal point. (So, 5 left, 2 right.)
You don't need to cast unless you want the behavior of DECIMAL types (typically, fixed point) rather than the behavior of FLOAT types (useful approximations with a relatively unpredictable number of digits right of the decimal point). For example, your average for product code "PEC" with the cast is 33333.65; without the cast it's 33333.653333.
If you're routinely using all the digits, you should probably increase the total number of digits in the cast. Say, to something like DECIMAL (14,2).
Why? Because if the intention is just to display the values, then casting to a DECIMAL with two decimal places will make it easier to read. If you take out the CASTs you will be shown values like AVERAGE 33333.653333 STD DEV 47140.218734.
As you can read on MySQL manual:
The declaration syntax for a DECIMAL column is DECIMAL(M,D). The
ranges of values for the arguments in MySQL 5.1 are as follows:
M is the maximum number of digits (the precision). It has a range of 1
to 65. (Older versions of MySQL permitted a range of 1 to 254.)
D is the number of digits to the right of the decimal point (the
scale). It has a range of 0 to 30 and must be no larger than M.
If you use decimal(M,D) you are reserving no places for anything to the left of the decimal. Decimal(7,2) means 7-2 = 5 where 5 is your integer left and 2 being on right.
In simple words, it describes how many total digits a field will be able to store. Decimal(50,2) = 52 total digits, 50 before and 2 after decimal separator.

MySQL structure for storing numeric values that differ drastically

I have a column with numeric values that differ drastically:
123.072
2
0.00012
851
1234
0.1
12
0.531211
etc.
I've tried using float and decimal but when I enter 0.023 for example, it just rounds the value as 0. I can't afford to round these numbers.
What structure type and length should I be using?
Try defining the range(length) of your decimal:
decimal(number,number)

What is the use of DECIMAL(x,0)?

In a DECIMAL(M, D) column MySQL gives the option for the range of D to be 0 to 30.
Is there a subtle reason that I'm missing for the option of 0? Isn't a decimal with nothing after the decimal point an integer?
When and why would I want to specify a DECIMAL that has no decimal places?
The number range of the DECIMAL type is much greater than for an INTEGER or BIGINT. The greatest number you are able to store in a DECIMAL(65, 0) is 65 nines. The largest number in a BIGINT is 18446744073709551615.
DECIMAL(x, 0) is often a little more expensive for small numbers. Consider using a defined INTEGER type if your numbers are in the range for one of those.
The storage requirement in bytes for a DECIMAL(x, 0) field depends on the x according to this formula:
Storage = x / 9 + Leftover
Leftover = round_up((x % 9) / 2) (i.e., about half of the leftover digits)
You can read more about storage requirements for numeric types in the MySQL manual and compare for yourself.
Besides allowing to store values bigger than BIGINT, you can use DECIMAL(x,0) if you want to:
allow values in the range -9, ... , +9: use DECIMAL(1,0) (uses 1 byte)
allow values in the range -99, ... , +99: use DECIMAL(2,0) (uses 1 byte)
allow values in the range -999, ... , +999: use DECIMAL(3,0) (uses 2 bytes)
allow values in the range -9999, ... , +9999: use DECIMAL(4,0) (uses 2 bytes)
...
allow values in the range -999999999, ... , +999999999: use DECIMAL(9,0) (uses 4 bytes)
... etc (up to DECIMAL(65,0) which uses 29 bytes)
In Mysql,
Decimal(3,2) means total 3 digits and 2 digits after decimal point like 3.42
Decimal(3,0) means in total 3 digits and no digit after decimal point like 345
Even if you write something beyond the given range in brackets of decimal Mysql will automatically update them to 000 or 999.
In a biging you can only store a digit which is no larger than 18 446 744 073 709 551 615. This is 20 digits, but in a DECIMAL you can specify even a 65 digits to store. Also with int you can't constrait directly the number of digits to a low number (e.g. to one). So it is more flexible, and if you need to expand it on an existing database, it is easier.

What column type should I use to store values between 0 and 1 (say up to 5 decimal places) in MySQL?

It is most important that it be accurate, but also it should take the least disk space possible.
You would need a DECIMAL(6,5) to store a number from 0 to 1 with 5 decimal places.
The declaration syntax for a DECIMAL column is DECIMAL(M,D). The ranges of values for the arguments in MySQL 5.1 are as follows:
M is the maximum number of digits (the precision). It has a range of 1 to 65.
D is the number of digits to the right of the decimal point (the scale). It has a range of 0 to 30 and must be no larger than M.
According to this, in MySQL 5.0.3
DECIMAL(5,5) or DECIMAL (6,6) should take 3 bytes.
DECIMAL(4,4) 2 bytes.
If you need to store values from 0 to 1 inclusive, you might be tempted to use DECIMAL(6,5). But that occupies 4 bytes as integer and float parts are stored separately and you need one byte for integer and three for 5 decimal digits. And if you have 4 bytes you might as well use FLOAT.
Before MySql 5 DECIMALs were stored as strings and the most efficient way was to store SMALLINT or MEDIUMINT (2 or 3 bytes) and manually divide it by 10000 or 1000000 respectively.