# Re: [PHP] Formatting Decimals

`On Mon, Jan 11, 2010 at 7:45 PM, Mattias Thorslund <matt...@thorslund.us>wrote:`
```
> tedd wrote:
>
>> At 2:55 PM -0500 1/11/10, Rick Dwyer wrote:
>>
>>> I have been asked to further modify the value to the nearest half cent.
>>>
>>> So if the 3rd decimal spot ends in 1 or 2, it gets rounded down to 0
>>> If it ends in 3, 4, 5, 6 it gets rounded to 5.  And if it 7, 8 or 9 it
>>> gets rounded up to full cents.
>>>
>>> Can this be done fairly easily?  Not knowing PHP well, I am not aware of
>>> the logic to configure this accordingly.
>>>
>>> Thanks,
>>> --Rick
>>>
>>
>>
>> --Rick:
>>
>> The above described rounding algorithm introduces more bias than simply
>> using PHP's round() function, which always rounds down. IMO, modifying
>> rounding is not worth the effort.
>>
>> The "best" rounding algorithm is to look at the last digit and do this:
>>
>> 0 -- no rounding needed.
>> 1-4 round down.
>> 6-9 round up.
>>
>> In the case of 5, then look to the number that precedes it -- if it is
>> even, then round up and if it is odd, then round down -- or vise versa, it
>> doesn't make any difference as long as you are consistent.
>>
>> Here are some examples:
>>
>> 122.4  <-- round down (122)
>> 122.6 <-- round up (123)
>> 122.5 <-- round up (123)
>>
>> 123.4  <-- round down (123)
>> 123.6 <-- round up (124)
>> 123.5 <-- round down (123)
>>
>> There are people who claim that there's no difference, or are at odds with
>> this method, but they simply have not investigated the problem sufficiently
>> to see the bias that rounding up/down causes. However, that difference is
>> very insignificant and can only be seen after tens of thousands iterations.
>>  PHP's rounding function is quite sufficient.
>>
>> Cheers,
>>
>> tedd
>>
>>
> However that's not what Rick is asking for. He needs a function that rounds
> to the half penny with a bias to rounding up (greedy bosses):
>
>
> Actual Rounded Diff
> .011   .010    -.001
> .012   .010    -.002
> .013   .015    +.002
> .014   .015    +.001
> .015   .015     .000
> .016   .015    -.001
> .017   .020    +.003
> .018   .020    +.002
> .019   .020    +.001
> .020   .020     .000
> Bias           +.005
>
> This could easily be implemented by getting the 3rd decimal and using it in
> a switch() statement.
>
> An unbiased system could look like:
>
> Actual Rounded Diff
> .011   .010    -.001
> .012   .010    -.002
> .013   .015    +.002
> .014   .015    +.001
> .015   .015     .000
> .016   .015    -.001
> .017   .020    -.002
> .018   .020    +.002
> .019   .020    +.001
> .020   .020     .000
> Bias            .000
>
> The only difference is the case where the third decimal is 7.
>
> Cheers,
>
> Mattias
>
>
> --
> PHP General Mailing List (http://www.php.net/)
> To unsubscribe, visit: http://www.php.net/unsub.php
>
>
Here you go, Rick.  Just send the check in the mail ;)

function round_to_half_cent(\$amount)
{
if (!is_numeric(\$amount)) throw new Exception('The amount received by the
"round_to_half_cent" function was not numeric');
\$parts = explode('.', str_replace(',', '', (string)\$amount));
if (count(\$parts) >= 3) throw new Exception('The amount received by the
"round_to_half_cent" function had too many decimals.');
if (count(\$parts) == 1)
{
return \$amount;
}
\$digit = substr(\$parts[1], 2, 1);
if (\$digit == 0 || \$digit == 1 || \$digit == 2)
{
\$digit = 0;
}
elseif (\$digit == 3 || \$digit == 4 || \$digit == 5 || \$digit == 6)
{
\$digit = .005;
}
elseif (\$digit == 7 || \$digit == 8 || \$digit == 9)
{
\$digit = .01;
}
else
{
throw new Exception('OK, perhaps we are talking about different types of
numbers :(  Check the input to the "round_to_half_cent" function.');
}
return (double)(\$parts[0].'.'.substr(\$parts[1], 0, 2)) + \$digit;
}

echo "5.002 = ".round_to_half_cent(5.002);
echo "<br />70,000.126 = ".round_to_half_cent("70000.126");
echo "<br />55.897 = ".round_to_half_cent(55.897);
// should cause exception
echo "<br />One hundred = ".round_to_half_cent("One hundred");

--
Nephtali:  PHP web framework that functions beautifully
http://nephtaliproject.com
```