Roundup to next value in series - php

I'm trying to round up the result of a calculation to the next largst value in a series stored in an array.
I've tried the following but a calculation of 10.3 is rounding down to 10 when I want it to roundup to the next value in series of 16. When $s = 14.9 it works.
What am I doing wrong?
$s = 10.3
// List of standard cable CSA
$csa = array(1,1.5,2.5,4,6,10,16,25,35,50,70,95,120,150,185,240,300,400);
function nextSizeUp($s, $csa) {
$closest = null;
foreach ($csa as $size) {
if ($closest === null || abs($s - $closest) > abs($size - $s)) {
$closest = $size;
}
}
return $closest;
}
echo nextSizeUp($s,$csa);

You're trying to round up, not find the closest value. Something like this:
$s = 10.3;
// List of standard cable CSA
$csa = array(1,1.5,2.5,4,6,10,16,25,35,50,70,95,120,150,185,240,300,400);
function nextSizeUp($s, $csa)
{
foreach ($csa as $size) {
if ($size >= $s) {
return $size;
}
}
return false;
}
echo nextSizeUp($s,$csa);
This returns 16 and false when the value is bigger than 400.

Related

Get lowest price on sum of combinations in given array

This code is working fine when the array length is 8 or 10 only. When we are checking this same code for more than 10 array length.it get loading not showing the results.
How do reduce my code. If you have algorithm please share. Please help me.
This program working flow:
$allowed_per_room_accommodation =[2,3,6,5,3,5,2,5,4];
$allowed_per_room_price =[10,30,60,40,30,50,20,60,80];
$search_accommodation = 10;
i am get subsets = [5,5],[5,3,2],[6,4],[6,2,2],[5,2,3],[3,2,5]
Show lowest price room and then equal of 10 accommodation; output like as [5,3,2];
<?php
$dp=array(array());
$GLOBALS['final']=[];
$GLOBALS['room_key']=[];
function display($v,$room_key)
{
$GLOBALS['final'][] = $v;
$GLOBALS['room_key'][] = $room_key;
}
function printSubsetsRec($arr, $i, $sum, $p,$dp,$room_key='')
{
// If we reached end and sum is non-zero. We print
// p[] only if arr[0] is equal to sun OR dp[0][sum]
// is true.
if ($i == 0 && $sum != 0 && $dp[0][$sum]) {
array_push($p,$arr[$i]);
array_push($room_key,$i);
display($p,$room_key);
return $p;
}
// If $sum becomes 0
if ($i == 0 && $sum == 0) {
display($p,$room_key);
return $p;
}
// If given sum can be achieved after ignoring
// current element.
if (isset($dp[$i-1][$sum])) {
// Create a new vector to store path
// if(!is_array(#$b))
// $b = array();
$b = $p;
printSubsetsRec($arr, $i-1, $sum, $b,$dp,$room_key);
}
// If given $sum can be achieved after considering
// current element.
if ($sum >= $arr[$i] && isset($dp[$i-1][$sum-$arr[$i]]))
{
if(!is_array($p))
$p = array();
if(!is_array($room_key))
$room_key = array();
array_push($p,$arr[$i]);
array_push($room_key,$i);
printSubsetsRec($arr, $i-1, $sum-$arr[$i], $p,$dp,$room_key);
}
}
// Prints all subsets of arr[0..n-1] with sum 0.
function printAllSubsets($arr, $n, $sum,$get=[])
{
if ($n == 0 || $sum < 0)
return;
// Sum 0 can always be achieved with 0 elements
// $dp = new bool*[$n];
$dp = array();
for ($i=0; $i<$n; ++$i)
{
// $dp[$i][$sum + 1]=true;
$dp[$i][0] = true;
}
// Sum arr[0] can be achieved with single element
if ($arr[0] <= $sum)
$dp[0][$arr[0]] = true;
// Fill rest of the entries in dp[][]
for ($i = 1; $i < $n; ++$i) {
for ($j = 0; $j < $sum + 1; ++$j) {
// echo $i.'d'.$j.'.ds';
$dp[$i][$j] = ($arr[$i] <= $j) ? (isset($dp[$i-1][$j])?$dp[$i-1][$j]:false) | (isset($dp[$i-1][$j-$arr[$i]])?($dp[$i-1][$j-$arr[$i]]):false) : (isset($dp[$i - 1][$j])?($dp[$i - 1][$j]):false);
}
}
if (isset($dp[$n-1][$sum]) == false) {
return "There are no subsets with";
}
$p;
printSubsetsRec($arr, $n-1, $sum, $p='',$dp);
}
$blockSize = array('2','3','6','5','3','5','2','5','4');
$blockvalue = array('10','30','60','40','30','50','20','60','80');
$blockname = array("map","compass","water","sandwich","glucose","tin","banana","apple","cheese");
$processSize = 10;
$m = count($blockSize);
$n = count($processSize);
// sum of sets in array
printAllSubsets($blockSize, $m, $processSize);
$final_subset_room = '';
$final_set_room_keys = '';
$final_set_room =[];
if($GLOBALS['room_key']){
foreach ($GLOBALS['room_key'] as $set_rooms_key => $set_rooms) {
$tot = 0;
foreach ($set_rooms as $set_rooms) {
$tot += $blockvalue[$set_rooms];
}
$final_set_room[$set_rooms_key] = $tot;
}
asort($final_set_room);
$final_set_room_first_key = key($final_set_room);
$final_all_room['set_room_keys'] = $GLOBALS['room_key'][$final_set_room_first_key];
$final_all_room_price['set_room_price'] = $final_set_room[$final_set_room_first_key];
}
if(isset($final_all_room_price)){
asort($final_all_room_price);
$final_all_room_first_key = key($final_all_room_price);
foreach ($final_all_room['set_room_keys'] as $key_room) {
echo $blockname[$key_room].'---'. $blockvalue[$key_room];
echo '<br>';
}
}
else
echo 'No Results';
?>
I'm assuming your task is, given a list rooms, each with the amount of people it can accommodate and the price, to accommodate 10 people (or any other quantity).
This problem is similar to 0-1 knapsack problem which is solvable in polynomial time. In knapsack problem one aims to maximize the price, here we aim to minimize it. Another thing that is different from classic knapsack problem is that full room cost is charged even if the room is not completely occupied. It may reduce the effectiveness of the algorithm proposed at Wikipedia. Anyway, the implementation isn't going to be straightforward if you have never worked with dynamic programming before.
If you want to know more, CLRS book on algorithms discusses dynamic programming in Chapter 15, and knapsack problem in Chapter 16. In the latter chapter they also prove that 0-1 knapsack problem doesn't have trivial greedy solution.

