Jump to content
apeisa

Float field & rounding

Recommended Posts

Does it work? It seems to always round with 4 decimals (saving values through api). I have tried set value of "Number of decimal digits to round to" to 2 and 6 and I always end with decimals like: 60.2311, not 60.23 or 60.231148

Share this post


Link to post
Share on other sites

I've never tried, just shooting blind, but there is a difference between how many places you round to and how many digits you show – maybe four digits is default length of the part after the comma (I'm not completely sure how do we call it in english :) in formatted output?

A.

Edit: and just in case I'm right and you're outputting the float via simple echo (not sprintf('%.2f')), there might be an bug – no correlation between rounding and number of floating decimals or something.

Share this post


Link to post
Share on other sites

Outputting via simple echo, but it is also 4 digits when editing field through admin.

Share this post


Link to post
Share on other sites

The configuration option to set the precision of floats was specific to the Inputfield rather than the Fieldtype. Since the Inputfield is only used interactively (not in the API) the precision wasn't applicable to the API. That doesn't make a lot of sense, and I'm not sure why I set it up that way, but I just changed it. I moved the configuration stuff to the Fieldtype rather than the Inputfield. Now you should be able to set the precision and have it honored by both the API and the admin/inputfield. I think there was also an issue with the precision being ignored in some cases, which has been fixed as well. If you grab the latest commits, it should correct this. Please let me know if it doesn't, or if you run into any other similar issues. Some of these field types don't have many miles on them yet (like the Float one). :)

Thanks,

Ryan

Share this post


Link to post
Share on other sites

I can duplicate your result here. I think we must be running up against the bounds of what a default float field in MySQL will support. It looks like 6 digits max, whether before or after the point, from testing here. You could try changing it to a double from PhpMyAdmin, but I usually stick to a normal text field for lat/lng values, or for any longish floating point value that I don't need to use for greater-than/less-than comparisons in selectors. I may update this fieldtype's schema to use a double rather than a float, though I'm not positive even that will support the full scope of lat/lng values. 

  • Like 2

Share this post


Link to post
Share on other sites

I changed fields to double and it works nicely.

We actually need them to be floats rather than text since we want easily get queries like: all the events in 60km from this point, please.

Interesting thing when changing to double: 24.9194 => 24.9194049835205. That cannot be real value, since my original data source (last.fm) had those with 6 decimals. Or maybe mysql have some mystical superpowers and internal location database ;)

  • Like 1

Share this post


Link to post
Share on other sites

Glad converting to double fixed it. I will update this fieldtype to use double instead. That's interesting how it came up with that number on it's own... I've not used mysql with floating point numbers very much, but it seems like a much more complex subject than I realized before. Good weekend reading material for me :)

Share this post


Link to post
Share on other sites

Digging up an old thread, but I wanted to post some more info since the problem still exists. Just like you both confirmed on your own, if I define my decimal places to be rounded out to 6 spots on a float field, it still saves with 4.

I'm saving latitude and longitude values, but I need to be able to use greater-than and less-than comparisons in selectors. Looking at the database via phpMyAdmin, I noticed that the float fieldtype is still being created as a FLOAT column and not DOUBLE. I also noticed that the Length/Values for the column definition of the FLOAT field wasn't defined.

I manually set it to "10,6" (no quotes) and kept it as a FLOAT. It did the trick and the values saved correctly.

HOWEVER - Ryan mentioned the limitation of 6 decimal spots for the FLOAT column type. I did some research it a little and found this info on the MySQL website:

A precision from 0 to 23 results in a four-byte single-precision FLOAT column. A precision from 24 to 53 results in an eight-byte double-precision DOUBLE column.
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.
Source: http://dev.mysql.com...oint-types.html

Since that's the case, I decided that changing the field type to DOUBLE as apeisa suggested was a better solution and allows for a little more flexibility. Is changing the default column type created for Float fieldtypes from FLOAT to DOUBLE going to be integrated in a future PW release?

Share this post


Link to post
Share on other sites

It's been awhile since I looked at this, but I seem to recall some issue with DOUBLE going back into PHP that wasn't an issue with FLOAT, so put it off to research later. I need to take a closer look again. But what you did by modifying the schema directly towards your needs is a fine way to go in this case. ProcessWire is not going to go and change your schema back or anything (unless you change the fieldtype), so it should be safe. But please let me know if you run into any issues with losing precision on the DOUBLE when going to/from PHP.

Share this post


Link to post
Share on other sites

I am having some problems with this also, on the dev version. I can't seem to get a float to show a consistent number of decimal places. Some fields seem ok, but others get rounded to no decimal places, even though the full number is stored in the db.

Share this post


Link to post
Share on other sites

What are folks wanting to store in these float fields?

