PHP round half up doesn't work - php

I have this code
<?php echo round(0.572,2,PHP_ROUND_HALF_UP);?>
I want to round two decimals to half up, I expect a value as 0.58...
but the above code print 0.57
How can I do this?

if you expect 0,58 you don't have to use a "half round" but the ceil function
$v = 0.575;
echo ceil($v * 100) / 100; // show 0,58

The value 0.572 can not be rounded up to 0.58, because the third decimal, 2, is less than half (or 5). If you were doing round(0.575, 2, PHP_ROUND_HALF_UP) you would get 0.58. In this case 0.57 is the correct rounded value.
If you wish to always round up from the 3rd decimal, regardless of its value you could use ciel() instead, but it requires a little additional math. A simple function to demonstrate rounding up always would be...
function forceRoundUp($value, $decimals)
{
$ord = pow(10, $decimals);
return ceil($value * $ord) / $ord;
}
echo forceRoundUp(0.572, 2); // 0.58
echo forceRoundUp(0.57321, 4); // 0.5733

function round_up($value, $places)
{
$mult = pow(10, abs($places));
return $places < 0 ?
ceil($value / $mult) * $mult :
ceil($value * $mult) / $mult;
}
echo round_up(0.572,2);
Hope this will work for you!!

Related

php round off value with trailing 2 decimals and multiples of 5

I tried this function
function roundUpToAny($n,$x=5) {
return (round($n)%$x === 0) ? round($n) : round(($n+$x/2)/$x)*$x;
}
echo roundUpToAny(4.52); // This show 5 instead of 4.55
echo roundUpToAny(5.1); // This show 5 instead of 5.10
How can i created such function
I think the following function does what you want:
function roundUpToAny($n, $x=5, $sf=2) {
$scale = pow(10,$sf);
return number_format(round(ceil($n*$scale / $x), $sf) * $x / $scale, $sf);
}
The first argument is the number to be converted, the second is the "rounding factor" (multiples of $x - you asked for 5 in the title of the question), the third is the number of figures after the decimal point.
Test:
echo roundUpToAny(1.23, 5, 2) ."\n";
echo roundUpToAny(4.54, 5, 2) ."\n";
echo roundUpToAny(5.101, 5, 3) ."\n";
echo roundUpToAny(1.19, 5, 3) ."\n";
Result:
1.25
4.55
5.105
1.190
UPDATE
You pointed out in a follow-up that the above code fails for inputs of 1.1 and 2.2. The reason for this is the fact that these numbers are not exactly representable in double precision (strange though this may sound). The following code compensates for this, by creating an intermediate value that is rounded to be an integer (and therefore can be represented exactly):
function roundUpToAny($n, $x=5, $sf=2) {
$scale = pow(10,$sf);
$temp = round($n * $scale, $sf); // get rid of small rounding errors
return number_format(round(ceil($temp / $x), $sf) * $x / $scale, $sf);
}
Testing:
echo roundUpToAny(1.1, 5, 2) ."\n";
Result:
1.10
As expected.

Set precision for a float number in PHP

I get a number from database and this number might be either float or int.
I need to set the decimal precision of the number to 3, which makes the number not longer than (regarding decimals) 5.020 or 1518845.756.
Using PHP
round($number, $precision)
I see a problem:
It rounds the number. I need a function to only cut the decimals short, without changing their values which round( ) seems not to follow.
You can use number_format() to achieve this:
echo number_format((float) $number, $precision, '.', '');
This would convert 1518845.756789 to 1518845.757.
But if you just want to cut off the number of decimal places short to 3, and not round, then you can do the following:
$number = intval($number * ($p = pow(10, $precision))) / $p;
It may look intimidating at first, but the concept is really simple. You have a number, you multiply it by 103 (it becomes 1518845756.789), cast it to an integer so everything after the 3 decimal places is removed (becomes 1518845756), and then divide the result by 103 (becomes 1518845.756).
Demo
Its sound like floor with decimals. So you can try something like
floor($number*1000)/1000
If I understand correctly, you would not want rounding to occur and you would want the precision to be 3.
So the idea is to use number_format() for a precision of 4 and then remove the last digit:
$number = '1518845.756789';
$precision = 3;
echo substr(number_format($number, $precision+1, '.', ''), 0, -1);
Will display:
1518845.756
rather than:
1518845.757
Links : number_format() , substr()
See this answer for more details.
function numberPrecision($number, $decimals = 0)
{
$negation = ($number < 0) ? (-1) : 1;
$coefficient = pow(10, $decimals);
return $negation * floor((string)(abs($number) * $coefficient)) / $coefficient;
}
$num=5.1239;
$testnum=intval($num*1000)/1000;
echo $testnum; //return 5.123

