1

This problem drives me crazy. I have some other solution for it, but I would like top understand what is going on here, why php behaves like this in this case.

I have two MySql tables:

Packs:
+---------+-------------+
| Field   | Type        |
+---------+-------------+
| id      | int(11)     |
| price   | double(7,3) |
|   :     |   :         |
+---------+-------------+

Contracts:
+-------------+---------------+
| Field       | Type          |
+-------------+---------------+
| id          | int(11)       |
| final_price | decimal(20,3) |
|   :         |   :           |
+-------------+---------------+

I retrieve SUM(price) and SUM(final_price) into two php variables ($totalPrice and $totalFinalPrice), then I need to compare them.
When I do:

var_dump(
   gettype($totalPrice),
   $totalPrice,
   gettype($totalFinalPrice),
   $totalFinalPrice,
   $totalPrice == $totalFinalPrice);

I get:

string(6) "double"
float(39.669)
string(6) "string"
string(6) "39.669"
bool(false)

I also tried to cast both to float or to doubleval, but again, although var_dump returns exactly the same value, the comparison returns false!

I saw this answer, but I doubt this is the reason in this case, since the values in the database in finite and equal.

========= UPDATE =======
It is impossible to reproduce this problem assigning directly these values into variables. Only after retrieving them from DB.

I use eloquent, here is the code:

$totalPrice = DB::table('Packs')
    ->selectRaw('SUM(price) AS total_price')
    ->whereIn('id_packs', [3371,3372,3373,3374])
    ->first()->total_price;

$totalFinalPrice = DB::table('Contracts')
    ->selectRaw('SUM(final_price) AS total_final_price')
    ->whereIn('id_contracts', [204028,204029,204030,204031])
    ->first()->total_final_price;

$totalPriceDouble = (double) $totalPrice;
$totalFinalPriceDouble = (double) $totalFinalPrice;

dd($totalPrice == $totalFinalPrice, $totalPriceDouble == $totalFinalPriceDouble);

which returns:

^ false
^ false

====== Update (2) =======
I tried to reproduce the problem with PHPize Online, here is the demo:
https://phpize.online/s/on

I don't know why in my local machine the var_dump does not show the whole number, anyway this is what I see in the demo:

MySql:
+==========+========+
| id_packs | price  |
+==========+========+
| 3371     | 27.260 |
| 3372     | 0.000  |
| 3373     | 0.000  |
| 3374     | 12.409 |
+----------+--------+

+==============+============+
| id_contracts | FinalPrice |
+==============+============+
| 204028       | 27.260     |
| 204029       | 0.000      |
| 204030       | 0.000      |
| 204031       | 12.409     |
+--------------+------------+

PHP:
After executing queries:
 > float(39.669000000000004)
 > string(6) "39.669"
After casting into double:
 > float(39.669000000000004)
 > float(39.669)
guyaloni
  • 4,972
  • 5
  • 52
  • 92
  • 1
    [Cannot reproduce](https://3v4l.org/tpPrm) – Your Common Sense Mar 12 '23 at 17:43
  • It would help to see some more of the code, specifically your instantiation of PDO (assuming you're using it) and how you assign the variables. But in the end you'll want to use `bccomp()` anyway. Float arithmetic is notoriously unreliable, and not just in PHP. Especially when dealing with money, you'll want to use accurate arbitrary precision mathematics. – Ro Achterberg Mar 12 '23 at 17:43
  • [The answer you saw](https://stackoverflow.com/questions/5271058/odd-behavior-comparing-doubles-two-php-double-values-arent-equivalent/5271114#5271114) is correct, and probably the reason here as well. – KIKO Software Mar 12 '23 at 17:57
  • 1
    it is perfectly possible to reproduce,if you use a service like https://phpize.online/ – Your Common Sense Mar 12 '23 at 17:58
  • 2
    Unfortunately, your question has been closed pointing to a previous post that does not address your case. Although `$totalPrice` shows as `float(39.669)` that could very well be an approximate value. Floating point is implemented as a Base 2 number and decimal numbers in general cannot be represented precisely. Try: `$sum = 0.0; for ($i = 0; $i < 10; $i++) $sum += .1; var_dump(gettype($sum), $sum, $sum == 1.0);`. You will get `float(1)` displayed for `$sum` but the actual value is not 1.0, i.e. `$sum == 1.00` is `bool(false)`. – Booboo Mar 12 '23 at 18:06
  • 1
    I would like to contradict the statement that "Float arithmetic" is notoriously unreliable. It is only unreliable if you don't understand its limitations. If you do it works very reliable. When dealing with money many program internally use integers and convert these to decimal numbers only on output. So for US$ everything internally would work in dollar cents. Sometimes floats are even used here, to be able to work with fractions of dollar cents. – KIKO Software Mar 12 '23 at 18:07

0 Answers0