0

Got a bit of a head scratcher. I'm loading values fro a CSV, casting them to be a float, doing some simple arithmetic then comparing the result with a 4th value and logging an error if the results do not match.

$CsvArrayLine[2] = (float) $CsvArrayLine[2];
$CsvArrayLine[3] = (float) $CsvArrayLine[3];
$CsvArrayLine[4] = (float) $CsvArrayLine[4];

$GwTempTotal = $CsvArrayLine[2] +  $CsvArrayLine[3];
$GwTempTotal = $GwTempTotal * $CsvArrayLine[4];
$GwTempGiven = (float) $CsvArrayLine[5];

if ($GwTempTotal != $GwTempGiven){
    var_dump($GwTempTotal);
    echo "</br>";
    var_dump($GwTempGiven);
    echo "</br>";
    $GwErrorArray[] = array("03","$CsvArrayLine[0]"," $GwTempTotal each cost + pack each cost x pack does not = gross, this is BAD</br>");
}

Which is all good and for 24 lines of the 29 I'm testing it works fine. 5 of the lines however give an error even though the values are identical. The output from the var_dumps is that they are all floats and that they are all the same.

Is there anything obvious I'm missing that someone can see?

  • Try to avoid doing things like `"$CsvArrayLine[0]"` when you really want `$CsvArrayLine[0]`. – tadman Nov 03 '17 at 17:19
  • 1
    Would this be an issue of float error? Comparing floats, vs outputting floats... tends to be different results? – IncredibleHat Nov 03 '17 at 17:21
  • 1
    You really shouldn't use floats for currency values. You will get rounding errors and comparison errors. See also https://stackoverflow.com/questions/3730019/why-not-use-double-or-float-to-represent-currency and https://stackoverflow.com/questions/316727/is-a-double-really-unsuitable-for-money for example. – Simba Nov 03 '17 at 17:25
  • 1
    You should really include sample data! – Barthy Nov 03 '17 at 17:41
  • 1
    Hey guys thanks for the input. @tadman whilst that's not strictly part of the problem I'm having I'll be sure to check that out. – Gareth Westwood Nov 03 '17 at 22:12
  • @Randall, thanks. Not sure how I got to 37 years of age, working in IT for most of them without coming across this before! Thanks. – Gareth Westwood Nov 03 '17 at 22:17
  • and @Simba, as above. – Gareth Westwood Nov 03 '17 at 22:17
  • @Barthy thanks, I probably should have done and will bear that in mind for the next time. – Gareth Westwood Nov 03 '17 at 22:18
  • I've fought float rounding errors in prices for years too. Drives me nuts... and I usually punt and number_format everything haha. – IncredibleHat Nov 03 '17 at 22:34

2 Answers2

0

The nature of floating-point values in PHP is such that you should never use normal comparison operators. Instead, decide upon the smallest acceptable difference and use a comparison like:

if (abs(($a-$b)/$b) < 0.00001) {
  echo "same";
}

(hat tip @Joey)

If you absolutely must do "exact" comparisons of floating-point numbers and absolutely must do it in PHP, your best bet is to use BC Math Functions.

Ben Shoval
  • 1,732
  • 1
  • 15
  • 20
  • So, the received logic for currency calculations is to convert to pence/cents and use int's I presume. – Gareth Westwood Nov 03 '17 at 22:28
  • @GarethWestwood If all you’re dealing with is currency with a knowable number of digits after the decimal point, then just use integers. The easiest thing to do in the case of normal currency numbers (pounds for two digit pence, dollars for two digit cents, etc.) is to simply multiply by 100 to produce a decimal at intake. – Ben Shoval Nov 03 '17 at 22:43
0

Thanks to everyone who replied, it all pointed me in the right direction. I have gone with;

$CsvArrayLine[2] = (int) round($CsvArrayLine[2]*100);

For all the lines dealing with cash values (I've actually rounded nearly everything!) and that now seems to be working a whole lot better.

Thanks again for the help