473,397 Members | 1,960 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,397 software developers and data experts.

Missing 0.0000001 - driving me crazy - help!

mat
Hi all,

This is weird and it is driving me nuts, please can someone explain how
I can get it to return the correct answer:

print '$_SESSION["a"]: '.$_SESSION["a"].'<br />';
print '$_SESSION["c"]: '.$_SESSION["c"].'<br />';
print $_SESSION["c"]." - ".$_SESSION["a"].' =
'.($_SESSION["c"]-$_SESSION["a"]);

----------------- RETURNS -----------------------

$_SESSION["allowance"]: 200
$_SESSION["cart_value"]: 200.15
200.15 - 200 = 0.14999999999998

When I test on my windows box it is correct, but not when I test on my
Unix server.

Your help would be *greatly* appreciated.

mat
Dec 5 '05 #1
14 1743
Variables are held to s certain degree of precision. 200.15 cannot be
held accurately as a normal binary number, for example, so errors can
occur.

Use bcsub(200.15,200,n) where n is the number of decimal places you
want.

Ian

Dec 5 '05 #2
"mat" wrote:
Hi all,

This is weird and it is driving me nuts, please can someone explain how
I can get it to return the correct answer:

print '$_SESSION["a"]: '.$_SESSION["a"].'<br />';
print '$_SESSION["c"]: '.$_SESSION["c"].'<br />';
print $_SESSION["c"]." - ".$_SESSION["a"].' =
'.($_SESSION["c"]-$_SESSION["a"]);

----------------- RETURNS -----------------------

$_SESSION["allowance"]: 200
$_SESSION["cart_value"]: 200.15
200.15 - 200 = 0.14999999999998

When I test on my windows box it is correct, but not when I test on my
Unix server.


Your Windows box is just rounding the number up for you.

0.15 is an infinitely long number in binary [1], just like 3/10 is equal to
0.3333333333... in decimal notation

Try using sprintf [2] to tidy up your results.

[1] 0.00100110011001100110011001100...
[2] http://php.net/sprintf

--
phil [dot] ronan @ virgin [dot] net
http://vzone.virgin.net/phil.ronan/

Dec 5 '05 #3
"Philip Ronan" wrote:
0.15 is an infinitely long number in binary [1], just like 3/10 is equal to
0.3333333333... in decimal notation


Oops, "1/3" not "3/10"

--
phil [dot] ronan @ virgin [dot] net
http://vzone.virgin.net/phil.ronan/

Dec 5 '05 #4
mat
Thanks Philip and Ian, a real help.

Working on what Philip said about Windows just rounding, I did the same
and it works for me:

round($_SESSION["c"]-$_SESSION["a"],2)

Is this wrong / ill advised for any reason? Or just another way...

Thank you,

Mat
Dec 5 '05 #5
"mat" wrote:
Thanks Philip and Ian, a real help.

Working on what Philip said about Windows just rounding, I did the same
and it works for me:

round($_SESSION["c"]-$_SESSION["a"],2)

Is this wrong / ill advised for any reason? Or just another way...


No, that's fine. Just bear in mind that the round() function returns a
floating point value, so you still shouldn't expect it to be exactly equal
to the rounded number.

This is a problem common to all programming languages, not just PHP. You
should never expect floating point values to be exactly equal to anything.
Code like this just won't work properly:

$x = 1/10;
if ($x == 0.1) { ... do something ...}

--
phil [dot] ronan @ virgin [dot] net
http://vzone.virgin.net/phil.ronan/

Dec 5 '05 #6
round() converts the result of whatever is between the parentheses to a
float and rounds that up to whatever number of decimals you want, so
you start getting problems around the 15th decimal.

The bcmath functions work on strings to whatever degree of accuracy you
ask for and will never produce errors.

So basically if you round up to fewer than, say ten decimals, ordinary
maths functions are fine, but more than that, use bcmath.

Of course, with ints you just get ints back.

Ian

Dec 5 '05 #7
>print '$_SESSION["a"]: '.$_SESSION["a"].'<br />';
print '$_SESSION["c"]: '.$_SESSION["c"].'<br />';
print $_SESSION["c"]." - ".$_SESSION["a"].' =
'.($_SESSION["c"]-$_SESSION["a"]);