How to get the largest palindromic product PHP

First than nothing I'm not a native guy so sorry for all those mistakes.
I'm trying to get the largest palindromic product between two integers, for example; 3 and 11, the largest will be 11*11=121.
I tried with this.
function Pallendrome($str) : bool {
return (strval($str) == strrev(strval($str))) ? true : false;
}
function largestPalindromicProduct($lower, $upper) {
$array = array();
for($it=$upper; $it >= $lower; $it--){
for($it_=$upper; $it_ >= $lower; $it_--){
$num = $it*$it_;
if(Pallendrome($num)) { array_push($array, $num); }
}
}
if(empty($array)) { return NAN; }
else{ ksort($array); return $array[0];}
}
But, I'd need to get a way to optimize it 'cause it's taking a long time due to the numbers introduced in, are kind of big.
Do you guys have some idea for it? Thank ya!.
I'm sure the folks over at math.stackexchange.com could help you with a better algorithm, but for the purposes of optimizing what you've got thus far, here's a summation of all my comments:
function largestPalindromicProduct($lower, $upper)
{
$largest = 0;
for ($it = $upper; $it >= $lower; $it--) {
for ($it_ = $upper; $it_ >= $lower; $it_--) {
$num = $it * $it_;
// If we're on the first iteration and we have a product lower than the
// largest we've found so far, then we know we can never get a larger
// number (because we're counting down) and we can abort immediately.
if ($num <= $largest) {
if ($it_ == $upper) {
break 2;
}
// Otherwise, we can at least abort the rest of this subloop.
break;
}
// Only check if it's a palindrome once we've passed all the other checks.
if ($num == strrev($num)) {
$largest = $num;
}
}
}
return $largest;
}

