-1

Consider this array

    array(6) {
  ["id"]=>
  int(346058)
  ["amount"]=>
  string(5) "60.00"
  ["id_shop_where_transaction_is_done"]=>
  int(300)
  ["id_shop_where_money_come_from"]=>
  NULL
  ["negative_sum"]=>
  float(-60)
  ["negative"]=>
  array(11) {
    [0]=>
    array(5) {
      ["id"]=>
      int(346060)
      ["amount"]=>
      string(5) "-2.20"
      ["id_shop_where_transaction_is_done"]=>
      int(300)
      ["id_shop_where_money_come_from"]=>
      NULL
      ["id_referring_transaction"]=>
      int(346058)
    }
    [1]=>
    array(5) {
      ["id"]=>
      int(348152)
      ["amount"]=>
      string(5) "-7.50"
      ["id_shop_where_transaction_is_done"]=>
      int(300)
      ["id_shop_where_money_come_from"]=>
      NULL
      ["id_referring_transaction"]=>
      int(346058)
    }
    [2]=>
    array(5) {
      ["id"]=>
      int(350163)
      ["amount"]=>
      string(5) "-7.70"
      ["id_shop_where_transaction_is_done"]=>
      int(300)
      ["id_shop_where_money_come_from"]=>
      NULL
      ["id_referring_transaction"]=>
      int(346058)
    }
    [3]=>
    array(5) {
      ["id"]=>
      int(351996)
      ["amount"]=>
      string(5) "-5.20"
      ["id_shop_where_transaction_is_done"]=>
      int(300)
      ["id_shop_where_money_come_from"]=>
      NULL
      ["id_referring_transaction"]=>
      int(346058)
    }
    [4]=>
    array(5) {
      ["id"]=>
      int(353919)
      ["amount"]=>
      string(5) "-5.00"
      ["id_shop_where_transaction_is_done"]=>
      int(300)
      ["id_shop_where_money_come_from"]=>
      NULL
      ["id_referring_transaction"]=>
      int(346058)
    }
    [5]=>
    array(5) {
      ["id"]=>
      int(354768)
      ["amount"]=>
      string(5) "-2.50"
      ["id_shop_where_transaction_is_done"]=>
      int(300)
      ["id_shop_where_money_come_from"]=>
      NULL
      ["id_referring_transaction"]=>
      int(346058)
    }
    [6]=>
    array(5) {
      ["id"]=>
      int(356650)
      ["amount"]=>
      string(5) "-5.00"
      ["id_shop_where_transaction_is_done"]=>
      int(300)
      ["id_shop_where_money_come_from"]=>
      NULL
      ["id_referring_transaction"]=>
      int(346058)
    }
    [7]=>
    array(5) {
      ["id"]=>
      int(361683)
      ["amount"]=>
      string(5) "-5.00"
      ["id_shop_where_transaction_is_done"]=>
      int(300)
      ["id_shop_where_money_come_from"]=>
      NULL
      ["id_referring_transaction"]=>
      int(346058)
    }
    [8]=>
    array(5) {
      ["id"]=>
      int(361836)
      ["amount"]=>
      string(5) "-7.50"
      ["id_shop_where_transaction_is_done"]=>
      int(300)
      ["id_shop_where_money_come_from"]=>
      NULL
      ["id_referring_transaction"]=>
      int(346058)
    }
    [9]=>
    array(5) {
      ["id"]=>
      int(364145)
      ["amount"]=>
      string(5) "-7.90"
      ["id_shop_where_transaction_is_done"]=>
      int(300)
      ["id_shop_where_money_come_from"]=>
      NULL
      ["id_referring_transaction"]=>
      int(346058)
    }
    [10]=>
    array(5) {
      ["id"]=>
      int(364426)
      ["amount"]=>
      string(5) "-4.50"
      ["id_shop_where_transaction_is_done"]=>
      int(300)
      ["id_shop_where_money_come_from"]=>
      NULL
      ["id_referring_transaction"]=>
      int(346058)
    }
  }
}

A bit of explain:

$array[0]['negative_sum']

is the sum of the $array[0]['negative'][$i]['amount']

(If you do the sum, total is -60.)

Now, I need to check if $array[0]['amount'] is > of the negative_sum and so some stuff.

