At https://github.com/laravel/framework/blob/master/src/Illuminate/Database/Schema/Blueprint.php#L505 the default precision of float is set to 8 digits, 2 max after the decimal place. This is absolutely bizarre. That's the kind of thing decimal
is used for. When I want a float
I want a huge amount of precision (or double
for even more of course), and I see no reason for the framework to presume 2 decimal places is enough.
Just pass the amount of precision you want. No matter what default I pick, someone will want to change it.
What's wrong with just float
with no precision arguments? See the MySQL docs at http://dev.mysql.com/doc/refman/5.0/en/floating-point-types.html
MySQL permits a nonstandard syntax:
FLOAT(M,D)
orREAL(M,D)
orDOUBLE PRECISION(M,D)
. Here, “(M,D)
” means than values can be stored with up toM
digits in total, of whichD
digits may be after the decimal point.
and
For maximum portability, code requiring storage of approximate numeric data values should use
FLOAT
orDOUBLE PRECISION
with no specification of precision or number of digits."
The former, which as far as I can tell in Laravel is the only kind of float I can make with the schema builder, is non-standard. Seems odd to only allow this. And I could be wrong about this, but doesn't a float set up in MySQL like this behave exactly like DECIMAL(x,y)
? If that's what the user wants the user should be using decimal.
The latter (FLOAT
with no specification of precision or number of digits) is as you see above what is recommended, and it's exactly what I want to use, and I imagine what most users would want to use in most cases. But am I right that there's no way to specify this with schema builder at present? Or how is it done?
And I haven't mentioned the third possibility mentioned in the docs, where you pass a single argument to float to give the precision (which is not the same as either argument of the FLOAT(M,D
) syntax. As far as I can tell there's no way to specify this with schema builder either.
So right now as far as I can tell the only way to set up a column for an actual floating point number is to make a fixed precision "float", and then run a non-portable, database-type-specific statement to change that column to be a proper float.
But honestly my main beef here is that I simply can't think why _any_ developer would be looking for a float and say "yup, that's exactly as I expected" when they see it is limited to two decimal places. That's just not what a float is.
Thanks.
I just ran into this same problem... I need big float numbers but when I noticed it was cutting it off to 2 after the decimal.. that isnt even a float lol
Can I ask you to reconsider closing this. The fix is just to copy a few lines from double()
to float()
. This would allow us to use ->float('col', null, null)
in the same way we can currently use ->double('col', null, null)
.
From class MySqlGrammar...
protected function typeFloat(Fluent $column)
{
return "float({$column->total}, {$column->places})";
}
protected function typeDouble(Fluent $column)
{
if ($column->total && $column->places)
{
return "double({$column->total}, {$column->places})";
}
else
{
return 'double';
}
}
Surely the inconsitency between the two implementations must irk you as much as it irks me ;-)
If you don't have the time, I'm happy to create a PR.
Is this case still open? I tried changing float length from 2 to 8 positions accuracy in order to be able to store latitude and longitude values according to googles mysql guidelines, but float doesn't seem to support these length parameters in schema builder
Let's just assume that for some reason doubles are always better than floats. If I want a double, I would have asked for one. Why is laravel forcing me to use a double? It's like going into McDonalds and asking for a hamburger but give you a salad because its better for you. Can't I just get a float? What's the rationale here?
+1 - if you need a double, you have a double, but float should always imply the float type. Yes, there are dangers with using the float if you don't know what you are doing, but there are cases where you want to use the float when you do, and it is annoying to have to create a raw query in the migration when you have the float migration type right there. Not sure how it can be fixed since it would break backwards compatibility, though.
How is this still an issue? Float is float, double is double, they're different. MySQL obviously recognizes that cause they made 2 different types that behave in 2 different ways. So why make float a double?
How is this still an issue? Float is float, double is double, they're different. MySQL obviously recognizes that cause they made 2 different types that behave in 2 different ways. So why make float a double?
Laravel isn't "making a float a double". I think perhaps "double" dosen't mean what you think it does.
Laravel isn't "making a float a double"
Yes it is :-(
When this issue was created (laravel 4), floats were created as decimals. (See my post above)
protected function typeFloat(Fluent $column)
{
return "float({$column->total}, {$column->places})";
}
But since Laravel 5.0, it creates them as doubles:
protected function typeFloat(Fluent $column)
{
return $this->typeDouble($column);
}
The defintion of double has not changed.
protected function typeDouble(Fluent $column)
{
if ($column->total && $column->places) {
return "double({$column->total}, {$column->places})";
}
return 'double';
}
Where is that code?
The code I linked to when I opened this ticket (haha, four years ago!) doesn't look it has changed: it still has the same default arguments of 8 and 2.
If in some deeper part of code these arguments are ignored and a double is being used, I'd consider this closed. As long as the default doesn't only have two decimal places of precision...
Oh, so nothing has changed. Whether it's float(m, d) or double(m, d), it's still a fixed number of digits total and a fixed number of digits after the decimal point. Can null be passed instead to use mysql's default? (i.e. double() rather than double(m, d))
As long as the default doesn't only have two decimal places of precision
The defaults have not changed.
To get an IEEE double, you must specify a precision of 0
- i.e. $table->double('foo', 0);
There is still no way to get an IEEE float.
Ok, so there's a way to get a reasonable floating point data type without using raw SQL statements. That really should be default, in my opinion, hence this ticket.
I personally don't mind getting a double rather than a float. What's a use case where you'd need a float instead of a double?
What's a use case where you'd need a float instead of a double?
Latitude/longitude.
An IEEE float gives a resolution of 9 decimal digits (i.e. centimeters).
This is perfect for real-world applications (map locations, GPS co-ordinates, etc.)
An IEEE double gives a resolution of 17 decimal digits (i.e. ångström).
This is a pointless waste of database storage.
This is extremely counter-intuitive behavior -- if you use a float on (for example) mysql, you expect to get a mysql float. Instead I'm getting a mysql double (uses 8 bytes) which can hold less information than a float.
How could using 8 bytes to hold less than 4 bytes worth of information be correct behavior?
From the Mysql documentation:
For maximum portability, code requiring storage of approximate numeric data values should use FLOAT or DOUBLE PRECISION with no specification of precision or number of digits.
Yeah, I quoted the same thing over four years ago...
Hah, yeah :-) I noticed that after I posted.
Perhaps a more compelling reason is more theoretical -- a very general rule of programming is that throwing away information is bad and should only be done for a very good reason.
In this case, we're throwing away information for no good reason.
If the user puts in 0.0008, then we should store 0.0008 (up to the precision of the float) rather than storing 0.00, which is what is happening now.
The laravel 5.6 documentation (and every previous version) says that $table->float()
will give you a FLOAT
column.
$table->double('amount', 8, 2);
DOUBLE equivalent column with a precision (total digits) and scale (decimal digits).
$table->float('amount', 8, 2);
FLOAT equivalent column with a precision (total digits) and scale (decimal digits).
It is no wonder that people keep raising this as a bug - it clearly doesn't work as documented!
Yet every bug report gets closed and refered back to https://github.com/laravel/framework/issues/9103 where we are told that this is working as designed, and refered to commit https://github.com/laravel/framework/commit/0c0a717052d8326e7e032e5181019b91926b76a8 which has the cryptic message "Tweak column mapping a bit."
We are also told to take it up on the forum, which doesn't really add anything to the discussion.
I offered to write a PR in 2014. The offer still stands.
There are plenty of times that a double
should be used instead of float
. But there are plenty of times you need a float
. Anything statistics-related, engineering-related, etc ... there is a reason that MySQL differentiates these types.
I rarely disagree with a design decision in Laravel, but I have to say this is a terrible, terrible design decision. PLEASE give us the ability to make a FLOAT data type without resorting to use raw queries!
I think the main problem here is that when you add $table->float() you're
expecting a float because its documented as a float and more importantly
the function is labeled float in and most relational DB's float is
different than decimal / double. For 1, its only 4 bytes, vs decimal is 8
bytes at least but also in laravel it has a default value for precision
that is 4 decimal places. Floats are expected to have the float precision.
So when you go in as a dev and use float you expect to be able to store
something like a latitude / longitude without having to specify FLOAT
precision because you don't need to specify float precision in most
relational databases.
On Thu, Mar 22, 2018 at 8:53 AM, J David Baker notifications@github.com
wrote:
There are plenty of times that a double should be used instead of float.
But there are plenty of times you need a float. Anything
statistics-related, engineering-related, etc ... there is a reason that
MySQL differentiates these types.I rarely disagree with a design decision in Laravel, but I have to say
this is a terrible, terrible design decision. PLEASE give us the ability to
make a FLOAT data type without resorting to use raw queries!—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
https://github.com/laravel/framework/issues/3151#issuecomment-375334729,
or mute the thread
https://github.com/notifications/unsubscribe-auth/AEJjBQARqGFunBDjXfH8qSZQ0NWp29buks5tg7r2gaJpZM4BXyY1
.
I think is weird to tell the framework to add a float
column without specifying decimal precision, and getting instead ad double(8,2)
with only two decimal places and then getting a load of bug reports of users being unable to store his arbitrary precision values.
The framework should not take decisions like that, we, users of the framework, are all developers and it's assumed we know what we're doing and so we should be able to get a float
when we ask for a float
.
maybe a solution would be to remove "float" and "double" entirely and instead add something like:
"small_num" and "big_num" and that way it'll force the developer to look at the definitions to see if what is offered is appropriate? Then Laravel can give whatever definition makes Taylor Otwell happiest and no one can complain about unintuitive behavior....
I'm guessing Taylor's motivation was to make so the common case of handling American currencies ($1234.56) would be handled fairly correctly by notice programmers.
@dsandber I think that would break things even more. I would make the framework give what the developer expects and also the documentation had to be clarified, because of the word equivalent
: a FLOAT equivalent
is not a value with a fixed decimal precision, at least not on Mysql.
@underdpt Don't forget, Laravel is built to work with many databases, not just MySQL. Presumably other databases have a different concept of "float" and "double". That is probably why Taylor did this otherwise counter-intuitive thing.
IMHO there's basically three choices:
1) Float and Double mean whatever they mean in the underlying DB. This creates problems with DB portability -- eloquent is meant to be an abstraction to hide the details of the underlying DB.
2) Float and Double mean arbitrary things. This is the current situation but leads to unintuitive behavior.
3) ArbitraryName1 and ArbitraryName2 mean arbitrary things. This would be at least not be counter-intuitive.
Presumably other databases have a different concept of "float" and "double"
FLOAT
and DOUBLE
are ANSI-standard SQL.
SQLite only has a few data types, and uses 8 bytes (i.e. DOUBLE) for all floating point data.
4 years later this is still an issue. I though I was creating a float column but alas it was a double.
This ticket was about a precision of two decimal places being assigned as default when the query builder is asked for a float. It was closed by the project maintainer. This still doesn't make sense to me but I'm not going to fight about it, especially since I haven't used Laravel in a few years now.
However, the discussion about float vs double came later, and is not the intended subject of this ticket. I suggest one of you who cares about float vs double opens a new ticket about it.
I suggest one of you who cares about float vs double opens a new ticket about it.
You mean like we did in:
Raising new tickets is utterly pointless :-(
This is quite clearly a bug - it is not working as per documentation! - see my comments above on 21 Mar 2018.
I've offered to create a PR to fix it several times. The offer still stands.
The reason people keep commenting on this particular issue is that it contains the most comprehensive description of the problem and summary of the situation.
Ok, no need to talk about it in this closed, unrelated ticket then.
>
Actually I wasn’t very clear in my comment. I was trying to create a float field without precision but it ended up with a double with precision. Completely the opposite of what would be expected.
Sorry, @fisharebest, I responded above as soon as I saw the list of ticket references, I didn't get to the bottom of your comment. I feel your pain; I still think there's not much point commenting here though.
Hey everyone, just want to let you know that I've looked into this and I believe we indeed need to add a few fixes here and there. I've started an issue in the ideas repo to collect all the places across the different grammars which should be fixed. I've also voiced my concern there how this will affect almost every app using them. Please take a look and help pinpoint the ones which are off: https://github.com/laravel/ideas/issues/1527
Also want to note that this is an issue which we should tread with the most highest care and take our time and not rush things. So don't expect a solution soon. But let's take a look at how we can go further.
FYI, I already wrote a package to "fix" this problem.
I've just published it - https://github.com/fisharebest/laravel-floats
Just run composer require fisharebest/laravel-floats
and your floating point fields will start working as expected.
Sounds like that fixes the weird default fixed precision issue as well as the float vs double issue. Haven't tried it (not using Laravel currently) but it looks great from the readme.
works great @fisharebest
thanks!
https://github.com/likemusic/laravel-mysql-float - a little bit improved (than fisharebest/laravel-floats) implementation float columns for MySql in Laravel's migrations.
Most helpful comment
What's wrong with just
float
with no precision arguments? See the MySQL docs at http://dev.mysql.com/doc/refman/5.0/en/floating-point-types.htmland
The former, which as far as I can tell in Laravel is the only kind of float I can make with the schema builder, is non-standard. Seems odd to only allow this. And I could be wrong about this, but doesn't a float set up in MySQL like this behave exactly like
DECIMAL(x,y)
? If that's what the user wants the user should be using decimal.The latter (
FLOAT
with no specification of precision or number of digits) is as you see above what is recommended, and it's exactly what I want to use, and I imagine what most users would want to use in most cases. But am I right that there's no way to specify this with schema builder at present? Or how is it done?And I haven't mentioned the third possibility mentioned in the docs, where you pass a single argument to float to give the precision (which is not the same as either argument of the
FLOAT(M,D
) syntax. As far as I can tell there's no way to specify this with schema builder either.So right now as far as I can tell the only way to set up a column for an actual floating point number is to make a fixed precision "float", and then run a non-portable, database-type-specific statement to change that column to be a proper float.
But honestly my main beef here is that I simply can't think why _any_ developer would be looking for a float and say "yup, that's exactly as I expected" when they see it is limited to two decimal places. That's just not what a float is.
Thanks.