Closest number in array, but on Monopoly table

I have a monopoly game in progress and I need to retrieve the closest location from given value. I get available closest locations like this:
function Field_GetNearestByCategory($current,$category) {
$current = (int)$current;
$category = SQLEscape($category);
$s = "SELECT ID,Location FROM `card` WHERE Category='$category' AND Location <> $current";
$qr = SQLQuery($s);
$locs = array();
while($r = SQLGetArray($qr)) {
$locs[] = $r[1];
}
return $locs;
}
I have found solution for getting the closest value in array but problem occurs when $current == 40 and next closest field should be 6 (lets say we want to go to closest railroads).
function closest($search, $arr)
{
$closest = null;
foreach($arr as $item)
{
if($closest == null || abs($search - $closest) > abs($item - $search))
{
$closest = $item;
}
}
return $closest;
}
Please note that if $current == 40, anything below it is FAR away since Monopoly goes in one direction so 1 is closer to 40 than 39.
UPDATE:
I have found solution, thanks everyone
function closest($search, $arr) {
$c = null;
sort($arr);
foreach($arr as $k) {
if($k > $search) { return $k; }
else {
if(!$c) $c = $k;
}
}
return $c;
}
Here's a query that adds a "distance" field (the distance ahead the square is from $current) - mysql syntax for the CASE statement
SELECT ID, Location,
CASE WHEN Location < $current THEN Location + 40 - $current
ELSE Location - $current
END
AS Distance
FROM `card` WHERE Category='$category' AND Location <> $current

Longest Common Substring with wrong character tolerance