----------------- RETURNS -----------------------

$_SESSION["allowance"]: 200
$_SESSION["cart_value"]: 200.15
200.15 - 200 = 0.14999999999998

When I test on my windows box it is correct, but not when I test on my
Unix server.


There is no exact representation of 0.15 in binary floating point.
I suggest not printing so many digits after the decimal point.
printf() should round it.

0.15 as double:
Before: 0.149999999999999966693309261245303787291049957275 390625000000
Value: 0.149999999999999994448884876874217297881841659545 898437500000
After: 0.150000000000000022204460492503130808472633361816 406250000000

0.15 as float:
Before: 0.149999991059303283691406250000000000000000000000 000000000000
Value: 0.150000005960464477539062500000000000000000000000 000000000000
After: 0.150000020861625671386718750000000000000000000000 000000000000

Gordon L. Burditt
Dec 5 '05 #8
>Variables are held to s certain degree of precision. 200.15 cannot be
held accurately as a normal binary number, for example, so errors can
occur.

Use bcsub(200.15,200,n) where n is the number of decimal places you
want.


Any attempt to round to "a number of decimal places" will virtually
guarantee roundoff error. There are very few non-integer decimal
numbers which can be represented exactly in binary floating
point. All of them end in 5 (plus trailing zeroes).

Gordon L. Burditt
Dec 5 '05 #9

Gordon Burditt wrote:
Variables are held to s certain degree of precision. 200.15 cannot be
held accurately as a normal binary number, for example, so errors can
occur.

Use bcsub(200.15,200,n) where n is the number of decimal places you
want.


Any attempt to round to "a number of decimal places" will virtually
guarantee roundoff error. There are very few non-integer decimal
numbers which can be represented exactly in binary floating
point. All of them end in 5 (plus trailing zeroes).

Gordon L. Burditt


bcsub doesn't round

Dec 5 '05 #10
On Mon, 05 Dec 2005 11:14:32 +0000, mat <yu********************@yahoo.co.uk>
wrote:
Thanks Philip and Ian, a real help.

Working on what Philip said about Windows just rounding, I did the same
and it works for me:

round($_SESSION["c"]-$_SESSION["a"],2)

Is this wrong / ill advised for any reason? Or just another way...


You appear to be working with monetary values from the names in your original
post. You shouldn't use floating point numbers for money; use integers,
multiplied up to the minor currency. So £1.50 = 150.

This way the floating point inaccuracies (which are not specific to Windows or
PHP, they are fundamental to the way x86 and many other processors handle
floating point numbers) don't become an issue, because you're always dealing
with exact integer calculations.
--
Andy Hassall :: an**@andyh.co.uk :: http://www.andyh.co.uk
http://www.andyhsoftware.co.uk/space :: disk and FTP usage analysis tool
Dec 5 '05 #11
"Andy Hassall" wrote:
You appear to be working with monetary values from the names in your original
post. You shouldn't use floating point numbers for money; use integers,
multiplied up to the minor currency. So £1.50 = 150.


There might be a good reason for using floats. For example, all your sales
tax calculations will be rounded down if you use integers.

--
phil [dot] ronan @ virgin [dot] net
http://vzone.virgin.net/phil.ronan/

Dec 5 '05 #12
On Mon, 05 Dec 2005 19:41:25 +0000, Philip Ronan <in*****@invalid.invalid>
wrote:
"Andy Hassall" wrote:
You appear to be working with monetary values from the names in your original
post. You shouldn't use floating point numbers for money; use integers,
multiplied up to the minor currency. So £1.50 = 150.


There might be a good reason for using floats. For example, all your sales
tax calculations will be rounded down if you use integers.


Then you can multiply up to the number of decimal places required by your tax
authority and apply their rounding rules (up or down) - more deterministic than
having small but unpredictable amounts of money being lost or gained due to
non-exact float representations. Depending on how many decimals you pick, the
32-bit limits on integers (31 bits for signed) could then become a problem for
large transactions or monthly/yearly totals.
--
Andy Hassall :: an**@andyh.co.uk :: http://www.andyh.co.uk
http://www.andyhsoftware.co.uk/space :: disk and FTP usage analysis tool
Dec 6 '05 #13
Andy Hassall (an**@andyh.co.uk) wrote:
: On Mon, 05 Dec 2005 19:41:25 +0000, Philip Ronan <in*****@invalid.invalid>
: wrote:

