0

I have 3 numbers returned from a database that I need to add together. For a total of 1,740.01, I get like 10.00. These are floating point numbers. Here are the actual numbers I'm having a problem with.

> 1,729.13
> 10.88
> 0.00

How do I get the correct total of these numbers?

EDIT

$cash = preg_replace('/\$/', '', $cash);
$card = preg_replace('/\$/', '', $card);
$check = preg_replace('/\$/', '', $check);

$cash = number_format(array_sum($cash), 2);
$card = number_format(array_sum($card), 2);
$check = number_format(array_sum($check), 2);
$total  = number_format( $cash + $card + $check, 2 );
Jim
  • 3
  • 4
  • What data type are they in the database? – Pekka Jan 30 '11 at 12:22
  • The total is 1,740.01, in case you're wondering. If you need more, it'd be delightful to see the code you're using, so we can help fix it. – Sebastian Paaske Tørholm Jan 30 '11 at 12:22
  • possible duplicate of [PHP Math Precision](http://stackoverflow.com/questions/3726721/php-math-precision), [Rounding in PHP](http://stackoverflow.com/questions/3512663/rounding-in-php), [How to fix this problem in PHP?](http://stackoverflow.com/questions/1995226/how-to-fix-this-problem-in-php) – outis Jan 30 '11 at 12:23
  • Isn't 1740.01 what I have in the post? – Jim Jan 30 '11 at 12:23
  • @jim, see http://stackoverflow.com/posts/4842845/revisions for what happened to your original number. – sarnold Jan 30 '11 at 12:28
  • @Jim you need to add some more context and code for us to work with. – Pekka Jan 30 '11 at 12:28
  • #Pekka, They are decimal 10,7 – Jim Jan 30 '11 at 12:28
  • Methinks @outis needs a math lesson :-) He added the floating-point tag and, for some inexplicable reason, changed the total to the incorrect 2400. – paxdiablo Jan 30 '11 at 12:29
  • @sarnold, I rolled it back. Why he rolled back my corrected math is beyond me. – Jim Jan 30 '11 at 12:30
  • ... [Problem with Floats! (in PHP)](http://stackoverflow.com/questions/4276516/problem-with-floats-in-php) – outis Jan 30 '11 at 12:31
  • The only thing I edited was the tag. I have no idea why the question body was changed. @Jim: did you enter 2400.10 when you first asked the question, then change it to 1740.01 within 5 minutes? If so, that edit was stomped by my tag edit (SO doesn't count edits made within 5 minutes by the same user to be new revisions). – outis Jan 30 '11 at 12:32
  • @Jim you need to show some actual code – Pekka Jan 30 '11 at 12:34
  • Ah, good point @outis, I didn't think about concurrent edits. That is one possible explanation. Apologies for questioning your sanity :-) – paxdiablo Jan 30 '11 at 12:35
  • @paxdiabolo: the evidence is against me, I must admit. – outis Jan 30 '11 at 12:36
  • @Outis, I looked at the revision and the $1740 was canceled out and the 2400 was put back. It looked like it came from you because your name was in the edit. Anyhow, it's all good. :) – Jim Jan 30 '11 at 12:36
  • @Pekka, There is something wrong because when I add three numbers together, I get the correct result. Ket me post more code up top. – Jim Jan 30 '11 at 12:37
  • We still need some code from Jim to show how he's adding these numbers. This isn't a simple rounding issue with the degree of inaccuracy – Mark Baker Jan 30 '11 at 12:38
  • Are the $cash, $card and $check values arrays or floats? If the former, then preg_replace isn't going to work, if the latter, then why are you using array_sum? – Mark Baker Jan 30 '11 at 12:43
  • @Mark, preg_replace returns an array, so they are in array format. What do you recommend? – Jim Jan 30 '11 at 12:45
  • @Jim: aim for sample code that's [complete, self-contained and minimized](http://sscce.org/). As-is, the sample can't simply be copy-and-pasted into a PHP interpreter. Any additional code we have to write may not result in the same behavior you're experiencing. Also, `preg_replace` can take an array of strings as the third argument, which is the only situation in which it will return an array. – outis Jan 30 '11 at 12:50

1 Answers1

2

Don't add values that have been formatted using number_format(), otherwise they may well contain , as a thousand's separator... they're treated as strings rather than floats.

Assuming that $cash, $card and $check are arrays:

$cash = array_sum($cash);
$card = array_sum($card);
$check = array_sum($check);

$total  = number_format( $cash + $card + $check, 2 ); 

$cash = number_format( $cash, 2 );
$card = number_format( $card, 2 );
$check = number_format( $check, 2 );

Do any formatting after the math

EDIT

Use str_replace() rather than preg_replace() to strip out any $, then it's simple addition rather than needing to do the array_sum(), though I'm not sure where any $ is likely to come from if the values are DECIMAL 10,7 from the database

$cash = (float) str_replace( array('$',','), '', $cash );
$card = (float) str_replace( array('$',','), '', $card );
$check = (float) str_replace( array('$',','), '', $check );

$total  = number_format( $cash + $card + $check, 2 ); 

$cash = number_format( $cash, 2 );
$card = number_format( $card, 2 );
$check = number_format( $check, 2 );

(assumes that , is your thousands separator in the string values for $cash, $card and $check when doing the str_replace()

EDIT 2

To convert the $cash array to a sum of its values, having cleaned up any $ or , in the strings:

$cash = array ( 0 => '$1729.13', 1 => '0.00', 2 => '$1,234.56' );

function cleanArrayValues($value) {
    return (float) str_replace( array('$',','), '', $value );
}

$cash = array_sum(array_map('cleanArrayValues',$cash));

I've added an extra value into the $cash array just to demonstrate.

You'll need to filter $card and $checks in the same way, using the cleanArrayValues() callback function (if they're all arrays)

Mark Baker
  • 209,507
  • 32
  • 346
  • 385
  • Thanks Mark, just answered you above. The variables are arrays from pref_replace. So you're saying that I need to add these numbers together and then use number_format? – Jim Jan 30 '11 at 12:47
  • Just make sure they're numbers not strings. A `,` in `1,729.13` makes PHP cast the entire number to `1`. – Mchl Jan 30 '11 at 12:49
  • @Mark, thanks. These are values that I'm using elsewhere in my code so I needed to strip off the dollar sign. Thanks for the edit and example. I'll give this a shot now. – Jim Jan 30 '11 at 12:54
  • Mark, are you still around? I'm having another issue. – Jim Jan 30 '11 at 13:17
  • @Jim - If it's the same problem, then edit your original post here, else raise it as another question – Mark Baker Jan 30 '11 at 13:20
  • It is, Mark. My 'subject' portion in your str_replace function is an array. What is being returned from str_replace is a '1' instead of the actual database values. – Jim Jan 30 '11 at 13:25
  • This is a print_r of my $cash array: Array ( [0] => $1729.13 [1] => 0.00 ) – Jim Jan 30 '11 at 13:26
  • What exactly does your array contain? Are there multiple entries in the array? If so, you might well need to use array_map() or array_walk() to unformat the values. Use var_dump($cash) etc to check exactly what values you have in the array. – Mark Baker Jan 30 '11 at 13:28
  • OK, They are strings. Here is the dump: array(2) { [0]=> string(8) "$1729.13" [1]=> string(4) "0.00" } – Jim Jan 30 '11 at 13:30
  • Mark, that you very much. I just found your second edit. I was using array_sum before and it seemed to do what I needed. Can I ask, what is your code doing that array_sum isn't? I'm just curious. – Jim Jan 30 '11 at 13:55
  • Strike that last comment. I see it now. Thanks again for the help, Mark. – Jim Jan 30 '11 at 13:56