Comparison between 2 equal numbers returning 'false'?

3

I have the following code:

<?php var_dump($fullprice) ?>
<?php var_dump($cart->getData('subtotal')) ?>
<?php var_dump($fullprice == $cart->getData('subtotal')) ?>
  • $fullprice returns the sum of all products and quantities in the cart.
  • $cart->getData('subtotal') returns the subtotal in the cart.

The result:

float(319.2) 
float(319.2) 
bool(false)

Why this? The 2 values are equal, at least they were the same, but the dump returns false ?

edit: The whole code here

<?php /*----------  ##HACK##  ----------*/?>
<?php $cart = Mage::getModel('checkout/cart')->getQuote(); ?>
<?php $fullprice = 0; ?>
<?php foreach ($cart->getAllVisibleItems() as $item): ?>
    <?php $fullprice += ($item->getProduct()->getPrice() * $item->getQty()); ?>
<?php endforeach; ?>

<?php var_dump($fullprice) ?>
<br>
<?php var_dump($cart->getData('subtotal')) ?>
<br>
<?php var_dump($fullprice == $cart->getData('subtotal')) ?>

<?php if ($fullprice - $cart->getData('subtotal') > 0): ?>
    <p style="color: #319e49; font-size: 16px;">
        <?php echo "Você economizou R$", number_format($fullprice - $cart->getData('subtotal'), 2, ',', ''), "</br>" ?>
</p>
<?php endif; ?>
<?php /*----------  ##/HACK##  ----------*/?>
    
asked by anonymous 05.05.2016 / 16:23

2 answers

4

The problem occurs because the value of $fullprice or $cart->getData('subtotal') is actually a real number extremely close to 319.2 , something like 319.1999999999999 . You can reproduce this case with the following test:

<?php

$x = 319.199999999999;
$y = 319.2;
var_dump($x);
var_dump($y);
var_dump($x == $y);

bash-4.2$ php test.php 
double(319.2)
double(319.2)
bool(false)

Floating-point numbers are approximations with limited precision in computers because they use the binary system, which limits the accuracy of representation of real numbers, so numbers with large numbers of decimal places end up being rounded. In this case, the value of $x is printed as 3.2 because the PHP display engine rounds numbers with a number of decimal places smaller than the comparison engine, so while a echo|var_dump will round something like 319.1999999999999 The comparison ( == ) will only do the same for 319.1999999999999999 (it has three more nodes).

Note: A good introductory reference on floating point operations is the php documentation on the subject .

    
05.05.2016 / 17:16
2

This is about precision in PHP the same thing happens in several other programming languages. what can be done to get around the problem is to use the absolute value of the difference of the two values and compare with the EPSILON constant that corresponds to 0.00001 if the difference is less than constant then the values can be considered equal

So let's compare using the code of our dear friend as an inspiration.

    <?php
    // abaixo valores hipotéticos obtidos no script
    // $fullprice tem o valor de: 319.2
    // $cart->getData('subtotal') retornará 319.2

    /* 
     aqui está a comparação que consegue determinar a 
igualdade a partir do valor absoluto da diferença dos
valores com ponto flutuante considerando que o 
resultado dessa diferença seja inferior 
a constante de EPSILON (0.00001)
    */
    if(abs($fullprice - $cart->getData('subtotal')) < 0.00001){
        echo "IGUAIS!";
    }
    else{
        echo "DIFERENTES!";
    }
    
05.05.2016 / 17:02