1

I am not sure what I am doing wrong but this calculation

bcscale(20);
echo bcmul(bcdiv('422218', '2388865'), '473');

echoes "83.59999999999999999670" but every other calculator gives me 83.6.

Is there a way to solve this or is it a flaw in bcmath?

rmtheis
  • 5,992
  • 12
  • 61
  • 78
Zzzarka
  • 13
  • 3
  • 1
    That seems a construed example. Why don't you reorder the operations or simply use ordinary PHP float arithmetic if that is what you want? – mario Feb 22 '11 at 20:21

4 Answers4

5

The reason you see this result is because you first perform the division.

The division gives you:

422218/2388865
0.17674418604651162790697674418604651163

but you ask for 20 digits, so that becomes 0.1767441860465116279. In that light, bc gives you now the correct result:

0.1767441860465116279*473
83.5999999999999999967

A "solution" in this case would be to first perform the multiplication (which gives you "just" 9 digits) and then the division:

bcscale(20);
echo bcdiv(bcmul('422218','473'),'2388865');
83.60000000000000000000
Eelvex
  • 8,975
  • 26
  • 42
  • Yes! a proper solution without trickery. thank you! And now i think i will go and brush up on my math :) – Zzzarka Feb 22 '11 at 21:44
1

The bcmath functions use arbitrary precision arithmetic. The calculations aren't 100% precise - they're only as precise as you ask for (you asked for scale 20). Since the calculations aren't precise you can't always expect the answer to be precise.

You say that your calculator gives you the correct answer in this case. But assuming that it also uses arbitrary precision arithmetic (most do) it will give you the wrong answer in other cases. Some calculators hide their inaccuracy by calculating with a greater precision than they can display (for example an extra two digits). If you perform a calculation where the error builds up it will eventually become visible in the display.

Mark Byers
  • 811,555
  • 193
  • 1,581
  • 1,452
0

BCMath gives you exact result. If you need other number "form", use functions like round() to change it:

http://php.net/manual/en/function.round.php

For example:

echo round(bcmul(bcdiv('422218', '2388865'), '473'), 1);

Will give you 83.6.

Tomasz Kowalczyk
  • 10,472
  • 6
  • 52
  • 68
  • The exact result is `418/5` or `83.6`. – Eelvex Feb 22 '11 at 20:18
  • By "exact" result I mean exact number that is calculated by computer - as someone said it has limited precision, so result will be also "limited". – Tomasz Kowalczyk Feb 22 '11 at 20:19
  • @TomaszKowalczyk I see what i have done wrong and i will most likely use something like this to solve it, found a nice bcround() function in another question [link](http://stackoverflow.com/questions/1642614/how-to-ceil-floor-and-round-bcmath-numbers) that i think i will use to cut down the precision on the numbers i display. – Zzzarka Feb 22 '11 at 20:45
  • @Tomasz I think this answer is misleading and hides the underlying problem. In this case, for example, you can just swap the order of div and mul and have the exact, correct result. Please, since it's the accepted answer, at least make a comment for that. – Eelvex Feb 22 '11 at 20:52
  • @Eelvex how do you mean should i run 473*(422218/2388865) ? that seams to give me the same answer as above.. – Zzzarka Feb 22 '11 at 21:22
  • @Zzzarka: I mean `(473*422218)/2388865`; see [my answer](http://stackoverflow.com/questions/5083380/bcmath-seams-to-give-the-wrong-answer-to-my-calculation/5083529#5083529) – Eelvex Feb 22 '11 at 21:34
  • It's no longer accepted answer, so no comment is needed. ;] But I'd argue if I'm supposed to make any comment - it's a numeric problem, but given this exact code my answer is correct. – Tomasz Kowalczyk Feb 23 '11 at 01:01
  • @Tomasz: Off course it's correct; it's just that `round` as a solution is kind of misleading. – Eelvex Feb 24 '11 at 17:07
0

You've specified more precision (20 digits) than most calculators can carry. So they'll round it off, most likely to 10 or 15 digits, giving 83.5999...99, which rounds to 83.6.

Marc B
  • 356,200
  • 43
  • 426
  • 500