[PHP] Re: Rounding down?

2009-08-22 Thread David Robley
Ron Piggott wrote:

 Is there a way to round down to the nearest 50?
 
 Example: Any number between 400 and 449 I would 400 to be displayed; 450
 to 499 would be 450; 500 to 549 would be 500, etc?
 
 The original number of subscribers is from a mySQL query and changes each
 day.  I am trying to present a factual statement: There have been over
 ### subscribers in 2009 type of scenereo.
 
 Ron

Modulus - http://php.net/manual/en/language.operators.arithmetic.php



Cheers
-- 
David Robley

Oxymoron: Split level.
Today is Prickle-Prickle, the 15th day of Bureaucracy in the YOLD 3175. 


-- 
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php



[PHP] Re: rounding a number

2002-06-24 Thread George Whiffen

Phil Schwarzmann wrote:

 I want to round a number to the nearest decimal place...

 if the number is 4.623, I want it to display 4.6
 if the number is 2.36, I want it to display 2.7

 Is there a function that does this?  round(), ceil(), floor() don't do
 this and I've checked through all the math functions in my handy-dandy
 PHP Functions reference book.

 Thanks for your help!!!

 Or..if it's too hard to do that, I could just use a function that
 chops off the end of some decimals, like...

 if the number is 2.343234, I want just 2.3
 or if the number is 2.545434534534534534, I want just 2.5

 Thanks!!

As I understand it, you just want to truncate the number, without
rounding.

I think you are right, there isn't a function to do it for you but the
following code should do it:

intval(4.623 * 10)/10

or more generally:

function truncate_number($mynumber,$places) {

return intval($mynumber * pow(10,$places))/pow(10,$places);
}


-- 
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php




[PHP] Re: Rounding....

2002-06-21 Thread George Whiffen



Matthew Clark wrote:

 Seeing as the mathematically correct way to round numbers is to round down
 to n for n-1=m=n.5 and up to n+1 for n.5mn+1, I wonder why the PHP
 round() function couldn't include a little 'fuzz' to handle the rounding
 problems we encounter due to floating point representation in the hardware?
 It could even be a configurable option - but it would save writing a
 wrapper...

Matthew,

I can't agree with you more.

I really don't understand the point of php having a round function which
gives the wrong answer on even very simple decimals
e.g. round(0.35,1) returns 0.3.

The fuzz you suggest works fine and need only be very small.
pow(10.0,places-DBL_DIG) seems to do the job. e.g. a change
to the source of   math.c:PHP_FUNCTION(round) as follows, (changes
underlined):

   f = pow(10.0, (double) places);

   return_val *= f;
   if (return_val = 0.0)
 return_val = floor(pow(10.0,places - DBL_DIG)) + 0.5 + return_val);
-
  else
 return_val = ceil(return_val - (0.5 + pow(10.0,places - DBL_DIG)));


   return_val /= f;


You'll note that this implies a bias to high absolute values, but then we
already
have that bias since we're rounding up anyway.  The only numbers which
would be incorrectly rounded because of the bias in the fix, already have more

than 14 significant figures e.g 0.349 rounds to 0.4 but
0.34 still rounds to 0.3.

I can't see any possible reason for this not being fixed, but then I
also think we should fix the rest of the binary representation problems i.e.

1. Comparison of Floating Points
0.8  == 0.7 + 0.1; evaluates as false not true.
In general, all the comparison operators, ==, !=, =, , , =, === may
give incorrect results if either of the operands is a floating point.

2. Conversion of Floating Point to Integer
floor(10 * (0.7 + 0.1)); evaluates to 7 not 8.
In general, floor(), ceil() and (int) may give incorrect results.

3. Spurious Differences
print (0.8 - (0.7 + 0.1)); outputs 1.1102230246252E-16 not 0

4. Cumulative Conversion Errors
for($i=1,$i=10,++$i){$total = $total + 0.1;}; calculates $total
as 1. not 1

They all have the same cause as the round problem i.e. the use of binary
floating points for decimal arithmetic without any compensation for
conversion errors.

As it happens, there's a simple fix for all of these as well   The fix is to
automatically
round the results of php's arithmetic operators to 15 significant figures when

floating point numbers are involved.  It comes to about 20 lines of code
change
to zend_operators.c i.e.8 calls to the following new function:

