[PHP] Re: Rounding down?
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
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....
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
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