: >"Andy Hassall" wrote:
: >
: >> You appear to be working with monetary values from the names in your original
: >> post. You shouldn't use floating point numbers for money; use integers,
: >> multiplied up to the minor currency. So £1.50 = 150.
: >
: >There might be a good reason for using floats. For example, all your sales
: >tax calculations will be rounded down if you use integers.

: Then you can multiply up to the number of decimal places required by your tax
: authority and apply their rounding rules (up or down) - more deterministic than
: having small but unpredictable amounts of money being lost or gained due to
: non-exact float representations. Depending on how many decimals you pick, the
: 32-bit limits on integers (31 bits for signed) could then become a problem for
: large transactions or monthly/yearly totals.

(My understanding, feel free to argue.)

Computer double size floating point numbers can perform calculations on
integer _values_ with out integer value errors (exactly like integer
numbers do).

But the computer double can represent a much larger range of exact integer
values.

So to avoid 32-bit limits on integer numbers, scale the value to create an
integer value (just like you suggest), but store and manipulate that value
using doubles.

I guess the only issue would be to determine if any part of a caculation's
integer result went beyond the range of what could be represented exactly,
but I think that question also arises if you use plain integers anyway, so
I'm not sure this is an additional problem. E.g. if you multiply two
large integers using integer arithmentic then the resulting value may not
be correct and you don't get an error to warn you - at least that is what
I confirmed in one quick test using one C compiler to multiple two large
integers.


--

This programmer available for rent.
Dec 6 '05 #14
On 6 Dec 2005 11:04:51 -0700, yf***@vtn1.victoria.tc.ca (Malcolm Dew-Jones)
wrote:
Computer double size floating point numbers can perform calculations on
integer _values_ with out integer value errors (exactly like integer
numbers do).

But the computer double can represent a much larger range of exact integer
values.


Makes sense - you can go up to 2^53 in an exact form in a double using just
the significand without using the exponent bits.
--
Andy Hassall :: an**@andyh.co.uk :: http://www.andyh.co.uk
http://www.andyhsoftware.co.uk/space :: disk and FTP usage analysis tool
Dec 6 '05 #15

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

4
by: dont bother | last post by:
This is really driving me crazy. I have a dictionary feature_vectors{}. I try to sort its keys using #apply sorting on feature_vectors sorted_feature_vector=feature_vectors.keys()...
6
by: Keiron Waites | last post by:
Please see the problem in action here: http://www.leadbullet.biz/contact.php If you mouse over the fields, you will see that text is shown on the right. The text makes the other fields move when...
10
by: vbnetrookie | last post by:
Hi all, I want to add a column to my db table with numbers starting at 0000001 and going t'ill the end...It has 2.7 millions entries..so it should be around .. 2700000. I really need the first...
0
by: Shapper | last post by:
Hello, I have this code in Global.asax: Sub Session_Start(Sender As Object, E As EventArgs) Dim cookie As HttpCookie = Request.Cookies("MyCookie") If Not cookie Is Nothing Then...
5
by: JohnR | last post by:
Hi all, I have an application that uses a custom DLL. The DLL needs to be in the same directory as the executable. If it's not I want to catch the error and give a meaningful message to the...
1
by: Miguel Dias Moura | last post by:
Hello, I have been trying, for days, to retrieve a control's ClientId in a javascript function. I am using a master page and this is why I need to retrieve the Control's ClientId. The control...
5
by: Pupeno | last post by:
Hello, I am experiencing a weird behavior that is driving me crazy. I have module called Sensors containing, among other things: class Manager: def getStatus(self): print "getStatus(self=%s)"...
3
by: rashpal.sidhu | last post by:
Please help, this problem is driving me crazy !! I am using metaphone to create phonetic keys. When i run the module stand-a-lone it works fine. I'm trying to create a runner for informix...
2
by: kheitmann | last post by:
OK, so I have a blog. I downloaded the "theme" from somewhere and have edited a few areas to suit my needs. There are different font themes within the page theme. Long story short, my "Text Posts"...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.