I have a script I found on here that works well when looking for the Lowest Common Substring.
However, I need it to tolerate some incorrect/missing characters. I would like be able to either input a percentage of similarity required, or perhaps specify the number of missing/wrong characters allowable.
For example, I want to find this string:
big yellow school bus
inside of this string:
they rode the bigyellow schook bus that afternoon
This is the code i'm currently using:
function longest_common_substring($words) {
$words = array_map('strtolower', array_map('trim', $words));
$sort_by_strlen = create_function('$a, $b', 'if (strlen($a) == strlen($b)) { return strcmp($a, $b); } return (strlen($a) < strlen($b)) ? -1 : 1;');
usort($words, $sort_by_strlen);
// We have to assume that each string has something in common with the first
// string (post sort), we just need to figure out what the longest common
// string is. If any string DOES NOT have something in common with the first
// string, return false.
$longest_common_substring = array();
$shortest_string = str_split(array_shift($words));
while (sizeof($shortest_string)) {
array_unshift($longest_common_substring, '');
foreach ($shortest_string as $ci => $char) {
foreach ($words as $wi => $word) {
if (!strstr($word, $longest_common_substring[0] . $char)) {
// No match
break 2;
}
}
// we found the current char in each word, so add it to the first longest_common_substring element,
// then start checking again using the next char as well
$longest_common_substring[0].= $char;
}
// We've finished looping through the entire shortest_string.
// Remove the first char and start all over. Do this until there are no more
// chars to search on.
array_shift($shortest_string);
}
// If we made it here then we've run through everything
usort($longest_common_substring, $sort_by_strlen);
return array_pop($longest_common_substring);
}
Any help is much appreciated.
UPDATE
The PHP levenshtein function is limited to 255 characters, and some of the haystacks i'm searching are 1000+ characters.
Writing this as a second answer because it's not based on my previous (bad) one at all.
This code is based on http://en.wikipedia.org/wiki/Wagner%E2%80%93Fischer_algorithm and http://en.wikipedia.org/wiki/Approximate_string_matching#Problem_formulation_and_algorithms
It returns one (of potentially several) minimum-levenshtein substrings of $haystack, given $needle. Now, levenshtein distance is just one measure of edit distance and it may not actually suit your needs. 'hte' is closer on this metric to 'he' than it is to 'the'. Some of the examples I put in show the limitations of this technique. I believe this to be considerably more reliable than the previous answer I gave, but let me know how it works for you.
// utility function - returns the key of the array minimum
function array_min_key($arr)
{
$min_key = null;
$min = PHP_INT_MAX;
foreach($arr as $k => $v) {
if ($v < $min) {
$min = $v;
$min_key = $k;
}
}
return $min_key;
}
// Calculate the edit distance between two strings
function edit_distance($string1, $string2)
{
$m = strlen($string1);
$n = strlen($string2);
$d = array();
// the distance from '' to substr(string,$i)
for($i=0;$i<=$m;$i++) $d[$i][0] = $i;
for($i=0;$i<=$n;$i++) $d[0][$i] = $i;
// fill-in the edit distance matrix
for($j=1; $j<=$n; $j++)
{
for($i=1; $i<=$m; $i++)
{
// Using, for example, the levenshtein distance as edit distance
list($p_i,$p_j,$cost) = levenshtein_weighting($i,$j,$d,$string1,$string2);
$d[$i][$j] = $d[$p_i][$p_j]+$cost;
}
}
return $d[$m][$n];
}
// Helper function for edit_distance()
function levenshtein_weighting($i,$j,$d,$string1,$string2)
{
// if the two letters are equal, cost is 0
if($string1[$i-1] === $string2[$j-1]) {
return array($i-1,$j-1,0);
}
// cost we assign each operation
$cost['delete'] = 1;
$cost['insert'] = 1;
$cost['substitute'] = 1;
// cost of operation + cost to get to the substring we perform it on
$total_cost['delete'] = $d[$i-1][$j] + $cost['delete'];
$total_cost['insert'] = $d[$i][$j-1] + $cost['insert'];
$total_cost['substitute'] = $d[$i-1][$j-1] + $cost['substitute'];
// return the parent array keys of $d and the operation's cost
$min_key = array_min_key($total_cost);
if ($min_key == 'delete') {
return array($i-1,$j,$cost['delete']);
} elseif($min_key == 'insert') {
return array($i,$j-1,$cost['insert']);
} else {
return array($i-1,$j-1,$cost['substitute']);
}
}
// attempt to find the substring of $haystack most closely matching $needle
function shortest_edit_substring($needle, $haystack)
{
// initialize edit distance matrix
$m = strlen($needle);
$n = strlen($haystack);
$d = array();
for($i=0;$i<=$m;$i++) {
$d[$i][0] = $i;
$backtrace[$i][0] = null;
}
// instead of strlen, we initialize the top row to all 0's
for($i=0;$i<=$n;$i++) {
$d[0][$i] = 0;
$backtrace[0][$i] = null;
}
// same as the edit_distance calculation, but keep track of how we got there
for($j=1; $j<=$n; $j++)
{
for($i=1; $i<=$m; $i++)
{
list($p_i,$p_j,$cost) = levenshtein_weighting($i,$j,$d,$needle,$haystack);
$d[$i][$j] = $d[$p_i][$p_j]+$cost;
$backtrace[$i][$j] = array($p_i,$p_j);
}
}
// now find the minimum at the bottom row
$min_key = array_min_key($d[$m]);
$current = array($m,$min_key);
$parent = $backtrace[$m][$min_key];
// trace up path to the top row
while(! is_null($parent)) {
$current = $parent;
$parent = $backtrace[$current[0]][$current[1]];
}
// and take a substring based on those results
$start = $current[1];
$end = $min_key;
return substr($haystack,$start,$end-$start);
}
// some testing
$data = array( array('foo',' foo'), array('fat','far'), array('dat burn','rugburn'));
$data[] = array('big yellow school bus','they rode the bigyellow schook bus that afternoon');
$data[] = array('bus','they rode the bigyellow schook bus that afternoon');
$data[] = array('big','they rode the bigyellow schook bus that afternoon');
$data[] = array('nook','they rode the bigyellow schook bus that afternoon');
$data[] = array('they','console, controller and games are all in very good condition, only played occasionally. includes power cable, controller charge cable and audio cable. smoke free house. pes 2011 super street fighter');
$data[] = array('controker','console, controller and games are all in very good condition, only played occasionally. includes power cable, controller charge cable and audio cable. smoke free house. pes 2011 super street fighter');
foreach($data as $dat) {
$substring = shortest_edit_substring($dat[0],$dat[1]);
$dist = edit_distance($dat[0],$substring);
printf("Found |%s| in |%s|, matching |%s| with edit distance %d\n",$substring,$dat[1],$dat[0],$dist);
}

