From: Rick Dwyer on
Hello List.

In an earlier post, I received help with a custom function to round
decimals off (the custom function provided by Adam Richardson is below).

However in my MySQL db, when I have values with only 1 decimal point,
I need the value PHP returns to display as 2. For example, 3.8 needs
to display as 3.80.

My line of code that calls the custom function looks like this:

$my_price = round_to_half_cent(number_format($my_price, 3, '.', ','));

When the value of $my_price is 3.81, it returns 3.81. However, when
the value of $my_price is 3.8 that is what it returns.

How can I force the formatting of my_price to always contain either 2
or 3 decimal points (3 if the original number contains 3 or more
decimal points to begin with)


Thanks,

--Rick



On Jan 11, 2010, at 10:39 PM, Adam Richardson wrote:

> On Mon, Jan 11, 2010 at 7:45 PM, Mattias Thorslund <mattias(a)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


--Rick


From: tedd on
>Hello List.
>
>In an earlier post, I received help with a custom function to round
>decimals off (the custom function provided by Adam Richardson is
>below).
>
>However in my MySQL db, when I have values with only 1 decimal
>point, I need the value PHP returns to display as 2. For example,
>3.8 needs to display as 3.80.
>
>My line of code that calls the custom function looks like this:
>
>$my_price = round_to_half_cent(number_format($my_price, 3, '.', ','));
>
>When the value of $my_price is 3.81, it returns 3.81. However, when
>the value of $my_price is 3.8 that is what it returns.
>
>How can I force the formatting of my_price to always contain either
>2 or 3 decimal points (3 if the original number contains 3 or more
>decimal points to begin with)
>
>
>Thanks,
>
>--Rick


Rick:

Okay so 3.8 is stored in the database and not as 3.80 -- but that's
not a problem. What you have is a display problem so use one of the
many PHP functions to display numbers and don't worry about how it's
stored.

Cheers,

tedd

--
-------
http://sperling.com http://ancientstones.com http://earthstones.com
From: Rick Dwyer on

On Jan 22, 2010, at 4:24 PM, tedd wrote:

>> Hello List.
>>
>> In an earlier post, I received help with a custom function to round
>> decimals off (the custom function provided by Adam Richardson is
>> below).
>>
>> However in my MySQL db, when I have values with only 1 decimal
>> point, I need the value PHP returns to display as 2. For example,
>> 3.8 needs to display as 3.80.
>>
>> My line of code that calls the custom function looks like this:
>>
>> $my_price = round_to_half_cent(number_format($my_price, 3, '.',
>> ','));
>>
>> When the value of $my_price is 3.81, it returns 3.81. However,
>> when the value of $my_price is 3.8 that is what it returns.
>>
>> How can I force the formatting of my_price to always contain either
>> 2 or 3 decimal points (3 if the original number contains 3 or more
>> decimal points to begin with)
>>
>>
>> Thanks,
>>
>> --Rick
>
>
> Rick:
>
> Okay so 3.8 is stored in the database and not as 3.80 -- but that's
> not a problem. What you have is a display problem so use one of the
> many PHP functions to display numbers and don't worry about how it's
> stored.


Hi Ted.

This is exactly what I am trying to do, some of the values in the DB
are going to have 3 decimals, some 2 and some 1.

On my page I pull the value from the db with:

$my_price = $row['my_price'];

This returns 3.80... even though my db has it as 3.8. No problem.
But once I run the variable $my_price through the following line of
code, it is truncating the 0:

$my_price = round_to_half_cent(number_format($my_price, 3, '.', ','));

Again, the above call to the custom function works fine for 2 and 3
decimal points.... just not 1 decimal point. Because I call this
function over many pages, I would prefer if possible to fix it at the
custom function level rather than recode each page. But I will do
whatever is necessary. I afraid with my current understanding of PHP
I am not able to successfully modify the custom function to tack on a
0 when the decimal place is empty. Will keep trying and post if I am
successful

Thanks,

--Rick




I'm afraid with my current understanding of PHP, I am not able to come
up with the logic to

--Rick


From: Nathan Rixham on
Rick Dwyer wrote:
>
> On Jan 22, 2010, at 4:24 PM, tedd wrote:
>
>>> Hello List.
>>>
>>> In an earlier post, I received help with a custom function to round
>>> decimals off (the custom function provided by Adam Richardson is below).
>>>
>>> However in my MySQL db, when I have values with only 1 decimal point,
>>> I need the value PHP returns to display as 2. For example, 3.8 needs
>>> to display as 3.80.
>>>
>>> My line of code that calls the custom function looks like this:
>>>
>>> $my_price = round_to_half_cent(number_format($my_price, 3, '.', ','));
>>>

your doing the number format before the rounding.. here's a version of
the function that should fit the bill:

function round_to_half_cent( $value )
{
$value *= 100;
if( $value == (int)$value || $value < ((int)$value)+0.3 ) {
return number_format( (int)$value/100 , 2);
} else if($value > ((int)$value)+0.6) {
return number_format( (int)++$value/100 , 2);
}
return number_format( 0.005+(int)$value/100 , 3);
}


echo round_to_half_cent( 12.1 ); // 12.10
echo round_to_half_cent( 12.103 ); // 12.105
echo round_to_half_cent( 12.107 ); // 12.11
echo round_to_half_cent( 123456.789 ); // 123,456.79


From: Rick Dwyer on

On Jan 22, 2010, at 7:30 PM, Nathan Rixham wrote:


Thanks Nathan I'll give it a shot.

--Rick


>>>>
>
> your doing the number format before the rounding.. here's a version of
> the function that should fit the bill:
>
> function round_to_half_cent( $value )
> {
> $value *= 100;
> if( $value == (int)$value || $value < ((int)$value)+0.3 ) {
> return number_format( (int)$value/100 , 2);
> } else if($value > ((int)$value)+0.6) {
> return number_format( (int)++$value/100 , 2);
> }
> return number_format( 0.005+(int)$value/100 , 3);
> }
>
>
> echo round_to_half_cent( 12.1 ); // 12.10
> echo round_to_half_cent( 12.103 ); // 12.105
> echo round_to_half_cent( 12.107 ); // 12.11
> echo round_to_half_cent( 123456.789 ); // 123,456.79
>
>