Edit report at https://bugs.php.net/bug.php?id=65637&edit=1

 ID:                 65637
 Comment by:         productivepc at hotmail dot com
 Reported by:        productivepc at hotmail dot com
 Summary:            Using division PHP_ROUND_HALF_UP rounds DOWN when
                     working with 2 precision
 Status:             Feedback
 Type:               Bug
 Package:            Math related
 Operating System:   Windows 7
 PHP Version:        5.5.3
 Block user comment: N
 Private report:     N

 New Comment:

I went ahead and wrote it before I went to bed.  The only thing you have to 
change is the 3 to a 2 in this line:  $additionalPcCostPerDay = 
round($additionalPcCost/$totalWorkingDays,3,PHP_ROUND_HALF_UP);
You will see the price go from 182.09 when it is looking at 3 decimal places to 
182.04 when it is looking at 2 decimal places.  When rounding up even if the 
number previously was a 6 I would expect it to go to 182.10 and not drop $.05.

<?php
        $workingDaysLeft = 16;
        $totalWorkingDays = 21;
        $mainPcCost = 169;
        $additionalPcCost = 69.99;
        $additionalpcs = 1;
        $mainPcCostPerDay = $mainPcCost/$totalWorkingDays;
        $additionalPcCostPerDay = 
round($additionalPcCost/$totalWorkingDays,3,PHP_ROUND_HALF_UP);
        $mainPcProratedCost = $mainPcCostPerDay*$workingDaysLeft;
        $additionalPcProratedCost = $additionalPcCostPerDay*$workingDaysLeft;
        $totalProratedCost = 
number_format($mainPcProratedCost+$additionalPcProratedCost,2,'.',',');
        $costPerFullMonth = $mainPcCost+($additionalpcs*$additionalPcCost);
//      echo "<br>mainPcCost: " . $mainPcCost . "<br>additionalPcCost: " . 
$additionalPcCost;
//      echo "<br>additionalpcs: " . $additionalpcs;
//      echo "<br>WorkingDaysLeft: " . $workingDaysLeft . 
"<br>totalWorkingDays: 
" . $totalWorkingDays;
//      echo "<br>mainPcCostPerDay: " . $mainPcCostPerDay . "
<br>additionalPcCostPerDay: " . $additionalPcCostPerDay;
//      echo "<br>mainPcProratedCost: " . $mainPcProratedCost . "
<br>additionalPcProratedCost: " . $additionalPcProratedCost;
        echo "<br>totalProratedCost: " . $totalProratedCost;// . "
<br>costPerFullMonth: " . $costPerFullMonth;
?>


Previous Comments:
------------------------------------------------------------------------
[2013-09-09 05:34:34] productivepc at hotmail dot com

In your example, you are rounding to 1 decimal place and yes absolutely that 
will 
throw it off however if you do =PRODUCT(ROUNDUP(1.45,2),1000) = 1450. I removed 
all rounding except for the $additionalPcCostPerDay = 
round($additionalPcCost/$totalWorkingDays,3,PHP_ROUND_HALF_UP); and the error 
still happens.  When I attempt to round to 2 decimal places the rounding 
appears 
to round down and not up.  When I do it to 3 then it works as expected.  It is 
1:33am.  I will write a smaller script tomorrow after I sleep and post it here.

------------------------------------------------------------------------
[2013-09-09 02:57:46] requi...@php.net

And by the way, you know that rounding numbers too early will throw off future 
calculations, right? 1.45 * 1000 = 1450 but roundup(1.45, 1) * 1000 = 1500. 
Don't 
round until the very end.

------------------------------------------------------------------------
[2013-09-09 02:48:04] requi...@php.net

The script you've provided doesn't output the example numbers you gave. I get

additionalPcCostPerDay: 0.159 or 0.16
additionalPcProratedCost: 2.54 or 2.56
totalProratedCost: 131.34 or 131.36

Want to try the repro script again? Hopefully something a bit smaller with 
fewer 
variables?

------------------------------------------------------------------------
[2013-09-09 00:24:58] productivepc at hotmail dot com