If you want to store what would be monetary values then I'd suggest avoiding floats or doubles like the plague. Go with fixed-point values which are usually strings which you manipulate with PHP's bc maths functions. MySQL also supports fixed point numbers using the DECIMAL() type.

Contrary to popular belief, floating point numbers (including doubles) are *extremely* inaccurate number representations. Where floats and doubles shine is where you have to store values from a huge *range*; but they do it at the expense of accuracy. They are almost always inaccurate approximations of the value you want to store.

  • Like 1

Share this post


Link to post
Share on other sites

Good point - I guess I initially chose float because decimal and double were not supported. I have often used text fields for numeric values in the past and made use of PHP without problems. I have only rarely used float in the past, but thought they must have been more useful than I thought since since it is the only numeric (other than integer) that is offered in PW.

Anyway, happy to use text, but I still think there is a bug with displaying float decimal places in the admin.

Share this post


Link to post
Share on other sites

Take a look at fNumber and fMoney from the Flourish library if you need something to ease working with these kinds of data. And here's a how-to for autoloading Flourish from your template files should you choose to go down that route.

  • Like 1

Share this post


Link to post
Share on other sites

Thanks for the Flourish suggestion - I did recently see something about it, but hadn't investigated yet - looks like it could come in quite handy.

I know it's been said before, but the community on this forum really is about the best I've ever experienced. I am looking forward to being able to give something back very soon.

  • Like 4

Share this post


Link to post
Share on other sites
If you want to store what would be monetary values then I'd suggest avoiding floats or doubles like the plague. Go with fixed-point values which are usually strings which you manipulate with PHP's bc maths functions. MySQL also supports fixed point numbers using the DECIMAL() type.

I once heard that you should use integers for these kind of data, as in instead of $3.256 you'd have 3256 fractions of a cent (and do int calculations with that)

  • Like 1

Share this post


Link to post
Share on other sites

That's a good example of fixed-point storage and is certainly one way to address this.

Also, though I'm not 100% sure about this, I seem to remember having heard from accounting circles that you should be storing 2 decimal points beyond the smallest unit of currency, not one. Meaning $3.25 would be represented as 32500 and $3.256 as 32560. If that's right, that would apply no matter if you were using strings or integers behind the scenes.

Share this post


Link to post
Share on other sites
That's a good example of fixed-point storage and is certainly one way to address this.

Also, though I'm not 100% sure about this, I seem to remember having heard from accounting circles that you should be storing 2 decimal points beyond the smallest unit of currency, not one. Meaning $3.25 would be represented as 32500 and $3.256 as 32560. If that's right, that would apply no matter if you were using strings or integers behind the scenes.

Yeah, I believe it's the case, I've just thought it doesn't matter to illustrate use of (int) with 'decimal' values :)

Share this post


Link to post
Share on other sites

Just noticed that with the latest dev, floats are stored as integers in the db.

For example: 0.3423 -> 0, 3.5 -> 3

I'm using text-fields and cast them in PHP to (float) or (double) when needed.

Share this post


Link to post
Share on other sites
Just noticed that with the latest dev, floats are stored as integers in the db.

For example: 0.3423 -> 0, 3.5 -> 3

I'm confused -- I haven't changed anything here, and the getDatabaseSchema() function for FieldtypeFloat still says this:

public function getDatabaseSchema(Field $field) {
  $schema = parent::getDatabaseSchema($field);
  $schema['data'] = 'float NOT NULL';
  return $schema;
}

Can you clarify what you mean about them being stored as ints in the DB? :) I want to make sure I didn't break something. 

Share this post


Link to post
Share on other sites

Hi ryan,

Here's my setup:

1) Created a Float-Field "test_float" – no number entered under Details (rounding)

2) Insert a value in test_float, for example 3.5

3) Save

4) Reload and After saving the page, the value in the field is 4

This is also the value stored in the database, see my screenshot.

The schema of "data" is correctly set to float

post-582-0-04759000-1360496491_thumb.png

Share this post


Link to post
Share on other sites

Having hard time debuging where my value gets rounded. The post-request ist okay, but:

- InputfieldFloat::sanitizeValue already receives the rounded one.

- Page::setFieldValue also already receives the rounded one

Cannot dig deeper now, but is this something specific or can anyone confirm this issue?

Cheers

Share this post


Link to post
Share on other sites

On the details tab, what do you have for "number of decimal digits to round to"?

On the input tab, what do you have for "numeric input type?"

Share this post


Link to post
Share on other sites

number of decimal digits to round to: Empty, but also doesn't work when entering a number

numeric input type: Text

Strange. I'll check out on another setup / environment

Share this post


Link to post
Share on other sites

Thanks -- let me know what you find, and I'll do some more testing here too. If you find that it's repeatable, please post a GitHub issue report so that I don't lose track of it. :) 

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...