PHP How do I round down to two decimal places? [duplicate]

This question already has answers here:
Truncate float numbers with PHP
(14 answers)
Closed 11 months ago.
I need to round down a decimal in PHP to two decimal places so that:
49.955
becomes...
49.95
I have tried number_format, but this just rounds the value to 49.96. I cannot use substr because the number may be smaller (such as 7.950). I've been unable to find an answer to this so far.
Any help much appreciated.
This can work: floor($number * 100) / 100
Unfortunately, none of the previous answers (including the accepted one) works for all possible inputs.
1) sprintf('%1.'.$precision.'f', $val)
Fails with a precision of 2 : 14.239 should return 14.23 (but in this case returns 14.24).
2) floatval(substr($val, 0, strpos($val, '.') + $precision + 1))
Fails with a precision of 0 : 14 should return 14 (but in this case returns 1)
3) substr($val, 0, strrpos($val, '.', 0) + (1 + $precision))
Fails with a precision of 0 : -1 should return -1 (but in this case returns '-')
4) floor($val * pow(10, $precision)) / pow(10, $precision)
Although I used this one extensively, I recently discovered a flaw in it ; it fails for some values too. With a precision of 2 : 2.05 should return 2.05 (but in this case returns 2.04 !!)
So far the only way to pass all my tests is unfortunately to use string manipulation. My solution based on rationalboss one, is :
function floorDec($val, $precision = 2) {
if ($precision < 0) { $precision = 0; }
$numPointPosition = intval(strpos($val, '.'));
if ($numPointPosition === 0) { //$val is an integer
return $val;
}
return floatval(substr($val, 0, $numPointPosition + $precision + 1));
}
This function works with positive and negative numbers, as well as any precision needed.
Here is a nice function that does the trick without using string functions:
<?php
function floorp($val, $precision)
{
$mult = pow(10, $precision); // Can be cached in lookup table
return floor($val * $mult) / $mult;
}
print floorp(49.955, 2);
?>
An other option is to subtract a fraction before rounding:
function floorp($val, $precision)
{
$half = 0.5 / pow(10, $precision); // Can be cached in a lookup table
return round($val - $half, $precision);
}
I think there is quite a simple way to achieve this:
$rounded = bcdiv($val, 1, $precision);
Here is a working example. You need BCMath installed but I think it's normally bundled with a PHP installation. :) Here is the documentation.
function roundDown($decimal, $precision)
{
$sign = $decimal > 0 ? 1 : -1;
$base = pow(10, $precision);
return floor(abs($decimal) * $base) / $base * $sign;
}
// Examples
roundDown(49.955, 2); // output: 49.95
roundDown(-3.14159, 4); // output: -3.1415
roundDown(1000.000000019, 8); // output: 1000.00000001
This function works with positive and negative decimals at any precision.
Code example here: http://codepad.org/1jzXjE5L
Multiply your input by 100, floor() it, then divide the result by 100.
You can use bcdiv PHP function.
bcdiv(49.955, 1, 2)
Try the round() function
Like this: round($num, 2, PHP_ROUND_HALF_DOWN);
For anyone in need, I've used a little trick to overcome math functions malfunctioning, like for example floor or intval(9.7*100)=969 weird.
function floor_at_decimals($amount, $precision = 2)
{
$precise = pow(10, $precision);
return floor(($amount * $precise) + 0.1) / $precise;
}
So adding little amount (that will be floored anyways) fixes the issue somehow.
Use formatted output
sprintf("%1.2f",49.955) //49.95
DEMO
You can use:
$num = 49.9555;
echo substr($num, 0, strpos($num, '.') + 3);
function floorToPrecision($val, $precision = 2) {
return floor(round($val * pow(10, $precision), $precision)) / pow(10, $precision);
}
An alternative solution using regex which should work for all positive or negative numbers, whole or with decimals:
if (preg_match('/^-?(\d+\.?\d{1,2})\d*$/', $originalValue, $matches)){
$roundedValue = $matches[1];
} else {
throw new \Exception('Cannot round down properly '.$originalValue.' to two decimal places');
}
Based on #huysentruitw and #Alex answer, I came up with following function that should do the trick.
It pass all tests given in Alex's answer (as why this is not possible) and build upon huysentruitw's answer.
function trim_number($number, $decimalPlaces) {
$delta = (0 <=> $number) * (0.5 / pow(10, $decimalPlaces));
$result = round($number + $delta, $decimalPlaces);
return $result ?: 0; // get rid of negative zero
}
The key is to add or subtract delta based on original number sign, to support trimming also negative numbers.
Last thing is to get rid of negative zeros (-0) as that can be unwanted behaviour.
Link to "test" playground.
EDIT: bcdiv seems to be the way to go.
// round afterwards to cast 0.00 to 0
// set $divider to 1 when no division is required
round(bcdiv($number, $divider, $decimalPlaces), $decimalPlaces);
sprintf("%1.2f",49.955) //49.95
if you need to truncate decimals without rounding - this is not suitable, because it will work correctly until 49.955 at the end, if number is more eg 49.957 it will round to 49.96
It seems for me that Lght`s answer with floor is most universal.
Did you try round($val,2) ?
More information about the round() function

how to create "pretty" numbers?

my question is: is there a good (common) algorithm to create numbers, which match well looking user understood numbers out of incomming (kind of random looking for a user) numbers.
i.e. you have an interval from
130'777.12 - 542'441.17.
But for the user you want to display something more ...say userfriendly, like:
130'000 - 550'000.
how can you do this for several dimensions?
an other example would be:
23.07 - 103.50 to 20 - 150
do you understand what i mean?
i should give some criteria as well:
the interval min and max should
include the given limits.
the "rounding" should be in a
granularity which reflects the
distance between min and max (meaning
in our second example 20 - 200
would be too coarse)
very much honor you'll earn if you know a native php function which can do this :-)
*update - 2011-02-21 *
I like the answer from #Ivan and so accepted it. Here is my solution so far:
maybe you can do it better. i am open for any proposals ;-).
/**
* formats a given float number to a well readable number for human beings
* #author helle + ivan + greg
* #param float $number
* #param boolean $min regulates wheter its the min or max of an interval
* #return integer
*/
function pretty_number($number, $min){
$orig = $number;
$digit_count = floor(log($number,10))+1; //capture count of digits in number (ignoring decimals)
switch($digit_count){
case 0: $number = 0; break;
case 1:
case 2: $number = round($number/10) * 10; break;
default: $number = round($number, (-1*($digit_count -2 )) ); break;
}
//be sure to include the interval borders
if($min == true && $number > $orig){
return pretty_number($orig - pow(10, $digit_count-2)/2, true);
}
if($min == false && $number < $orig){
return pretty_number($orig + pow(10, $digit_count-2)/2, false);
}
return $number;
}
I would use Log10 to find how "long" the number is and then round it up or down. Here's a quick and dirty example.
echo prettyFloor(23.07);//20
echo " - ";
echo prettyCeil(103.50);//110
echo prettyFloor(130777.12);//130000
echo " - ";
echo prettyCeil(542441.17);//550000
function prettyFloor($n)
{
$l = floor(log(abs($n),10))-1; // $l = how many digits we will have to nullify :)
if ($l<=0)
$l++;
if ($l>0)
$n=$n/(pow(10,$l)); //moving decimal point $l positions to the left eg(if $l=2 1234 => 12.34 )
$n=floor($n);
if ($l>0)
$n=$n*(pow(10,$l)); //moving decimal point $l positions to the right eg(if $l=2 12.3 => 1230 )
return $n;
}
function prettyCeil($n)
{
$l = floor(log(abs($n),10))-1;
if ($l<=0)
$l++;
if ($l>0)
$n=$n/(pow(10,$l));
$n=ceil($n);
if ($l>0)
$n=$n*(pow(10,$l));
return $n;
}
This example unfortunately will not convert 130 to 150. As both 130 and 150 have the same precision. Even thou for us, humans 150 looks a bit "rounder". In order to achieve such result I would recommend to use quinary system instead of decimal.
You can use php's round function which takes a parameter to specify the precision.
<?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
?>
The number_format() function handles "prettifying" numbers with arbitrary thousands/decimal characters and decimal places, but you'd have to split your ranges/strings into individual numbers, as number_formation only works on one number at a time.
The rounding portion would have to handled seperately as well.
I haven't seen ready algorithm or function for that. But it should be simple, based on string replacement (str_replace, preg_replace), number_format and round functions.
This actually is kind of a special case, that can be addressed with the following function:
function roundto($val, $toceil=false) {
$precision=2; // try 1, 2, 5, 10
$pow = floor(log($val, 10));
$mult = pow(10, $pow);
$a = $val/$mult*$precision;
if (!$toceil) $a-=0.5; else $a+=0.5;
return round($a)/$precision*$mult;
}
$v0=130777.12; $v1=542441.17;
echo number_format(roundto($v0, false), 0, '.', "'").' - '
.number_format(roundto($v1, true), 0, '.', "'").'<br/>';
$v0=23.07; $v1=103.50;
echo number_format(roundto($v0, false), 0, '.', "'").' - '
.number_format(roundto($v1, true), 0, '.', "'").'<br/>';
Outputs exactly this:
100'000 - 550'000
20 - 150
For any other case of number formatting it might be interesting to have a look at my newly published PHP class "php-beautiful-numbers", which I use in almost ever project to display run times ("98.4 µs" [= 9.8437291615846E-5]) or numbers in running text (e.g. "you booked two flights." [= 2]).
https://github.com/SirDagen/php-beautiful-numbers

Round DOWN to nearest half integer in PHP

I need a PHP function that will take a float and round it down to the nearest half (x.0 or x.5). I found other functions that will round to the nearest fraction, but they round both ways.
The function I need can only round down.
Examples
7.778 -> 7.5
7.501 -> 7.5
7.49 -> 7.0
7.1 -> 7.0
$x = floor($x * 2) / 2;
I'm assuming PHP has a floor function: floor($num * 2) / 2 ought to do it.
A easy solution is to use modulo operator (fmod() function), like this :
function roundDown($number, $nearest){
return $number - fmod($number, $nearest);
}
var_dump(roundDown(7.778, 0.5));
var_dump(roundDown(7.501, 0.5));
var_dump(roundDown(7.49, 0.5));
var_dump(roundDown(7.1, 0.5));
And the result :
The advantage it's that work with any nearest number (0.75, 22.5, 3.14 ...)
You can use the same operator to roundUp :
function roundUp($number, $nearest){
return $number + ($nearest - fmod($number, $nearest));
}
var_dump(roundUp(7.778, 0.5));
var_dump(roundUp(7.501, 0.5));
var_dump(roundUp(7.49, 0.5));
var_dump(roundUp(7.1, 0.5));
You can do it on that way round($number / 5, 1) * 5 the second parameter in the round() is the precision.
Example with $number equal to 4.6, 4.8 and 4.75
>>> round(4.6 / 5, 1) * 5;
=> 4.5
>>> round(4.8 / 5, 1) * 5;
=> 5.0
>>> round(4.75 / 5, 1) * 5;
=> 5.0
If you want you can round() down too like round($number, 1, PHP_ROUND_HALF_DOWN) check the documentation for more information https://www.php.net/manual/en/function.round.php
echo round($val*2) / 2; // Done
From my job's requirements. I put an function to do this. Hope you can view it as a reference:
function round_half_five($no) {
$no = strval($no);
$no = explode('.', $no);
$decimal = floatval('0.'.substr($no[1],0,2)); // cut only 2 number
if($decimal > 0) {
if($decimal <= 0.5) {
return floatval($no[0]) + 0.5;
} elseif($decimal > 0.5 && $decimal <= 0.99) {
return floatval($no[0]) + 1;
}
} else {
return floatval($no);
}
}

Categories