Frage

I've looked all over and can't find this answer.

How many actual digits are there for a MySQL FLOAT?

I know (think?) that it truncates what's in excess of the FLOAT's 4 byte limit, but what exactly is that?

War es hilfreich?

Lösung

From the manual (emphasis mine):

For FLOAT, the SQL standard permits an optional specification of the precision (but not the range of the exponent) in bits following the keyword FLOAT in parentheses. MySQL also supports this optional precision specification, but the precision value is used only to determine storage size. A precision from 0 to 23 results in a 4-byte single-precision FLOAT column. A precision from 24 to 53 results in an 8-byte double-precision DOUBLE column.

So up to 23 bits of precision for the mantissa can be stored in a FLOAT, which is equivalent to about 7 decimal digits because 2^23 ~ 10^7 (8,388,608 vs 10,000,000). I tested it here. You can see that 12 decimal digits are returned, of which only the first 7 are really accurate.

Andere Tipps

for those of you who think that MySQL treats floats the same as, for example JAVA, I got some SHOCKING news: MySQL degrades the available accuracy which is possible to a float, in order to hide from you decimal places which might be incorrect! Check this out:

JAVA:

public static void main(String[] args) {
    long i = 16777225;
    DecimalFormat myFormatter = new DecimalFormat("##,###,###");
    float iAsFloat = Float.parseFloat("" + i);
    System.out.println("long i = " + i + " becomes " + myFormatter.format(iAsFloat));
}

the output is

long i = 16777225 becomes 16,777,224

So far, so normal. Our example integer is just above 2^24 = 16777216. Due to the 23 bit mantissa, between 2^23 and 2^24, a float can hold every integer. Then from 2^24 to 2^25, it can hold only even numbers, from 2^25 to 2^26 only numbers divisible by 4 and so on (also in the other direction: from 2^22 to 2^23, it can hold all multiples of 0.5). As long as the exponent isn't out of range, that's the rule of what a float can store.

16777225 is odd, so the "float version" is one off, because in that range (from 2^24 to 2^25) the "step size" of the float is 2.

And now, what does MySQL make of it.

Here is the fiddle, in case you don't believe me (I wouldn't)

http://www.sqlfiddle.com/#!2/a42e79/1

CREATE TABLE IF NOT EXISTS `test` (
     `test` float NOT NULL
) ENGINE=InnoDB DEFAULT CHARSET=latin1;

INSERT INTO `test`(`test`) VALUES (16777225)

SELECT * FROM `test`

result:

16777200

the result is off by 25 rather than 1, but has the "advantage" of being divisible by 100. Thanks a lot.

I think I understand the "philosophy" behind this utter nonsense, but I can't say I approve. Here is the "reason":

They don't want you to see the decimal places which could be wrong, which they accomplish by rounding the "actual" float value (as it is in JAVA and according to the industry standard) to some suitable power of ten.

In the example, if we leave it as it is, the last digit is wrong, without being a zero, and we can't have that.

Then, if we round to multiples of ten, the correct value would be 16777230, while what the "actual" float would be rounded to 16777220. Now, the 7th digit is wrong (it wasn't wrong before, but now it is.) And it's not zero. We can't have that. Better round to multiples of 100. Now both the correct value and the "actual" float value round to 16777200. So you see only the 6 correct digits. You don't want to know the "24" at the end, telling you (since the step size is 2 in that range) that your original number must have been between 1677723 and 1677725. No, you don't want to know that; those 2 numbers differ in the 7th digit after rounding to the 7th digit, so you can't know the "proper" 7th digit, and hence you want to stop at the 6th digit. Anyway, that's what they think you want at MySQL.

So their goal is to round to some number of decimal digits (namely, 6), such those 6 digits are always "correct", in that you'd have gotten the same 6 digits if you'd rounded the original exact number (before converting it to a float) to 6 digits. And since log_base10(2^23) = 6.92, rounded down 6, I can see why they think that this will always work. Tragically, not even that is true.

example:

i = 33554450

the number is between 2^25 and 2^26, so the "float version" (that is the JAVA float version, not the MySQL float version) of it is the closest multiple of 4 (the smaller one, if it's right in the middle), so that is

i_as_float = 33554448

i rounded to 6 decimals (i.e. to multiples of 100, since it's an 8 digit number) gives 33554500.

i_as_float rounded to 6 decimals gives 33554400

Oops! those differ at the 6th digit! But don't tell the MySQL people. They might just start "improving" 16777200 towards 16777000.

UPDATE

other databases don't do it like that.

fiddle: http://www.sqlfiddle.com/#!15/d9144/1

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top