$positive_amount = $transaction[$i]['amount'];
$negative_amount = $transaction[$i]['negative_sum'];

if ($positive_amount>abs($negative_amount)) {


    $difference = -$positive_amount-$negative_amount;

    var_dump($difference);

    $data['difference'] = $difference;

}

First of all, the if code in specific case would not be executed, because 60 is not bigger than abs(-60). But it is executed.

Second one, var_dump($difference) output is

float(-7,105427357601E-15)

cannot understand why. Thank you.

Per @OptimusCrime answer. I did modify a bit the code.

$positive_amount = $transaction[$i]['amount'];
$negative_amount = $transaction[$i]['negative_sum'];

var_dump(number_format($positive_amount, 90));
var_dump(number_format($negative_amount, 90));

if ($positive_amount>abs($negative_amount)) {


    $difference = -$positive_amount-$negative_amount;

    var_dump($difference);

    $data['difference'] = $difference;

}

That var_dump outputs both:

string(93) "60.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000" 
string(94) "-60.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"
sineverba
  • 5,059
  • 7
  • 39
  • 84
  • 2
    [What every developer should know about floating point](http://floating-point-gui.de/) – Mark Baker Sep 13 '17 at 09:49
  • 2
    Then read the [PHP Docs about floats](http://www.php.net/manual/en/language.types.float.php), with that big warning message, and that section devoted to comparisons with float values – Mark Baker Sep 13 '17 at 09:49
  • 1
    Possible duplicate of [PHP - Floating Number Precision](https://stackoverflow.com/questions/3726721/php-floating-number-precision) – Qirel Sep 13 '17 at 09:56

1 Answers1

2

Floating numbers are difficult to represent correctly. The result of this is that you can not always know for sure that there are no insignificant values in the floating numbers. As illustrated in this 3v4l.org snippet, the sum of your numbers are evaluated as -60.0:

$sum = array_sum([-2.20, -7.50, -7.70, -5.20, -5.00, -2.50, -5.00, -5.00, -7.50, -7.90, -4.50]);
var_dump($sum); // float(-60)

However, what you don't see is the true float value:

var_dump(number_format($sum, 22)); // string(26) "-59.9999999999999928945726"

This is what causes problems for you when you check the difference later.

A rule when dealing with floating numbers is to compare them with a given delta:

if ((a - b) < delta)

For example:

if (abs($sum - $total) < 0.0001)
OptimusCrime
  • 14,662
  • 13
  • 58
  • 96
  • I understand your answer, and it seems right. But, I did var_dumped both the positive and negative... and they are equal until 90th digit..... – sineverba Sep 13 '17 at 10:24
  • 1
    @sineverba It is the insignificant digits that makes the difference. You can also make the `delta` variable a lot smaller, but you can not directory do `float === float` as PHP can not guarantee that two floating numbers that may seem identical are actually identical. – OptimusCrime Sep 13 '17 at 10:26
  • can I solve with a simple (round($positive , 2)) and round ($negative , 2) ? – sineverba Sep 13 '17 at 10:32
  • 1
    `round` also returns floats. You can not, CAN NOT, strictly compare floats against each other, as different OSes, architectures (64/32bit) and so on handles this differently. Read the links posted as comments to your question. Never ever do `float === float`. – OptimusCrime Sep 13 '17 at 10:37
  • OK. Tryng to port your solution to my code. if (abs($sum - $total) < 0.0001) . Now ipotize we have $postive = 60.0000 and $negative = -59.9999 (coming for my code). For enter in the "if" part, I need to put : if ( ( $positive + $negative ) > 0.01 then .... All right? – sineverba Sep 13 '17 at 10:50
  • `if (abs($sum - $total) < 0.0001)` basically means "these two numbers are equal" (or very, very close to being equal). `if (abs($sum - $total) > 0.0001)` means "these numbers are not equal". You can just keep the `abs` method. It is easier to read (in my opinion) than adding two numbers. `abs` takes the absolute value, so that if you do `-60.0 + 60.0` and `abs` then that number will always be a positive float close to zero. Or you could `abs($negative)` number and do `abs($positive - $negative)` which is even more readable. The point here is to avoid numbers that are below zero. – OptimusCrime Sep 13 '17 at 10:51
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/154328/discussion-between-sineverba-and-optimuscrime). – sineverba Sep 13 '17 at 10:54