[PHP] Converting floats to ints with intval
I've got the following script which demonstrates a problem I'm having with floating point numbers and intval: $times100 = (-37.12 * 100); print $times100 . \n; $intval100 = intval($times100); print $intval100 . \n; print ($intval100 / 100) . \n; I expect the output to be: -3712 -3712 -37.12 However, the actual output I'm getting (on several systems, so it's not just my machine) is: -3712 -3711 -37.11 Is there a reason for this, and a better way I should be doing it? Basically I need to add up a list of floats, representing currency values, and see if they're equal to another float, but I need to convert them to ints first because I can't guarantee than there won't be something after the second decimal place. Thanks, Paul -- Paul Waring http://www.pwaring.com -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP] Converting floats to ints with intval
On Thu, 2010-05-06 at 11:24 +0100, Paul Waring wrote: I've got the following script which demonstrates a problem I'm having with floating point numbers and intval: $times100 = (-37.12 * 100); print $times100 . \n; $intval100 = intval($times100); print $intval100 . \n; print ($intval100 / 100) . \n; I expect the output to be: -3712 -3712 -37.12 However, the actual output I'm getting (on several systems, so it's not just my machine) is: -3712 -3711 -37.11 Is there a reason for this, and a better way I should be doing it? Basically I need to add up a list of floats, representing currency values, and see if they're equal to another float, but I need to convert them to ints first because I can't guarantee than there won't be something after the second decimal place. Thanks, Paul -- Paul Waring http://www.pwaring.com It's part of the rounding problem you get with most languages out there. Why can't you compare the floating point values though? Currency should only have one decimal place anyway. Thanks, Ash http://www.ashleysheridan.co.uk
Re: [PHP] Converting floats to ints with intval
Ashley Sheridan wrote: It's part of the rounding problem you get with most languages out there. Why can't you compare the floating point values though? Currency should only have one decimal place anyway. You can't compare floating point values because if you have, for example, a user-entered value of '37.12' and add that to '0.18' it won't necessarily be equal to '37.30'. Currency must have two decimal places, otherwise how would you represent five pounds and sixteen pence (£5.16) for example? -- Paul Waring http://www.pwaring.com -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP] Converting floats to ints with intval
On Thu, 2010-05-06 at 11:40 +0100, Paul Waring wrote: Ashley Sheridan wrote: It's part of the rounding problem you get with most languages out there. Why can't you compare the floating point values though? Currency should only have one decimal place anyway. You can't compare floating point values because if you have, for example, a user-entered value of '37.12' and add that to '0.18' it won't necessarily be equal to '37.30'. Currency must have two decimal places, otherwise how would you represent five pounds and sixteen pence (£5.16) for example? -- Paul Waring http://www.pwaring.com Sorry, I misread that as decimal point! Why don't you store them as integer values and add in the decimal point with something like sprintf() afterwards? Store the values as pence and then you won't have any rounding problems. Thanks, Ash http://www.ashleysheridan.co.uk
Re: [PHP] Converting floats to ints with intval
Ashley Sheridan wrote: Why don't you store them as integer values and add in the decimal point with something like sprintf() afterwards? Store the values as pence and then you won't have any rounding problems. If I was designing the system from scratch, that's what I'd do. Unfortunately this is an add-on to a legacy system where currency values are already stored as strings in the database (yes, not ideal I know, but you have to work with what you've got). -- Paul Waring http://www.pwaring.com -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP] Converting floats to ints with intval
On 06/05/10 11:52, Paul Waring wrote: Ashley Sheridan wrote: Why don't you store them as integer values and add in the decimal point with something like sprintf() afterwards? Store the values as pence and then you won't have any rounding problems. If I was designing the system from scratch, that's what I'd do. Unfortunately this is an add-on to a legacy system where currency values are already stored as strings in the database (yes, not ideal I know, but you have to work with what you've got). Can you not just add up the floating point numbers and the round them with round() (http://www.php.net/manual/en/function.round.php) Certainlay for consistent calculations I'd always use the float values for as long as possible... Otherwise, why not multiply by 1000 before taking the intval, then at least you preserve the next decimal place. -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP] Converting floats to ints with intval
On 6 May 2010 11:52, Paul Waring p...@xk7.net wrote: If I was designing the system from scratch, that's what I'd do. Unfortunately this is an add-on to a legacy system where currency values are already stored as strings in the database (yes, not ideal I know, but you have to work with what you've got). I don't know much about your situation, but it does sound like you need to fix the root problem. I'd use a decimal type, and lean on the database to do the maths. http://dev.mysql.com/doc/refman/5.1/en/numeric-types.html You many also find money_format() useful: http://php.net/manual/en/function.money-format.php -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP] Converting floats to ints with intval
David Otton wrote: On 6 May 2010 11:52, Paul Waring p...@xk7.net wrote: If I was designing the system from scratch, that's what I'd do. Unfortunately this is an add-on to a legacy system where currency values are already stored as strings in the database (yes, not ideal I know, but you have to work with what you've got). I don't know much about your situation, but it does sound like you need to fix the root problem. I'd use a decimal type, and lean on the database to do the maths. As I said, unfortunately it's a legacy system, so I can't just change the database to use a different type (there are dozens of columns set up like this, with thousands of values already set). -- Paul Waring http://www.pwaring.com -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP] Converting floats to ints with intval
On Thursday 06 May 2010 07:19:48 Paul Waring wrote: David Otton wrote: On 6 May 2010 11:52, Paul Waring p...@xk7.net wrote: If I was designing the system from scratch, that's what I'd do. Unfortunately this is an add-on to a legacy system where currency values are already stored as strings in the database (yes, not ideal I know, but you have to work with what you've got). I don't know much about your situation, but it does sound like you need to fix the root problem. I'd use a decimal type, and lean on the database to do the maths. As I said, unfortunately it's a legacy system, so I can't just change the database to use a different type (there are dozens of columns set up like this, with thousands of values already set). Would It be possible to write a script to extract everything from that database and insert it into a database with the correct columns and values, then all you would need to do is change the db connection information. -- Blessings, David M. -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php
RE: [PHP] Converting floats to ints with intval
From: David McGlone On Thursday 06 May 2010 07:19:48 Paul Waring wrote: David Otton wrote: On 6 May 2010 11:52, Paul Waring p...@xk7.net wrote: If I was designing the system from scratch, that's what I'd do. Unfortunately this is an add-on to a legacy system where currency values are already stored as strings in the database (yes, not ideal I know, but you have to work with what you've got). I don't know much about your situation, but it does sound like you need to fix the root problem. I'd use a decimal type, and lean on the database to do the maths. As I said, unfortunately it's a legacy system, so I can't just change the database to use a different type (there are dozens of columns set up like this, with thousands of values already set). Would It be possible to write a script to extract everything from that database and insert it into a database with the correct columns and values, then all you would need to do is change the db connection information. If the data is really stored in strings, you need to break it down into substrings around the decimal and then convert both sides into integers and combine them into an integer value. It is the conversion into float that introduces the error because of the imprecise representation of fractional decimal values in binary. Bob McConnell -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP] Converting floats to ints with intval
David McGlone wrote: On Thursday 06 May 2010 07:19:48 Paul Waring wrote: David Otton wrote: On 6 May 2010 11:52, Paul Waring p...@xk7.net wrote: If I was designing the system from scratch, that's what I'd do. Unfortunately this is an add-on to a legacy system where currency values are already stored as strings in the database (yes, not ideal I know, but you have to work with what you've got). I don't know much about your situation, but it does sound like you need to fix the root problem. I'd use a decimal type, and lean on the database to do the maths. As I said, unfortunately it's a legacy system, so I can't just change the database to use a different type (there are dozens of columns set up like this, with thousands of values already set). Would It be possible to write a script to extract everything from that database and insert it into a database with the correct columns and values, then all you would need to do is change the db connection information. Possible, yes. Practical, no. :) -- Paul Waring http://www.pwaring.com -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP] Converting floats to ints with intval
On Thursday 06 May 2010 08:39:03 Bob McConnell wrote: From: David McGlone On Thursday 06 May 2010 07:19:48 Paul Waring wrote: David Otton wrote: On 6 May 2010 11:52, Paul Waring p...@xk7.net wrote: If I was designing the system from scratch, that's what I'd do. Unfortunately this is an add-on to a legacy system where currency values are already stored as strings in the database (yes, not ideal I know, but you have to work with what you've got). I don't know much about your situation, but it does sound like you need to fix the root problem. I'd use a decimal type, and lean on the database to do the maths. As I said, unfortunately it's a legacy system, so I can't just change the database to use a different type (there are dozens of columns set up like this, with thousands of values already set). Would It be possible to write a script to extract everything from that database and insert it into a database with the correct columns and values, then all you would need to do is change the db connection information. If the data is really stored in strings, you need to break it down into substrings around the decimal and then convert both sides into integers and combine them into an integer value. It is the conversion into float that introduces the error because of the imprecise representation of fractional decimal values in binary. I see. -- Blessings, David M. -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP] Converting floats to ints with intval
Paul Waring wrote: I've got the following script which demonstrates a problem I'm having with floating point numbers and intval: $times100 = (-37.12 * 100); print $times100 . \n; $intval100 = intval($times100); print $intval100 . \n; print ($intval100 / 100) . \n; I expect the output to be: -3712 -3712 -37.12 However, the actual output I'm getting (on several systems, so it's not just my machine) is: -3712 -3711 -37.11 Is there a reason for this, and a better way I should be doing it? Basically I need to add up a list of floats, representing currency values, and see if they're equal to another float, but I need to convert them to ints first because I can't guarantee than there won't be something after the second decimal place. This is a very well known problem in computer science: http://en.wikipedia.org/wiki/Floating_point To illustrate your example run the following: ?php $value = -37.12; echo Value: .sprintf( '%f', $value ). (what you think you have)\n; echo Value: .sprintf( '%f', $value ). (what the computer thinks you have)\n\n; $value *= 100; echo Value: .sprintf( '%f', $value ). (after multiply by 100)\n; echo Value: .sprintf( '%.20f', $value ). (what the computer thinks you have)\n\n; $value = intval( $value ); echo Value: .sprintf( '%d', $value ). (after type conversion to int)\n; echo Value: .sprintf( '%d', $value ). (what the computer thinks you have)\n\n; $value /= 100; echo Value: .sprintf( '%f', $value ). (after divide by 100)\n; echo Value: .sprintf( '%.20f', $value ). (what the computer thinks you have)\n\n; ? As you can see the values are tripped up at the multiplication stage where the computer can't perfectly store the value -3712.0 and then this is excerbated by the truncation of the value to an integer using intval(). If you want to avoid this, then you should avoid the conversion to int and use rounding for the final result. ?php $value = -37.12; $value *= 100; $value /= 100; echo Value: .sprintf( '%f', $value ). (after divide by 100)\n; echo Value: .sprintf( '%.20f', $value ). (what the computer thinks you have)\n; echo Value: .sprintf( '%.2f', $value ). (formatted with rounding)\n; ? Cheers, Rob. -- http://www.interjinn.com Application and Templating Framework for PHP -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php
Re: [PHP] Converting floats to ints with intval
I think Bob has a good idea here, split the string values and the concatenate them to make the whole value. If the data is really stored in strings, you need to break it down into substrings around the decimal and then convert both sides into integers and combine them into an integer value. It is the conversion into float that introduces the error because of the imprecise representation of fractional decimal values in binary. Bob McConnell -- PHP General Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php