Another way to code all 7 rounding methods according IEEE754 standart:
<?php
// We need precision parameter for ceil & floor
function p_ceil( $val, $d )
{
return ceil($val * pow (10, $d) )/ pow (10, $d) ;
}
function p_floor( $val, $d )
{
return floor($val * pow (10, $d) )/ pow (10, $d) ;
}
// We need signum
function sgn($x)
{
return $x ? ($x>0 ? 1 : -1) : 0;
}
// Now seven functions for standart rounding methods
function round_down($num, $d = 0)
{
return sgn($num)*p_floor(abs($num), $d);
}
function round_up($num, $d = 0)
{
return sgn($num)*p_ceil(abs($num), $d);
}
function round_half_even($num, $d = 0)
{
if( round($num,$d) == round_half_down($num,$d) )
return round($num,$d);
$pre_digit = round_down( $num, $d );
if( ($pre_digit/2) == round_down($pre_digit/2,$d) )
return round_down($num, $d);
else
return round_up($num, $d);
}
function round_ceiling($num, $d = 0)
{
return p_ceil($num, $d);
}
function round_floor($num, $d = 0)
{
return p_floor($num, $d);
}
function round_half_down($num, $d = 0)
{
return ((2*round_up($num,$d)==round_up(2*$num,$d))
? round($num,$d) : round_down($num,$d) );
}
function round_half_up($num, $d = 0)
{
return round($num, $d);
}
?>
My article (in Russian) about rounding in PHP is here:
http://altsoph.ru/?p=521
round
(PHP 4, PHP 5)
round — 浮動小数点数を丸める
説明
float round
( float $val
[, int $precision
] )
val を、指定した precision (小数点以下の桁数)に丸めた値を 返します。precision を負またはゼロ(デフォルト) とすることも可能です。
注意: PHP は、デフォルトでは "12,300.2" のような 文字列を正しく処理しません。文字列からの変換 を参照ください。
注意: パラメータ precision は、PHP 4 以降でのみ 利用可能です。 (訳注:内部的な 2 進数表現と 10 進数表現の差により生じる丸め誤差の影響により 必ずしも小数点以下を四捨五入した結果を返さないことに注意してください。)
パラメータ
- val
-
丸める値。
- precision
-
オプションで指定する、丸める桁数。デフォルトは 0 です
返り値
The rounded value
例
Example#1 round() examples
<?php
echo round(3.4); // 3
echo round(3.5); // 4
echo round(3.6); // 4
echo round(3.6, 0); // 4
echo round(1.95583, 2); // 1.96
echo round(1241757, -3); // 1242000
echo round(5.045, 2); // 5.05
echo round(5.055, 2); // 5.06
?>
round
altsoph
08-Feb-2008 03:30
08-Feb-2008 03:30
denis at softmaster dot com dot ua
31-Jan-2008 05:08
31-Jan-2008 05:08
There is a bug like round up (100*1.1);
In PHP round_up(100*1.1) you got 110.01;
A true value is 100*1.1 = 110;
A elegant decision of this problem (money round up) is:
<?
// Money round up
function mround($value) {
return ceil((string)($value*100))/100;
}
?>
(string)($value*100) - this is decision! =)
martinr at maarja dot net
13-Jan-2008 08:40
13-Jan-2008 08:40
Please note that the format of this functions output also depends on your locale settings. For example, if you have set your locale to some country that uses commas to separate decimal places, the output of this function also uses commas instead of dots.
This might be a problem when you are feeding the rounded float number into a database, which requires you to separate decimal places with dots.
See it in action:
<?php
echo round('3.5558', 2);
setlocale(constant('LC_ALL'), 'et_EE.UTF-8');
echo '<br />'. round('3.5558', 2);
?>
The output will be:
3.56
3,56
xellisx at gmail dot com
14-Nov-2007 08:58
14-Nov-2007 08:58
[quote]
This can be much more efficient:
<?php
function roundup ($value, $dp)
{
return ceil($value*pow(10, $dp))/pow(10, $dp);
}
function rounddown ($value, $dp)
{
return floor($value*pow(10, $dp))/pow(10, $dp);
}
?>
Much cleaner, isn't it ;)?
[/quote]
Unfortunately - it wasn't formatting the number right and you have to figure out which way you want to go.
Using the code - I've come up with this:
<php
function fract_round($n, $dp)
{
if(round($n, $dp) > $n)
{
return number_format(ceil($n*pow(10, $dp))/pow(10,$dp),$dp);
}
else
{
return number_format(floor($n*pow(10,$dp))/pow(10,$dp),$dp);
}
}
?>
Of course we could just do this:
<?php
function fract_round($n, $dp)
{
return number_format(round($n, $dp), $dp);
}
?>
mark at customcartons dot com dot au
10-Nov-2007 02:39
10-Nov-2007 02:39
[quot]
This can be much more efficient:
<?php
function roundup ($value, $dp)
{
return ceil($value*pow(10, $dp))/pow(10, $dp);
}
function rounddown ($value, $dp)
{
return floor($value*pow(10, $dp))/pow(10, $dp);
}
?>
Much cleaner, isn't it ;)?
[/quot]
Nice cleanup job, you've also managed to solve the issue which "xploded at lycos.com" noted earlier about passing 0 as the value. Thanks to you both for your input :-)
trhodes at plus dot net
07-Nov-2007 02:48
07-Nov-2007 02:48
smithaapc's trueRound() function is also broken. For example:
trueRound(1.11, 3) //returns 1.1, should return 1.11
Here's a function that uses PHP's round() to calculate significant figures:
<?php
function sigFig($value, $sigFigs) {
$exponent = floor(log10($value) + 1);
$significand = $value / pow(10, $exponent);
$significand = round($significand * pow(10, $sigFigs)) / pow(10, $sigFigs);
$value = $significand * pow(10, $exponent);
return($value);
}
//Examples
sigFig(123.45, 6); // 123.45 (doesn't pad with zeros)
sigFig(123.45, 5); // 123.45
sigFig(123.45, 4); // 123.5
sigFig(123.45, 3); // 123
sigFig(123.45, 2); // 120 (rounds to 2 figures)
sigFig(123.45, 1); // 100
sigFig(123.45, 0); // 0 (!)
?>
KingIsulgard
29-Oct-2007 10:23
29-Oct-2007 10:23
[quote]I'm sure its been done before, but here's my example of a round up function.
This function allows you to specify the number of decimal places to round up to.
Eg, when rounding up to 3 decimal places, this function adds 0.0005 to the original value and performs round(), or for 6 decimal places, adds 0.0000005 and performs round(), etc...
Hopefully some of you will find it useful:
<?php
function roundup ($value, $dp)
{
// Offset to add to $value to cause round() to round up to nearest significant digit for '$dp' decimal places
$offset = pow (10, -($dp + 1)) * 5;
return round ($value + $offset, $dp);
}
?>
Please post if you have any comments or improvements on this :-) [/quote]
This can be much more efficient:
<?php
function roundup ($value, $dp)
{
return ceil($value*pow(10, $dp))/pow(10, $dp);
}
function rounddown ($value, $dp)
{
return floor($value*pow(10, $dp))/pow(10, $dp);
}
?>
Much cleaner, isn't it ;)?
thawee from thailand
11-Oct-2007 01:41
11-Oct-2007 01:41
my round function
function rounding($n,$d){
$base=intval($n);
$n=number_format($n,25);
$dotpos=strpos($n,".");
$strlen=strlen($n);
$b= substr($n,$dotpos+1,$strlen-$dotpos);
$j=1;
$p=0;
for($i=strlen($b);$i>$d;$i--){
$c=substr($b,-$j,1)+$p;
if($c<5){
$p=0;
}else{
$p=1;
}
$j++;
}
return $base+((substr($b,0,$d)+$p)/pow(10,$d));
}
xploded at lycos.com
05-Sep-2007 01:31
05-Sep-2007 01:31
to mark at customcartons dot com dot au
found your roundup very useful, the only problem is if the value passed is 0.00 as it roundsup to 0.01 which may not be desired.
I modified the return statement to:
return ($value>0) ? round($value+$offset,$dp) : '0.00';
regards
James
Secret at secret dot com
24-Aug-2007 02:26
24-Aug-2007 02:26
Round down..
A very simple way to round down is the following..
$numbera=41;
$numberb=3;
$sum=$numbera/$numberb;
echo $sum; // Will give 13.66666.....
$rounddownsum=(int)($numbera/$numberb);
echo $rounddownsum; // Will give 13 ;o)
If you wana round decimals simply multiply the variables with 10...100...1000 or whatever before performing this action.. Then divide back after calculations.. then ex.
$numbera=41;
$numberb=3;
$sum=$numbera/$numberb;
$sum=(int)($sum*1000);
$sum=$sum/1000;
echo $sum; // Will give 13.666
Hope that helps someone... ;o)
mark at customcartons dot com dot au
06-Aug-2007 10:39
06-Aug-2007 10:39
I'm sure its been done before, but here's my example of a round up function.
This function allows you to specify the number of decimal places to round up to.
Eg, when rounding up to 3 decimal places, this function adds 0.0005 to the original value and performs round(), or for 6 decimal places, adds 0.0000005 and performs round(), etc...
Hopefully some of you will find it useful:
<?php
function roundup ($value, $dp)
{
// Offset to add to $value to cause round() to round up to nearest significant digit for '$dp' decimal places
$offset = pow (10, -($dp + 1)) * 5;
return round ($value + $offset, $dp);
}
?>
Please post if you have any comments or improvements on this :-)
Pascal Hofmann
05-Aug-2007 03:21
05-Aug-2007 03:21
The function from Felix Schwarz returns wrong results for values near 0. bccomp should be called with param $scale.
function bcround ($number, $decimals, $precision) {
$precision_add = str_repeat("5",$precision);
if (bccomp($number,0, $decimals+$precision) > 0) {
return (bcadd (bcadd ($number, "0.".str_repeat("0",$decimals).$precision_add, $decimals+$precision), 0, $decimals));
}
else {
return (bcadd (bcsub ($number, "0.".str_repeat("0",$decimals).$precision_add, $decimals+$precision), 0, $decimals));
}
}
smithaapc at NOSPAM dot yahoo dot com
27-Jul-2007 07:44
27-Jul-2007 07:44
round() is broken, plain and simple. The solution must take into account all of the digits of a given number during rounding. Truncating the number before the rounding eliminates valuable information. Consider:
myRound(12.4444444443, 2) = 12.45 ... not quite.
Try this out instead:
function trueRound($value, $figs=1) {
if(is_numeric($value) && is_int($figs) && $figs > 0) {
// must adjust $figs down 1 for computing significant figures
$figs--;
// $prec ensures all of the original digits are included in the sprintf format
$prec = strpos($value, '.') === false ? strlen($value)-1 : strlen($value)-2;
$sci = sprintf('%.'.$prec.'e', $value);
list($sig, $mant) = explode('e', $sci);
// $base includes all of the significant digits, $test contains all the remaining digits
list($base, $test) = explode('.', $sig * pow(10, $figs));
// All 4's on the left side of $test will not be significant in the rounding
$test = preg_replace('/^4+/', '', $test);
// The first digit in $test that is not a 4 will determine the direction of the rounding
$test = preg_replace('/^(\d)\d+/', '$1', $test);
if($test > 4) {
// If the digit is > 4, then simply round up by adding 1 ...
$base += 1;
}
// ... then simply adjust the decimal point
$value = $base * pow(10, $mant-$figs);
}
return($value);
}
Note this function rounds up to a number of significant figures (all digits) rather than significant digits (digits after the decimal point). Rounding down could be easily accomplished by passing a switch along with the other parameters.
Mike
lex_63de at yahoo dot de
26-Jun-2007 10:33
26-Jun-2007 10:33
Here is my little round function. Works nice on php 4.3.11 and 5.0.5
printf("0.285 - %s <br> ",round(0.285,2)); // incorrect result 0.28
printf("1.285 - %s <br> ",round(1.285,2)); // correct result 1.29
printf("1.255 - %s <br><br>",round(1.255,2)); // incorrect result 1.25
printf("0.285 - %s <br> ",myRound(0.285,2)); // incorrect result 0.29
printf("1.285 - %s <br> ",myRound(1.285,2)); // incorrect result 1.29
printf("1.255 - %s <br> ",myRound(1.255,2)); // incorrect result 1.255
function myRound($value,$round=2)
{
$value *= pow(10.0,$round);
$value = floor(floatval($value + 0.6));
$value /= pow(10.0,$round);
return($value);
}
bitbrains at yahoo dot com
22-Jun-2007 10:59
22-Jun-2007 10:59
Surprisingly, the round() cannot work with 1.255,
echo round(1.255, 2); echo "<BR>";// 1.25
pjm at pehjota dot com
28-Apr-2007 09:01
28-Apr-2007 09:01
In response to maxteiber at gmail dot com, regarding rounding 141.075 to 2 decimal places:
I can justify your computer for rounding it to 141.07. It's following a rounding rule similar to the "significant figures" rules in science. Try rounding 141.0751 or 141.0756.
tom at crysis-online dot com
18-Mar-2007 01:31
18-Mar-2007 01:31
I just found out then that even if you round a double (3.7) to an integer (4), it's data type remains as 'double'. So it's always good to use the settype() function when using the round() function to prevent any problems with your scripts.
16-Mar-2007 06:11
With regard to chafy at alo dot bg's not just previous; if the number 5.555 is displayed with sufficient precision (more than about 16 digits) it will probably turn out to have been stored as something like 5.554999999....9997, which would round down to 5.55.
Floating-point numbers should ALWAYS be regarded as being a little bit fuzzy. It's a consequence of the fact that they're stored in binary but humans want them displayed in decimal: you can't write one-tenth exactly as a binary expansion any more than you can write one-seventh exactly as a decimal one.
See the warning note on the floating-point type page.
chafy at alo dot bg
28-Feb-2007 11:13
28-Feb-2007 11:13
The function round numbers to a given precision.
function toFixed($number, $round=2)
{
$tempd = $number*pow(10,$round);
$tempd1 = round($tempd);
$number = $tempd1/pow(10,$round);
return $number;
}
echo round(5.555,2); //retunr 5.55 - I don\t know why
echo toFixed(5.555,2); //return 5.56
pokusman at gmail dot com
31-Jan-2007 12:06
31-Jan-2007 12:06
<php?
function RoundPrice($Price) {
$diff = $Price - floor($Price);
if ($diff<=0.25) {
$Price = floor($Price) + 0.25;
};
if ($diff>0.25 && $diff<=0.5) {
$Price = floor($Price) + 0.5;
};
if ($diff>0.5 && $diff<=0.75) {
$Price = floor($Price) + 0.75;
};
if ($diff>0.75) {
$Price = floor($Price) + 1;
};
return $Price;
}
$Price = "369.68";
$NewPrice = RoundPrice($Price); //369.75
echo "Old price: £".$Price." new price £".$NewPrice;
?>
Peter Tyson
christof dot moser at actra dot ch
06-Jan-2007 10:32
06-Jan-2007 10:32
<?php
function showAmount($amount, $countryData, $vat)
{
$amount = $amount*$countryData['kurs'];
if($vat == 1)
{
$amount = $amount*(100+$countryData['mwst'])/100;
}
$rval = 1/$countryData['rundung'];
$amount = (round($rval*$amount))/$rval;
return $amount;
}
$countryData['kurs'] = '1.619000';
$countryData['mwst'] = '7.60';
$countryData['rundung'] = '0.050000';
echo showAmount('3.976', $countryData, 1);
?>
05-Nov-2006 10:31
Javascript round_number
function roundnumber (n, d) {
n = n - 0;
if (d == null) d = 2;
var f = Math.pow(10, d);
n += Math.pow(10, - (d + 1));
n = Math.round(n * f) / f;
n += Math.pow(10, - (d + 1));
n += '';
return d == 0 ? n.substring(0, n.indexOf('.')) : n.substring(0, n.indexOf('.') + d + 1);
}
PHP round_number;
function roundnumber($n, $d = 0) {
$n = $n - 0;
if ($d === NULL) $d = 2;
$f = pow(10, $d);
$n += pow(10, - ($d + 1));
$n = round($n * $f) / $f;
$n += pow(10, - ($d + 1));
$n += '';
if ( $d == 0 ) :
return substr($n, 0, strpos($n, '.'));
else :
return substr($n, 0, strpos($n, '.') + $d + 1);
endif;
}
dave at koales dot co dot uk
30-Oct-2006 10:39
30-Oct-2006 10:39
Note, there is a bug in what appears to be the Windows implementation. See http://bugs.php.net/bug.php?id=36008 for more information and a fix (convert the number to a string before rounding).
maxteiber at gmail dot com
16-Oct-2006 09:15
16-Oct-2006 09:15
the result of this function always depends on the underlying C function. There have been a lot of compiler bugs and floating-point precission problems involving this function. Right now the following code:
<?php
echo round(141.075, 2);
?>
returns:
141.07
on my machine.
So never really trust this function when you do critical calculations like accounting stuff!
Instead: use only integers or use string comparisons.
Hitlers Pet Gerbil
05-Oct-2006 05:47
05-Oct-2006 05:47
In response to boonedocks at gmail dot com
Your calculations are slightly incorrect. You only use the formula when the 1/1000 position is equal to 5, otherwise you follow standard rounding proceedures.
I wrote a quick snippet which works with the input as a string, uses inline substrings and substitutions. Works VERY fast.
<?php
function bankers_round ($moneyfloat = null)
{
$money_str = sprintf("%01.3f", round($moneyfloat, 3)); // convert to rounded (to the nearest thousandth) string
$thous_pos = strlen($money_str)-1; // Thousandth string position
$hundt_pos = strlen($money_str)-2; // Hundredth string position
if ($money_str[$thous_pos] === "5") $money_str[$thous_pos] = ((int)$money_str[$hundt_pos] & 1) ? "9" : "0"; // use a bitwise test, its faster than modulus
// The above statement assists round() by setting the thousandth position to 9 or zero if the hundredth is even or odd (respectively)
return round($money_str, 2); // Return rounded value
}
?>
Hitlers Pet Gerbil
ionut dot socol at euromarket dot ro
12-Aug-2006 07:40
12-Aug-2006 07:40
My name is Ionut Socol and i'm from Romania
A small script that allow you to round up, round down or just return the integer number.
The $direction value cand be:
0 - rounding down
1 - rounding up
any thing else for returning the integer value
<?php
function rounding($no,$direction)
{ $skip=0;
if(is_float($no) and $direction = 1)
{
$exploded = explode(".",$no);
$nrr = $exploded[0]+1; $skip=1;
}
if(is_float($no) and $direction = 0)
{
$exploded = explode(".",$no);
$nrr = $exploded[0]; $skip=1;
}
if(!is_float($no) and $skip ==1) { $nrr = $nrr; } else { $nrr = floor($nrr); }
return $nrr;
}
?>
12-Jul-2006 02:48
Since everybody here seems to be occupied wanking over their selfmade round() functions, a little note about the actual php-implementation:
If you round() a _very_ small number to a reasonable number of decimals, it will retain its sign! IE:
round(1.4 - 1.4, 4) returns "-0" instead of just "0"!
Dont ask me how to properly get rid of this. Im just gonna cut it off
using preg_replace().
milosz_jablonski at yahoo dot co dot uk
12-May-2006 12:51
12-May-2006 12:51
function round is more than just fantastic. Why not to use this one instead of creating your own for rounding UP/DOWN
$proc_total1 had a number of values (see 2 examples below)
round($proc_total1) //$proc_total1=57.1428571429
echo $proc_total1; //57
round($proc_total1) //$proc_total1=42.8571428571
echo $proc_total1; //43
good luck
Mazzu
11-May-2006 05:41
11-May-2006 05:41
Another correction to the significant digits formula :
($n == 0) ? 0 : round($n, floor(0 - log10(abs($n))) + $sysdigits)
- In order to handle zero and negative numbers
- Use floor() instead of ceil() to do not substract 1
adrianbj
16-Feb-2006 05:19
16-Feb-2006 05:19
A simple correction to the significant digits formula posted way below:
round($n, ceil(0 - log10($n)) + $sigdigits - 1);
Note the addition of '-1' to the formula originally posted.
28-Jan-2006 05:41
Instead of writing roundDown() and roundUp() functions in php, you might want to consider floor() and ceil(), as they are probably much, much faster.
reinhard at ess dot co dot at
27-Jan-2006 12:56
27-Jan-2006 12:56
the same is true for round_down
function round_down($value){
list($val,$dummy) = explode(".",$value);
return $val;
}
reinhard at ess dot co dot at
27-Jan-2006 12:54
27-Jan-2006 12:54
I have made the round_up-function much more simpler and useable of any values (float or int) -> if no decimal values then the value is taken else we add one to the value in front of the dot ;)
function round_up($value){
list($val,$dummy) = explode(".",$value);
return $dummy?$val+1:$val;
}
elbekko at gmail dot com
24-Jan-2006 06:45
24-Jan-2006 06:45
I created a round down function, pretty basic but it should work :P
<?php
function round_down($value)
{
if(is_float($value))
{
$exploded = explode(".",$value);
return $exploded[0];
}
else
{
die("Only float values can be entered.");
}
}
?>
You could use the same function for rounding up:
<?php
function round_up($value)
{
if(is_float($value))
{
$exploded = explode(".",$value);
return $exploded[0] + 1;
}
else
{
die("Only float values can be entered.");
}
}
?>
php dot net at cdauth dot de
23-Jan-2006 05:33
23-Jan-2006 05:33
Beware that the implementation posted below:
<?php
$number = 254.51263;
$round = (int)($number+0.5); // 255
?>
does not work with very large numbers.
boonedocks at gmail dot com
14-Jan-2006 06:08
14-Jan-2006 06:08
Since PHP no longer does Banker's Rounding, I came up with an implementation here:
http://boonedocks.net/mike/archives/106-Bankers-Rounding-for-PHP.html
It hasn't really been hammered on, so testing and comments are welcome.
adrenalin at bmxstyle dot com
19-Dec-2005 10:42
19-Dec-2005 10:42
Oh sorry, I had mistake in a simple version of the script. Here is a working and tested version:
<?php
function divby($val, $by) {
$val -= $val % $by;
return $val;
}
?>
But in blackhole's description is a little mistake, because if I try: divby(-23, 10); it will return -20, because $val is negative so the result must be negative too.
adrenalin at bmxstyle dot com
19-Dec-2005 07:31
19-Dec-2005 07:31
Here is a simple version of blackhole's script.
<?php
function divby($val, $by) {
$val -= abs($val) % $by;
return $val;
}
?>
blackhole at ggot dot org
22-Sep-2005 09:01
22-Sep-2005 09:01
Sometimes you will want to make a number divisible by another (like rounding by 5s, or 10s, or 7s, or 1438s, or whatever) instead of just making it divisble by one such as round() with only one argument. The function that follows is fairly simply and behaves mostly as expected.
<?php
function divby($val, $by) {
if ($val < 0)
$val += -$val % $by;
else
$val -= $val % $by;
return $val;
}
?>
divby(23, 10) will return 20
divby(77, 5) will return 75
divby(138, 7) will reuturn 133
divby(-23, 10) will return 20
note: the only way to return a negative value is to make BOTH values negative, for example:
divby(-25, -10) will return -20
note also: if the value of $by is greater than $val then the function will return 0, for example:
divby(3, 4) will return 0
divby(4, 3) will return 3
twain47 at gmail dot com
10-May-2005 11:25
10-May-2005 11:25
The bankers' rounding behaviour mentioned in the notes below seems to have been changed to normaly rounding.
From the comments in http://bugs.php.net/bug.php?id=24142 it was changed in 4.3.0 but various bugs seem to have been introduced and it wasn't stable again until 4.3.5 (http://bugs.php.net/bug.php?id=25694)
roger dot anzoategui at gmail dot com
07-Apr-2005 01:14
07-Apr-2005 01:14
Ron, very good observation, in some occasions the behavior of an accounting system in which I participated, the following problem occurred: reduces it of two exact values did not give zero due to that millionths of difference in the decimals they existed (not yet itself if due to the own algorithms of the microprocessor or of the language, did not I have the opportunity to do a bench, and the surest thing is that this Reason that may not have been able to notice me previously).
Your observation I have it present in my code.
ron at korving dot demon dot nl
11-Feb-2005 07:46
11-Feb-2005 07:46
Unfortunately, ranzoategui's (and my revision) round version did not work well (try to round 8.075 to 2 decimals for example).
I found out the best way to achieve a good round is to add a tiny number to the value before rounding. This seems to work fine in all cases (and luckily it's faster than previous methods):
<?
function stdround($num, $d=0)
{
return round($num + 0.0001 / pow(10, $d), $d);
}
?>
10-Feb-2005 11:23
If you want more speed, and you dont need any decimals returned, use this:
<?php
$number = 254.51263;
$round = (int)($number+0.5); // 255
?>
This way is 32% faster than calling the round() function in this situation (tested!).
ron at korving dot demon dot nl
07-Feb-2005 11:12
07-Feb-2005 11:12
This is a slighty shorter and faster version of ranzoategui's round function:
<?
function stdround($num, $d=0)
{
$d = pow(10, $d);
return round(floor($num * $d * 10) / 10) / $d;
}
?>
This function behaves exactly like round(), except for the fact that it doesn't apply a so called bankers' rounding algorithm, but a more classic approach (where a 5 is always rounded up).
For more info on Banker's rounding: http://en.wikipedia.org/wiki/Significance_arithmetic
martin at chinese-monkey dot com
14-Nov-2004 02:16
14-Nov-2004 02:16
If you didn't want to use 'ceil()' or 'floor()' as it only rounds to a whole number u could do this:
<?php
$actual_value = 3.352;
$number = 0.01; //how many decimal places you want it to be
$temp1 = $actual_value * 2;
$temp2 = $temp1 + $number; //'+ $number' if rounding up '- $number' if rounding down
$temp3 = $temp2 / 2;
$new_value = round($temp3, 2);
echo $new_value; // 3.36
?>
red at aztec dot sk
19-Jul-2004 09:21
19-Jul-2004 09:21
Better is:
<?php
$actual_value = 3.45; // 3.45
$half_round = round(($actual_value*2), 0)/2; // 3.5
?>
or
<?php
$actual_value = 3.45; // 3.45
$temp1 = $actual_value * 2; // 6.9
$temp2 = round($temp1, 0); // 7
$half_round = $temp2 / 2 // 3.5
?>
NOT
<?php
$actual_value = 3.45; // 3.45
$temp1 = $actual_value * 2; // 6.9
$temp2 = round($actual_value, 0); // 7
$half_round = $temp2 / 2 // 3.5
?>
Dan
07-Jul-2004 06:08
07-Jul-2004 06:08
a simpler solution to the 'round to a half' method suggested by monte at ispi dot net, below. This version returna the actual number.
<?php
$actual_value = 3.45; // 3.45
$temp1 = $actual_value * 2; // 6.9
$temp2 = round($actual_value, 0); // 7
$half_round = $temp2 / 2 // 3.5
?>
monte at ispi dot net
29-Jun-2004 10:31
29-Jun-2004 10:31
Just a quick note on rounding to the nearest "half" instead of nearest "whole". I my case, I'm showing a user rating with stars and need to show a star for each whole, and half a star for remainder values closer to half than whole.
// replace 3.45 with any rating
$_actual_rating = 3.45;
$_rating_round_half = round($_actual_rating / 0.5) * 0.5;
$_remainder = fmod($_rating_round_half, 1);
$_rating = (int) $_rating_round_half - $_remainder;
$_half_star = $_remainder == 0.5;
In the above example, $_rating will contain a whole number for the number of stars to display, and $_half_star will be a boolean to determine whether or not to display half a star as well.
ga dot N-O-S-P-A-M at lacde dot net
15-Apr-2004 02:49
15-Apr-2004 02:49
If you want a complete and simple solution to round for n digits you should use this function at the bottom.
(you may want this to be even clearer with nice defines like below but it is not obliged if you use -1/0/1)
<?php
define(FLOOR,-1);
define(NEARER,0);
define(CEIL,1);
?>
$myNiceValue=MyApprox($value,3); <- nearest value for 3 digits
$myNiceValue=MyApprox($value,3,FLOOR); <- floor value
ex:
MyApprox(2.36745,3); // 2.37
MyApprox(1462.36745,3); // 146 (because nearer)
MyApprox(1465.36745,3); // 147 (because nearer)
MyApprox(1462.36745,3,FLOOR); // 146
MyApprox(1462.36745,3,CEIL); // 147
MyApprox(-1462.36745,3); // -146 (because nearer)
MyApprox(-1465.36745,3); // -147 (because nearer)
MyApprox(-1462.36745,3,FLOOR); // -147 <-- like PHP but for n digit
MyApprox(-1462.36745,3,CEIL); // 146 <-- like PHP but for n digit
The last argument ($inverseNeg) is provided only if you want to switch floor and ceil for negative value to overide the common behaviour of php. (little chances it would be useful for you)
This must work for php > 4.0.5
if you want to make it work for < versions you may only have to change the str_replace to do not use arrays but 2 str_replace instead.
It may be really interesting to have this kind of functions directly in php !
Plz note that this one is probably not the quicker code possible I coded it quickly. (if you need speed it's better to use directly the method you want anyway)
Note that it's simple to use a "common" behavior in your script(s) :
define(APPROX_METHOD,-1)
MyApprox($value,$n,APPROX_METHOD);
...
So you can change once for all the method or even by choice of your user.
<?php
function MyApprox($fValue,$sigdigits=0,$mode=0,$inverseNeg=0)
// mode=-1 gives floor
// mode=0 (default) gives automatic Round to nearest digit : >5 -> +1
// mode=1 gives ceil
// inverseNeg=0 (default)-> PHP floor/ceil behavior, floor(-2.3)=-6, floor towards -INF
// inverseNeg=1 -> inverse floor/ceil behavior means floor(-2.3)=-5, floor towards 0 in case of need
{
$sValue=''.(float)($fValue);
$lenght=strlen($sValue);
$isNeg=$fValue<0;
if(($sigdigits<=0)||($sigdigits==False))
{
if(($inverseNeg)&&($isNeg)) $mode=-$mode;
if($mode==-1) return floor($fValue);
if($mode==1) return ceil($fValue);
return round($fValue);
}
$posDot=strpos($sValue,'.');
$sResult=str_replace(array('.','-'),'', $sValue);
$fResult=0.0;
if(($mode==0)&&(intval($sResult{$sigdigits})>=5)) $fResult=1.0;
$sResult=substr($sResult,0,$sigdigits);
$fResult+=(float)$sResult;
if($isNeg)
{
if($inverseNeg)
{
if($mode==1) $fResult+=1;
}
else if($mode==-1) $fResult+=1;
}
else if($mode==1) $fResult+=1;
if($posDot==False) $posDot=$lenght;
$numb=$sigdigits-($posDot-$isNeg);
if($numb>0) for($i=0;$i<$numb;$i++) $fResult/=10.0;
else if($numb<0) for($i=0;$i<$numb;$i++) $fResult*=10.0;
if($isNeg) return -$fResult;
else return $fResult;
}
?>
terry at scribendi dot com
13-Jan-2004 04:45
13-Jan-2004 04:45
To round any number to a given number of significant digits, use log10 to find out its magnitude:
round($n, ceil(0 - log10($n)) + $sigdigits);
Or when you have to display a per-unit price which may work out to be less than a few cents/pence/yen you can use:
// $exp = currency decimal places - 0 for Yen/Won, 2 for most others
$dp = ceil(0 - log10($n)) + $sigdigits;
$display = number_format($amount, ($exp>$dp)?$exp:$dp);
This always displays at least the number of decimal places required by the currency, but more if displaying the unit price with precision requires it - eg: 'English proofreading from $0.0068 per word', 'English beer from $6.80 per pint'.
ssttoo at hotmail dot com
06-Dec-2003 09:12
06-Dec-2003 09:12
Having done the following test:
<?php
$test_numbers = array (1.255,3.255,10.255);
foreach ($test_numbers AS $number){
echo "<br />Number:<b> " . $number . "</b>";
echo "<br />Printf():<b> ";
printf("%.2f",$number);
echo "</b><br />Printf() and round(): <b> ";
printf("%.2f",round($number,2));
echo "</b><br />Printf() and round() *100/100:<b> ";
printf("%.2f",round($number*100)/100);
echo "</b><br />----------------";
}
?>
it looks that small numbers are not always rounded the way one expects, regardless of the rounding method used. The results are:
Number: 1.255
Printf(): 1.25
Printf() and round(): 1.25
Printf() and round() *100/100: 1.25
----------------
Number: 3.255
Printf(): 3.25
Printf() and round(): 3.25
Printf() and round() *100/100: 3.26
----------------
Number: 10.255
Printf(): 10.26
Printf() and round(): 10.26
Printf() and round() *100/100: 10.26
So to get around this I came out with a small 'fuzz'-ing:
<?php
function myFormattedRoundedNumber($number, $fuzz = 0.00000000001){
return sprintf("%.2f", (($number>=0) ? ($number+$fuzz) : ($number-$fuzz)));
}
?>
As you can see, it also takes into account the negative numbers.
PiotrL
13-Nov-2003 10:44
13-Nov-2003 10:44
There are many ways to round floating-point numbers.
And many valid (!) algorithms. This is because the algorithm depends on the domain of value and sometimes on... country.
For example as far as I know in my country money is rounded in the same way as in math calculations:
1.4 => 1
1.5 => 2
1.6 => 2
and
2.5 => 3
A lot of rounding algorithms (and very easy to implement in every language) can be found here:
http://www.merlyn.demon.co.uk/pas-chop.htm
26-Aug-2003 08:12
Many have thus far mentioned problems encountered when trying to add a small fuzz factor to a number such as 1.499999999. This is the way I get around that problem using , allbeit probably less efficient than assuming a small possiblitiy for error:
$numberToRound = 1.5;
//Convert to string.
$numberToRound = "$numberToRound";
//iff number ends in a "5", add fuzz
if (eregi("$5", $pages)) $pages += .000001;
$round = round($pages, 0);
ianring (at) golden.net
08-Aug-2003 04:30
08-Aug-2003 04:30
The round() function may indeed work properly with half-values (eg. 1.5), but this little method will give you peace of mind. Add some "fuzz" to your function with a miniscule delta value.
$delta = 0.00001;
$x = round($x+$delta);
This is fine, unless $x has a value of 1.49999 ... if you worried about that, use this method instead:
if(($x-floor($x))==0.5){
$x+=$delta;
}
$x = round($x);
you can change your "optimistic" delta into a "pessimistic" delta by subtracting instead of adding.
Cheers,
Ian Ring
ralf dot schreijer at smc dot uni-muenster dot de
18-Jun-2003 09:39
18-Jun-2003 09:39
The function below regards a higher number of digits for rounding as the number of digits you want to round! At least it rounds a Value to the number of digits you want to:
function MyRound($iValue, $iDigits, $iPrecision){
$iDigits = intval($iDigits);
$iPrecision = intval($iPrecision);
if($iDigits > $iPrecision){ $iPrecision = $iDigits; }
for($i = $iPrecision; $i >= $iDigits; $i--){
$iValue = round($iValue, $i);
} // for($i = $iPrecision; $i >= $iDigits; $i--) -- END
return $iValue;
}
Oromian
13-May-2003 09:08
13-May-2003 09:08
<?
// Rounding to the nearest fifth
// or any other increment you wish...
$percent = "48";
$num = round($percent/5)*5;
echo $num;
// returns 50
$percentt = "47";
$numm = round($percentt/5)*5;
echo $numm;
// returns 45
?>
eb at st-us dot com
18-Jan-2003 04:16
18-Jan-2003 04:16
/*next line will output 1.4999 as 1.49, no round. Use it if you want to collect fractional money less than 0.01 after for example % calculations.*/
$a=1.4999;
$a = sprintf("%01.2lf", floor($a*100)/100); //$a=1.49
tichoux at charlevoix dot net
24-Oct-2002 06:06
24-Oct-2002 06:06
for a poll, if you want to have 100% and not 99 or 99.99 % you can do that :
round( number_format( (($individual_result*100)/$total_result), 2), 1)
kt at netspirit dot ch
21-Aug-2002 01:10
21-Aug-2002 01:10
because of some site-effects between round() and modulo, therfore the result is not exactly at every time ...
another way ( and without site-effects) of getting 0.05 increments for currencies, f.e. swiss francs:
$res = (round(20*$chf))/20;
echo $res;
with kind regards
php at silisoftware dot com
15-Aug-2002 06:15
15-Aug-2002 06:15
Here's a function to round to an arbitary number of significant digits. Don't confuse it with rounding to a negative precision - that counts back from the decimal point, this function counts forward from the Most Significant Digit.
ex:
round(1241757, -3); // 1242000
RoundSigDigs(1241757, 3); // 1240000
Works on negative numbers too. $sigdigs should be >= 0
function RoundSigDigs($number, $sigdigs) {
$multiplier = 1;
while ($number < 0.1) {
$number *= 10;
$multiplier /= 10;
}
while ($number >= 1) {
$number /= 10;
$multiplier *= 10;
}
return round($number, $sigdigs) * $multiplier;
}
dalef at bendnet dot com
26-Mar-2002 04:27
26-Mar-2002 04:27
for php 3.x, if you need to use the precision arg:
function round3x($val,$precision){
$exp = pow(10,$precision);
$val = $val * $exp;
$val = round($val);
$val = $val / $exp;
return $val;
}
js5 at sanger dot ac dot uk
18-Jan-2002 04:17
18-Jan-2002 04:17
This isn't a bug. Rounding of "halves" is usally done to the even number. This means that on average half of the "halves" are rounded up and half of the "halves" are rounded down. So that
any "average" calculated should not be affected by the rounding.
twan at ecreation dot nl
16-May-2000 10:51
16-May-2000 10:51
If you'd only want to round for displaying variables (not for calculating on the rounded result) then you should use printf with the float:
printf ("%6.2f",3.39532);
This returns: 3.40 .