Description:
------------
PHP Version 5.5.0
Results on Screen when precision is set to 2 for $additionalPcCostPerDay.

mainPcCost: 169
additionalPcCost: 3.3328571428571
WorkingDaysLeft: 16
totalWorkingDays: 21
mainPcCostPerDay: 8.05
additionalPcCostPerDay: 3.333
mainPcProratedCost: 128.8
additionalPcProratedCost: 53.33
totalProratedCost: 182.13

=============================================
Results on screen when I change the precision to 2.  Please notice everything 
has stayed the same but the totalProratedCost has changed.  
contracttermid: 2
businesstypeid: 1
mainPcCost: 169
additionalPcCost: 3.3328571428571
WorkingDaysLeft: 16
totalWorkingDays: 21
mainPcCostPerDay: 8.05
additionalPcCostPerDay: 3.33
mainPcProratedCost: 128.8
additionalPcProratedCost: 53.28
totalProratedCost: 182.08

I noticed something because I have this same thing programmed in excel.  I 
decided to add the ROUNDUP function to my excel document just like I have it in 
PHP to ensure that everything worked exactly the same and I noticed that when I 
went to 2 decimals excel actually changed the additionalPcCostPerDay to 3.34 
instead of keeping it 3.33 therefore raising the price to 182.24 and PHP 
brought 
the price down to 182.08 instead of keeping it 182.13.  Looking in to this 
further, if I use the ROUNDDOWN function 
within excel then it too brings the price to 182.08 which is what makes me 
believe that the PHP function PHP_ROUND_HALF_UP is actually ROUNDING DOWN 
instead of UP.  The 
expected behavior for both excel and PHP would be to leave the price at 182.13. 
 
When I use 3 decimals for both then both PHP and Excel agree that the 
totalProratedPrice is 182.13.  I am not sure if this is a bug however I wanted 
to report it here before making a comment on the ROUND page with an example of 
this.

The example below I do not have settype() in it however I have attempted this 
by 
changing everything over to a float with settype before I did any math and the 
result was still the same.

Wayne

Test script:
---------------
$workingDaysLeft = 16;
$totalWorkingDays = 21;
$mainPcCost = 169;
$additionalPcCost = 3.3328571428571;
$mainPcCostPerDay = round($mainPcCost/$totalWorkingDays,2, PHP_ROUND_HALF_UP);
$additionalPcCost = $additionalPcCost/$totalWorkingDays;

// The next line is the problem area.  When I change it to 2 precision the 
expected behavior is for the total prorated cost to stay at 182.13 however it 
drops to 182.08.  If you change the below line to PHP_ROUND_HALF_DOWN then you 
also get 182.08 which would indicate that the behavior is not behaving as 
expected.
$additionalPcCostPerDay = round($additionalPcCost,3,PHP_ROUND_HALF_UP);

$mainPcProratedCost = 
round($mainPcCostPerDay*$workingDaysLeft,2,PHP_ROUND_HALF_UP);
$additionalPcProratedCost = 
round($additionalPcCostPerDay*$workingDaysLeft,2,PHP_ROUND_HALF_UP);
$totalProratedCost = 
number_format($mainPcProratedCost+$additionalPcProratedCost,2,'.',',');
echo "<br>mainPcCost: " . $mainPcCost . "<br>additionalPcCost: " . 
$additionalPcCost;
echo "<br>WorkingDaysLeft: " . $workingDaysLeft . "<br>totalWorkingDays: " . 
$totalWorkingDays;
echo "<br>mainPcCostPerDay: " . $mainPcCostPerDay . 
"<br>additionalPcCostPerDay: " . $additionalPcCostPerDay;
echo "<br>mainPcProratedCost: " . $mainPcProratedCost . 
"<br>additionalPcProratedCost: " . $additionalPcProratedCost;
echo "<br>totalProratedCost: " . $totalProratedCost;

Expected result:
----------------
Whether I have precision for $additionalPcCostPerDay set to 2 or 3 the 
totalProratedCost should remain the 182.13 and not change to 182.08.



------------------------------------------------------------------------



-- 
Edit this bug report at https://bugs.php.net/bug.php?id=65637&edit=1

Reply via email to