Calculating Nth root with bcmath in PHP

We are looking for the Nth root in PHP. We need to do this with a very large number, and the windows calculator returns 2. With the following code we are getting 1. Does anybody have an idea how this works?
echo bcpow(18446744073709551616, 1/64);
Well it seems that PHP and the BC lib has some limits, and after searching on the internet i found this interesting article/code:
So you should use this function:
<?php
function NRoot($num, $n) {
if ($n<1) return 0; // we want positive exponents
if ($num<=0) return 0; // we want positive numbers
if ($num<2) return 1; // n-th root of 1 or 2 give 1
// g is our guess number
$g=2;
// while (g^n < num) g=g*2
while (bccomp(bcpow($g,$n),$num)==-1) {
$g=bcmul($g,"2");
}
// if (g^n==num) num is a power of 2, we're lucky, end of job
if (bccomp(bcpow($g,$n),$num)==0) {
return $g;
}
// if we're here num wasn't a power of 2 :(
$og=$g; // og means original guess and here is our upper bound
$g=bcdiv($g,"2"); // g is set to be our lower bound
$step=bcdiv(bcsub($og,$g),"2"); // step is the half of upper bound - lower bound
$g=bcadd($g,$step); // we start at lower bound + step , basically in the middle of our interval
// while step!=1
while (bccomp($step,"1")==1) {
$guess=bcpow($g,$n);
$step=bcdiv($step,"2");
$comp=bccomp($guess,$num); // compare our guess with real number
if ($comp==-1) { // if guess is lower we add the new step
$g=bcadd($g,$step);
} else if ($comp==1) { // if guess is higher we sub the new step
$g=bcsub($g,$step);
} else { // if guess is exactly the num we're done, we return the value
return $g;
}
}
// whatever happened, g is the closest guess we can make so return it
return $g;
}
echo NRoot("18446744073709551616","64");
?>
Hope this was helpful ...
I had problems with HamZa's solution getting to work with arbitrary precission, so i adopted it a little.
<?php
function NthRoot($Base, $NthRoot, $Precision = 100) {
if ($NthRoot < 1) return 0;
if ($Base <= 0) return 0;
if ($Base < 2) return 1;
$retVal = 0;
$guess = bcdiv($Base, 2, $Precision);
$continue = true;
$step = bcdiv(bcsub($Base, $guess, $Precision), 2, $Precision);
while ($continue) {
$test = bccomp($Base, bcpow($guess, $NthRoot, $Precision), $Precision);
if ($test == 0) {
$continue = false;
$retVal = $guess;
}
else if ($test > 0) {
$step = bcdiv($step, 2, $Precision);
$guess = bcadd($guess, $step, $Precision);
}
else if ($test < 0) {
$guess = bcsub($guess, $step, $Precision);
}
if (bccomp($step, 0, $Precision) == 0) {
$continue = false;
$retVal = $guess;
}
}
return $retVal;
}

Categories