I have a basic 5 star rating system based on user submissions. depending on the rating, a particular image is shown.
$user_rating contains the rating number to one decimal place.
There are 'star' images with
0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0
in the file names.
I need whatever number is contained in $user_rating to be rounded down to the nearest value above and stored in a new variable $star_rating. The numbers can never be rounded up. Even if $user_rating is 4.9, $star_rating should be 4.5.
Can someone help me achieve this?
Thanks
EDIT - using this but just returns original value - in this case 3.8
$star_rating = $user_rating;
function roundToHalf($star_rating) {
$temp = $star_rating * 10;
$remainder = $star_rating % 5;
return ($temp - $remainder) / 10;
}
<?php
function roundRating($rating, array $ratings)
{
if (in_array($rating, $ratings))
{
return $rating;
}
foreach($ratings as $key => $value)
{
if ($value > $rating)
{
return $ratings[($key - 1)];
}
}
return FALSE;
}
$ratings = array(0.5, 1.0, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5, 5.0);
$rating = 4.3;
if ($rate = roundRating($rating, $ratings))
echo sprintf('%.01f', $rate);
Demo: http://3v4l.org/BRBne
A simple approach:
function roundToHalf($star_rating) {
return floor( $star_rating * 2 ) / 2;
}
This works because you're looking values evenly divisible by .5 . The result is a float. I think you're better off getting back a numerical value, in case you want to use it for mathematical purposes. Let your display code format it as needed.
function roundDownToHalf($number) {
$remainder = ($number * 10) % 10;
$half = $remainder >= 5 ? 0.5 : 0;
$value = floatval(intval($number) + $half);
return number_format($value, 1, '.', '');
}
define("ENDL", "\n");
print roundDownToHalf(4.9) . ENDL;
print roundDownToHalf(4.5) . ENDL;
print roundDownToHalf(3.8) . ENDL;
print roundDownToHalf(2.3) . ENDL;
print roundDownToHalf(1.0) . ENDL;
print roundDownToHalf(0.6) . ENDL;
Output
4.5
4.5
3.5
2.0
1.0
0.5
All in one compact function:
function roundDownToHalf($n) {
return number_format(floatval(intval($n)+((($n*10)%10)>=5?.5:0)),1,'.','');
}
Multiply by 10 to make it into an integer than use the modulus operator '%' to remove the remainder. Then divide by 10 to make it back into a decimal.
function roundToHalf($number) {
$temp = intval($number * 10);
$remainder = $temp % 5;
return ($temp - $remainder) / 10;
}
Related
I would like to solve rounding mechanism by using php4,5.2 and below (not 5.3)
Currently I am doing 0.05 rounding, something like this page:
http://www.bnm.gov.my/index.php?ch=209&pg=657&ac=568
before rounding | after rounding
89.90 | 89.90
89.91 | 89.90
89.92 | 89.90
89.93 | 89.95
89.94 | 89.95
89.95 | 89.95
89.96 | 89.95
89.97 | 89.95
89.98 | 90.00
89.99 | 90.00
I try to use string to split it out and manually do adding, but not really a good solution, hoping here can find someone to solve it.
use this function
function rndfunc($x){
return round($x * 2, 1) / 2;
}
Conceptually, the procedure can be done as:
Divide by 0.05
or multiply by (1 / 0.05)
Round to nearest integer
Multiply by 0.05
You basically want to map values to a grid. The grid is defined as a multiple of .05. In general, you need to find the multiplicands your value lies between.
What isn't in the table are the negative numbers. You need to decide on whether to round away from zero (symmetrical) or always in the same direction (i.e. positive).
code:
$step = .05;
$multiplicand = floor( $value / $step );
$rest = $value % $step ;
if( $rest > $step/2 ) $multiplicand++; // round up if needed
$roundedvalue = $step*$multiplicand;
Multiply by two, then round, then divide by two.
Hint:-
$input1 = 24.05;
$things = abs($input * 20 ); // 481 ".05"s
$tenpcnt = abs($things / 10); // 48 ".05"s
$ouput = $tenpcnt / 20;
echo $ouput; // 2.40
function round5Sen ($value) {
return number_format(round($value*20,0)/20,2,'.','');
}
echo round5Sen(155.13);
echo "\n";
echo round5Sen(155.12);
echo "\n";
echo round5Sen(155.0);
echo "\n";
echo round5Sen(155.18);
echo "\n";
I'm sure there are more elegant solutions, but this appears to suit the task:
<?php
// setup test
$start_num = 89.90;
$iterations = 10;
// loop through test numbers
for ($i = 0; $i < $iterations; $i++) {
nickleRound($start_num + (0.01 * $i));
echo "\n\n";
}
//
function nickleRound($num) {
$p = 0.05;
echo "\n" . 'p= ' . $p;
$num = round($num, 2);
echo "\n" . 'num= ' . $num;
$r = ($num / $p);
echo "\n" . 'r= ' . $r;
$r2 = ceil($r) - $r;
echo "\n" . 'r2= ' . $r2;
$a = round($num, 1);
if (($r2 > 0) && ($r2 < 0.5)) {
$a = $a + 0.05;
}
echo "\n" . 'a= ' . $a;
}
Expanding a little on #xtofl to allow for more precise steps (not technically required for this question)
$step = 0.0005;
$multiplicand = floor($value / $step);
$rest = fmod($value, $step);
$value = $step * $multiplicand;
if ($rest > $step / 2) {
$value += $step;
}
//Round to nearest 0.05
echo round ($number * 20, 0) / 20;
//Round Up to nearest 0.05
echo ceil ($number * 20) / 20;
//Round Down to nearest 0.05
echo floor ($number * 20) / 20;
Thank you #mauris for the solution to solve my problem on Malaysia GST rounding mechanism. It also works in SQL.
DECLARE #tempTable AS TABLE(Number Decimal(20,4));
INSERT INTO #tempTable VALUES (89.90),(89.91),(89.92),(89.93),(89.94),(89.95),(89.96),(89.97),(89.98),(89.99)
SELECT Number, round(Number * 2, 1) / 2 AS 'Rounded' FROM #tempTable
PHP has the function round() for the PHP 4, PHP 5, PHP 7, PHP 8
https://www.php.net/manual/en/function.round.php
I want to round up my variable if it's decimal larger than .3 and if it's lower or equal it will round down, for example if i have 1.34 it will round up to 2, if i have 1.29 it will round down to 1, and if i have 1.3 it will round down to 1. I don't know how to do this precisely, right now i'm using the round basic function like this:
$weight = $weight/1000;
if($weight < 1) $weight = 1;
else $weight = round($weight, 0, PHP_ROUND_HALF_DOWN);
If you manipulate the numbers a bit, you can figure out if the decimals are .3 or higher. You achieve this by flooring the value, and subtract that from the original value. Check if the result of that, multiplied by 10, is greater than 3. If it is, you've got something above x.3.
$number = 1.31;
$int = floor($number);
$float = $number-$int;
if ($float*10 > 3.1)
$result = ceil($number);
else
$result = $int;
echo $result; // 2
Live demo
I made you a little hack, here's the code
$weight = 5088;
$weight = $weight/1000;
if($weight < 1) {
$weight = 1;
} else {
// I get the last number (I treat the $weight as a string here)
$last_number = substr($weight, -1, 1);
// Then I get the precision (floating numbers)
$precision = strlen(substr(strrchr($weight, "."), 1));
// Then I convert it to a string so I can use some helpful string functions
$weight_str = (string) $weight;
// If the last number is less then 3
if ($last_number > 3)
// I change it to 9 I could just change it to 5 and it would work
// because round will round up if then number is 5 or greater
$weight_str[strlen($weight_str) -1] = 9;
}
}
// Then the round will round up if it's 9 or round down if it's 3 or less
$weight = round($weight_str, $precision);
echo $weight;
Maybe something like this function?
function roundImproved($value, $decimalBreakPart = 0.3) {
$whole = floor($value);
$decimal = $value - $whole;
$decimalPartLen = strlen($decimal) - 2;
return (number_format($decimal, $decimalPartLen) <= number_format($decimalBreakPart, $decimalPartLen) ? $whole : ceil($value));
}
Proof:
http://sandbox.onlinephpfunctions.com/code/d75858f175dd819de069a8a05611ac9e7053f07a
You can specify "break part" if you want.
I would like to format (round) float (double) numbers to lets say 2 significant digits for example like this:
1 => 1
11 => 11
111 => 110
119 => 120
0.11 => 0.11
0.00011 => 0.00011
0.000111 => 0.00011
So the arbitrary precision remains same
I expect there is some nice function for it already built in, but could not find any so far
I was pointed to How to round down to the nearest significant figure in php, which is close but doesn't work for N significant digits and I'm not sure what it does with 0.000XXX numbers
To get a number rounded to n significant figures you need to find the size of the number in powers of ten, and subtract that from n.
This works fine for simple rounding:
function sigFig($value, $digits)
{
if ($value == 0) {
$decimalPlaces = $digits - 1;
} elseif ($value < 0) {
$decimalPlaces = $digits - floor(log10($value * -1)) - 1;
} else {
$decimalPlaces = $digits - floor(log10($value)) - 1;
}
$answer = round($value, $decimalPlaces);
return $answer;
}
This will give the following:
0.0001234567 returns 0.0001235
123456.7 returns 123500
However a value such as 10 to four significant figures should strictly be represented as 10.00 to signify the precision to which the value is known.
If this is the desired output you can use the following:
function sigFig($value, $digits)
{
if ($value == 0) {
$decimalPlaces = $digits - 1;
} elseif ($value < 0) {
$decimalPlaces = $digits - floor(log10($value * -1)) - 1;
} else {
$decimalPlaces = $digits - floor(log10($value)) - 1;
}
$answer = ($decimalPlaces > 0) ?
number_format($value, $decimalPlaces) : round($value, $decimalPlaces);
return $answer;
}
Now 1 is displayed as 1.000
With little modification to possible duplicate, answer by Todd Chaffee:
public static function roundRate($rate, $digits)
{
$mod = pow(10, intval(round(log10($rate))));
$mod = $mod / pow(10, $digits);
$answer = ((int)($rate / $mod)) * $mod;
return $answer;
}
To make sigFig(0.9995, 3) output 1.00, use
if(floor(log10($value)) !== floor(log10(round($value, $decimalPlaces)))) {$decimalPlaces--;}
Said line of code should be placed before declaring $answer.
If input $value is negative, set a flag and remove the sign at the beginning of the function, like this:
if($value < 0){$flag = 1;}
$value = ltrim($value, "-");
Then right before returning $answer, detect if the flag is set and if so restore the negative sign, like this:
if(isset($flag)){$answer = "-".$answer;}
Finally, for result values with ambiguous number of significant digits (e.g., 1000, 12000,...), express the result in scientific notation to the desired number of significant digits using sprintf or printf.
$temp is currently 6. But the variable result can be changing every time to a different number so it is not a fixed value.
Anyway, for this $temp * 1.1666666, the result will be 6.99999996. Since I used the floor function, it will be rounded down to 6.
Is there any way when the value is more then>*.49999 it will stay at *.5 instead of *?
Example: 6.51111111, 6.78948123, 6.9747124
Expected Output: 6.5
Example: 6.49999999, 6.12412431, 6.33452361
Expected Output: 6
Do note that, $temp value will be ever changing..thank you!
Use round($number, 1). That will round to the nearest decimal point.
$number = round(.1666666 * $temp, 1);
If you want to round to the nearest half you can do this:
function round_to_half($num)
{
if($num >= ($half = ($ceil = ceil($num))- 0.5) + 0.25) return $ceil;
else if($num < $half - 0.25) return floor($num);
else return $half;
}
$number = round_to_half(.1666666 * $temp);
Try this code...
<?php
$temp = 6.94444;
echo myRound($temp);
function myRound($temp)
{
$frac = $temp - floor($temp);
$frac = ($frac >= .5) ? .5 : 0;
return ( floor($temp) + $frac );
}
?>
Hope this is what you want.
I would like to solve rounding mechanism by using php4,5.2 and below (not 5.3)
Currently I am doing 0.05 rounding, something like this page:
http://www.bnm.gov.my/index.php?ch=209&pg=657&ac=568
before rounding | after rounding
89.90 | 89.90
89.91 | 89.90
89.92 | 89.90
89.93 | 89.95
89.94 | 89.95
89.95 | 89.95
89.96 | 89.95
89.97 | 89.95
89.98 | 90.00
89.99 | 90.00
I try to use string to split it out and manually do adding, but not really a good solution, hoping here can find someone to solve it.
use this function
function rndfunc($x){
return round($x * 2, 1) / 2;
}
Conceptually, the procedure can be done as:
Divide by 0.05
or multiply by (1 / 0.05)
Round to nearest integer
Multiply by 0.05
You basically want to map values to a grid. The grid is defined as a multiple of .05. In general, you need to find the multiplicands your value lies between.
What isn't in the table are the negative numbers. You need to decide on whether to round away from zero (symmetrical) or always in the same direction (i.e. positive).
code:
$step = .05;
$multiplicand = floor( $value / $step );
$rest = $value % $step ;
if( $rest > $step/2 ) $multiplicand++; // round up if needed
$roundedvalue = $step*$multiplicand;
Multiply by two, then round, then divide by two.
Hint:-
$input1 = 24.05;
$things = abs($input * 20 ); // 481 ".05"s
$tenpcnt = abs($things / 10); // 48 ".05"s
$ouput = $tenpcnt / 20;
echo $ouput; // 2.40
function round5Sen ($value) {
return number_format(round($value*20,0)/20,2,'.','');
}
echo round5Sen(155.13);
echo "\n";
echo round5Sen(155.12);
echo "\n";
echo round5Sen(155.0);
echo "\n";
echo round5Sen(155.18);
echo "\n";
I'm sure there are more elegant solutions, but this appears to suit the task:
<?php
// setup test
$start_num = 89.90;
$iterations = 10;
// loop through test numbers
for ($i = 0; $i < $iterations; $i++) {
nickleRound($start_num + (0.01 * $i));
echo "\n\n";
}
//
function nickleRound($num) {
$p = 0.05;
echo "\n" . 'p= ' . $p;
$num = round($num, 2);
echo "\n" . 'num= ' . $num;
$r = ($num / $p);
echo "\n" . 'r= ' . $r;
$r2 = ceil($r) - $r;
echo "\n" . 'r2= ' . $r2;
$a = round($num, 1);
if (($r2 > 0) && ($r2 < 0.5)) {
$a = $a + 0.05;
}
echo "\n" . 'a= ' . $a;
}
Expanding a little on #xtofl to allow for more precise steps (not technically required for this question)
$step = 0.0005;
$multiplicand = floor($value / $step);
$rest = fmod($value, $step);
$value = $step * $multiplicand;
if ($rest > $step / 2) {
$value += $step;
}
//Round to nearest 0.05
echo round ($number * 20, 0) / 20;
//Round Up to nearest 0.05
echo ceil ($number * 20) / 20;
//Round Down to nearest 0.05
echo floor ($number * 20) / 20;
Thank you #mauris for the solution to solve my problem on Malaysia GST rounding mechanism. It also works in SQL.
DECLARE #tempTable AS TABLE(Number Decimal(20,4));
INSERT INTO #tempTable VALUES (89.90),(89.91),(89.92),(89.93),(89.94),(89.95),(89.96),(89.97),(89.98),(89.99)
SELECT Number, round(Number * 2, 1) / 2 AS 'Rounded' FROM #tempTable
PHP has the function round() for the PHP 4, PHP 5, PHP 7, PHP 8
https://www.php.net/manual/en/function.round.php