I'm just writing a script to enter payments into a database and allocate them to various categories. It seemed to be working OK until I came to enter a particular set of values.

If I enter 20.56 into $bank_uk and allocate for example 11.75 and 8.81 to categories the script echos the total amount entered (20.56) and the total allocated amount (20.56) but says that they do not match!

If I enter 20.57 into $bank_uk and allocate for example 11.76 and 8.81 to categories the script succesfully enters the correct amounts into the database and displays the result!

Does anyone know why this strange behaviour should occur? I've tried all sorts of amounts and only the first case above seems to fail to validate.

	$total_entered = 0; // initialise total amount to check against total allocated
	if (!empty($_POST['bank_uk'])) {
		$bank_uk = $_POST['bank_uk'];
		$total_entered = $total_entered + $bank_uk;
		$insert_query_fields = "bank_uk, ";
		$insert_query_values = "'$bank_uk', ";
	} else {
		$bank_uk = NULL;
	}

// check that funds have been allocated and that totals agree with amount of cash/bank entered
$allocation = 0; // initialise total amount allocated to a category


if (!empty($_POST['domains'])) {
	$domains = $_POST['domains'];
	$allocation = $allocation + $domains;
	$insert_query_fields .= "domains, ";
	$insert_query_values .= "'$domains', ";
} else {
	$domains = NULL;
}

if (!empty($_POST['travel'])) {
	$travel = $_POST['travel'];
	$allocation = $allocation + $travel;
	$insert_query_fields .= "travel, ";
	$insert_query_values .= "'$travel', ";
} else {
	$travel = NULL;
}

if (!empty($_POST['premises'])) {
	$premises = $_POST['premises'];
	$allocation = $allocation + $premises;
	$insert_query_fields .= "premises, ";
	$insert_query_values .= "'$premises', ";
} else {
	$premises = NULL;
}


if ($allocation != $total_entered) {
	$allocated = FALSE;
	$allocation_msg = "Amount(s) entered do not match amount(s) allocated<br />Total entered = $total_entered<br />Allocated = $allocation<br />";
} else if ($allocation <= 0) {
	$allocated = FALSE;
	$allocation_msg = "Funds not allocated<br />";
} else  {
	$allocated = TRUE;
	$allocation_msg = NULL;
}

    Three words: floating point arithmetic (Google it for more details).

    Computers that do their arithmetic in binary cannot represent one-tenth exactly; they have to approximate it. Same way that one-seventh cannot be represented in decimal exactly: 0.142857........

    In particular, 20.56 gets stored (after translating back into decimal) as something more like 20.559999999999998721, 11.75 as 11.75 (that one just happens to be exact, since three-quarters can be represented exactly in binary as 0.11), and 8.81 as 8.81000000000000049738. And 11.75+8.81000000000000049738 == 20.56000000000000049738 != 20.559999999999998721 - even if they look the same if you round them off to two (or twelve) decimal places.

    Practical upshot: don't perform arithmetic on decimal numbers and expect exact results: always regard them as being a little bit fuzzy.

    Store 2057, 1176 and 881 and work with those numbers instead of 20.57, 11.76 and 8.81.

      Thanks. I wondered if it might be something like this, but didn't know if or why it should be. 🙂

      I've got round it by using number_format on them before comparing them - with the simple additions involved I think that will function OK. I'm about to test it with a currency conversion as well, so we'll see!

      BTW when I post or reply in this forum I'm getting the following above the rest of the page:

      Warning: strpos(): Empty delimiter. in /global.php(349) : eval()'d code on line 9
      
      Warning: strpos(): Empty delimiter. in /global.php(349) : eval()'d code on line 9
      
      Warning: strpos(): Empty delimiter. in /global.php(349) : eval()'d code on line 9
      
      Warning: strpos(): Empty delimiter. in /global.php(349) : eval()'d code on line 9
        Write a Reply...