double decimalise(double dval)
{
  double f;
  if (dval == 0)
  {
 return dval;
  }
  f = pow(10.0, DBL_DIG - (1 + floor(log10(fabs(dval);
  return (double) (rint(dval*f))/f;
}

There is a performance downside, although much less than doing your own
workarounds.  To put it in perspective, the impact is a twentieth of that of
using
a string cast/sprintf.  Indeed, the slowdown is less than using objects or
arrays in your
arithmetic i.e. with the fix $a = $b + $c takes the same or less time than
unfixed $a = $b + $c-d

Or, to put it another way, if you are not worried about the performance impact
of using
objects and arrays in arithmetic operations, you should not be worried by the
impact of
this fix for decimal arithmetic.  (The decimalise function could also be
speeded up with a
more clever calculation of f, e.g. by skipping the log10 and pow functions
but I'd rather
leave that to a real C programmer ;))

I haven't had a very enthusiastic response from the php developers in the past
on these
issues, but I'm keen to have another go if you or anyone else thinks it's
worth sorting
this out properly.  Personally, I just don't see the point of having
operators/functions
in php that can go wrong at even a single decimal digit!

Regards,

George





-- 
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php




[PHP] Re: Rounding....Message repeated

2002-06-21 Thread George Whiffen

 Repeat of previous message in thread without the extra ugly wrapping, (sorry!!!)

Matthew Clark wrote:

   Seeing as the mathematically correct way to round numbers is to round down
   to n for n-1=m=n.5 and up to n+1 for n.5mn+1, I wonder why the PHP
   round() function couldn't include a little 'fuzz' to handle the rounding
   problems we encounter due to floating point representation in the hardware?
   It could even be a configurable option - but it would save writing a
   wrapper...

Matthew,

I can't agree with you more.

I really don't understand the point of php having a round function which
gives the wrong answer on even very simple decimals
e.g. round(0.35,1) returns 0.3.

The fuzz you suggest works fine and need only be very small.
pow(10.0,places-DBL_DIG) seems to do the job. e.g. a change
to the source of   math.c:PHP_FUNCTION(round) as follows, (changes
underlined):

   f = pow(10.0, (double) places);

   return_val *= f;
   if (return_val = 0.0)
 return_val = floor(pow(10.0,places - DBL_DIG)) + 0.5 + return_val);
-
  else
 return_val = ceil(return_val - (0.5 + pow(10.0,places - DBL_DIG)));
   
   return_val /= f;


You'll note that this implies a bias to high absolute values, but then we already
have that bias since we're rounding up anyway.  The only numbers which
would be incorrectly rounded because of the bias in the fix, already have more
than 14 significant figures e.g 0.349 rounds to 0.4 but
0.34 still rounds to 0.3.

I can't see any possible reason for this not being fixed, but then I
also think we should fix the rest of the binary representation problems i.e.

1. Comparison of Floating Points
0.8  == 0.7 + 0.1; evaluates as false not true.
In general, all the comparison operators, ==, !=, =, , , =, === may
give incorrect results if either of the operands is a floating point.

2. Conversion of Floating Point to Integer
floor(10 * (0.7 + 0.1)); evaluates to 7 not 8.
In general, floor(), ceil() and (int) may give incorrect results.

3. Spurious Differences
print (0.8 - (0.7 + 0.1)); outputs 1.1102230246252E-16 not 0

4. Cumulative Conversion Errors
for($i=1,$i=10,++$i){$total = $total + 0.1;}; calculates $total
as 1. not 1

They all have the same cause as the round problem i.e. the use of binary
floating points for decimal arithmetic without any compensation for
conversion errors.

As it happens, there's a simple fix for all of these as well   The fix is to 
automatically
round the results of php's arithmetic operators to 15 significant figures when
floating point numbers are involved.  It comes to about 20 lines of code change
to zend_operators.c i.e.8 calls to the following new function:

double decimalise(double dval)
{
  double f;
  if (dval == 0)
  {
 return dval;
  }
  f = pow(10.0, DBL_DIG - (1 + floor(log10(fabs(dval);
  return (double) (rint(dval*f))/f;
}

There is a performance downside, although much less than doing your own
workarounds.  To put it in perspective, the impact is a twentieth of that of using
a string cast/sprintf.  Indeed, the slowdown is less than using objects or arrays in 
your
arithmetic i.e. with the fix $a = $b + $c takes the same or less time than
unfixed $a = $b + $c-d

Or, to put it another way, if you are not worried about the performance impact of using
objects and arrays in arithmetic operations, you should not be worried by the impact of
this fix for decimal arithmetic.  (The decimalise function could also be speeded up 
with a
more clever calculation of f, e.g. by skipping the log10 and pow functions but I'd 
rather
leave that to a real C programmer ;))

I haven't had a very enthusiastic response from the php developers in the past on these
issues, but I'm keen to have another go if anyone else shares my view that it's time to
sort out decimal arithmetic properly.  I just don't see the point of these 
operators/functions
that can go wrong at even a single decimal digit!

Regards,

George


-- 
PHP General Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php