#### Do you have a question? Post it now! No Registration Necessary. Now with pictures!

**posted on**

December 5, 2005, 10:18 am

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

## Re: Missing 0.0000001 - driving me crazy - help!

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

## Re: Missing 0.0000001 - driving me crazy - help!

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/

## Re: Missing 0.0000001 - driving me crazy - help!

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/

## Re: Missing 0.0000001 - driving me crazy - help!

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

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

## Re: Missing 0.0000001 - driving me crazy - help!

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.

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 :: andy@andyh.co.uk :: http://www.andyh.co.uk

http://www.andyhsoftware.co.uk/space :: disk and FTP usage analysis tool

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 :: andy@andyh.co.uk :: http://www.andyh.co.uk

http://www.andyhsoftware.co.uk/space :: disk and FTP usage analysis tool

## Re: Missing 0.0000001 - driving me crazy - help!

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 :: andy@andyh.co.uk :: http://www.andyh.co.uk

http://www.andyhsoftware.co.uk/space :: disk and FTP usage analysis tool

## Re: Missing 0.0000001 - driving me crazy - help!

Andy Hassall (andy@andyh.co.uk) wrote:

: 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

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.

: 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 integernumbers 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.

## Re: Missing 0.0000001 - driving me crazy - help!

On 6 Dec 2005 11:04:51 -0700, yf110@vtn1.victoria.tc.ca (Malcolm Dew-Jones)

wrote:

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 :: andy@andyh.co.uk :: http://www.andyh.co.uk

http://www.andyhsoftware.co.uk/space :: disk and FTP usage analysis tool

wrote:

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 :: andy@andyh.co.uk :: http://www.andyh.co.uk

http://www.andyhsoftware.co.uk/space :: disk and FTP usage analysis tool

## Re: Missing 0.0000001 - driving me crazy - help!

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.149999999999999966693309261245303787291049957275390625000000

Value: 0.149999999999999994448884876874217297881841659545898437500000

After: 0.150000000000000022204460492503130808472633361816406250000000

0.15 as float:

Before: 0.149999991059303283691406250000000000000000000000000000000000

Value: 0.150000005960464477539062500000000000000000000000000000000000

After: 0.150000020861625671386718750000000000000000000000000000000000

Gordon L. Burditt

#### Site Timeline

- » PHP Guestbook list on PHPKode.com
- — Next thread in » PHP Scripting Forum

- » Need help getting a script for huge inserts
- — Previous thread in » PHP Scripting Forum

- » URL redirection
- — Newest thread in » PHP Scripting Forum

- » Seamless SSO
- — Last Updated thread in » PHP Scripting Forum

- » SSD partition alignment revisited
- — The site's Newest Thread. Posted in » Computer Hardware