I've created a memoized function of the recursive version of fibonacci.
I use this as an example for other kinds of functions that would use memoization.
My implementation is bad since if I include it in a library, that means that the global variable is still seen..
This is the original recursive fibonacci function:
function fibonacci($n) {
if($n > 1) {
return fibonacci($n-1) + fibonacci($n-2);
}
return $n;
}
and I modified it to a memoized version:
$memo = array();
function fibonacciMemo($n) {
global $memo;
if(array_key_exists($n, $memo)) {
return $memo[$n];
}
else {
if($n > 1) {
$result = fibonacciMemo($n-1) + fibonacciMemo($n-2);
$memo[$n] = $result;
return $result;
}
return $n;
}
}
I purposely didn't use the iterative method in implementing fibonacci.
Is there any better ways to memoize fibonacci function in php? Can you suggest me better improvements? I've seen func_get_args() and call_user_func_array as another way but I can't seem to know what is better?
So my main question is: How can I memoize fibonacci function in php properly? or What is the best way in memoizing fibonacci function in php?
Well, Edd Mann shows an excellent way to implement a memoize function in php in His post
Here is the example code (actually taken from Edd Mann's post):
$memoize = function($func)
{
return function() use ($func)
{
static $cache = [];
$args = func_get_args();
$key = md5(serialize($args));
if ( ! isset($cache[$key])) {
$cache[$key] = call_user_func_array($func, $args);
}
return $cache[$key];
};
};
$fibonacci = $memoize(function($n) use (&$fibonacci)
{
return ($n < 2) ? $n : $fibonacci($n - 1) + $fibonacci($n - 2);
});
Notice that the global definition it's replaced thanks to function clousure and PHP's first-class function support.
Other solution:
You can create a class containing as static members: fibonnacciMemo and $memo. Notice that you don't longer have to use $memo as a global variable, so it won't give any conflict with other namespaces.
Here is the example:
class Fib{
//$memo and fibonacciMemo are static members
static $memo = array();
static function fibonacciMemo($n) {
if(array_key_exists($n, static::$memo)) {
return static::$memo[$n];
}
else {
if($n > 1) {
$result = static::fibonacciMemo($n-1) + static::fibonacciMemo($n-2);
static::$memo[$n] = $result;
return $result;
}
return $n;
}
}
}
//Using the same method by Edd Mann to benchmark
//the results
$start = microtime(true);
Fib::fibonacciMemo(10);
echo sprintf("%f\n", microtime(true) - $start);
//outputs 0.000249
$start = microtime(true);
Fib::fibonacciMemo(10);
echo sprintf("%f\n", microtime(true) - $start);
//outputs 0.000016 (now with memoized fibonacci)
//Cleaning $memo
Fib::$memo = array();
$start = microtime(true);
Fib::fibonacciMemo(10);
echo sprintf("%f\n", microtime(true) - $start);
//outputs 0.000203 (after 'cleaning' $memo)
Using this, you avoid the use of global and also the problem of cleaning the cache. Althought, $memo is not thread save and the keys stored are no hashed values.
Anyways, you can use all the php memoize utilites such as memoize-php
i think... this should to to memoize a fibonacci:
function fib($n, &$computed = array(0,1)) {
if (!array_key_exists($n,$computed)) {
$computed[$n] = fib($n-1, $computed) + fib($n-2, $computed);
}
return $computed[$n];
}
some test
$arr = array(0,1);
$start = microtime(true);
fib(10,$arr);
echo sprintf("%f\n", microtime(true) - $start);
//0.000068
$start = microtime(true);
fib(10,$arr);
echo sprintf("%f\n", microtime(true) - $start);
//0.000005
//Cleaning $arr
$arr = array(0,1);
$start = microtime(true);
fib(10,$arr);
echo sprintf("%f\n", microtime(true) - $start);
//0.000039
Another solution:
function fib($n, &$memo = []) {
if (array_key_exists($n,$memo)) {
return $memo[$n];
}
if ($n <=2 ){
return 1;
}
$memo[$n] = fib($n-1, $memo) + fib($n-2, $memo);
return $memo[$n];
}
Performance:
$start = microtime(true);
fib(100);
echo sprintf("%f\n", microtime(true) - $start);
// 0.000041
This's an implementation of memoize a fibonacci:
function fib(int $n, array &$memo = [0,1,1]) : float {
return $memo[$n] ?? $memo[$n] = fib($n-1, $memo) + fib($n-2, $memo);
}
Call
echo fib(20); // 6765
function fibMemo($n)
{
static $cache = [];
//print_r($cache);
if (!empty($cache[$n])) {
return $cache[$n];
} else {
if ($n < 2) {
return $n;
} else {
$p = fibMemo($n - 1) + fibMemo($n - 2);
$cache[$n] = $p;
return $p;
}
}
}
echo fibMemo(250);
Related
I'm trying to find outliers using the 1st and 3rd quartile. This is what I have currently:
$data = Data::select('created_at', 'value')
->get();
$median = collect($data)->median("value");
You can create a private function like this:
function Quartile($Array, $Quartile) {
sort($Array);
$pos = (count($Array) - 1) * $Quartile;
$base = floor($pos);
$rest = $pos - $base;
if( isset($Array[$base+1]) ) {
return $Array[$base] + $rest * ($Array[$base+1] - $Array[$base]);
} else {
return $Array[$base];
}
}
function Average($Array) {
return array_sum($Array) / count($Array);
}
function StdDev($Array) {
if( count($Array) < 2 ) {
return;
}
$avg = Average($Array);
$sum = 0;
foreach($Array as $value) {
$sum += pow($value - $avg, 2);
}
return sqrt((1 / (count($Array) - 1)) * $sum);
}
Then, you can call the Quartile() method depends on which quartile you want, if you want the first quartile, then put 0.25 for the as $Quartile's parameter value, for the third quartile, its 0.75.
Source answer
I'm having problems trying to "print" a PHP function to convert an IP address range to CIDR format, here is the function posted by IP2Location.com :
https://www.ip2location.com/tutorials/how-to-convert-ip-address-range-into-cidr
function iprange2cidr($ipStart, $ipEnd){
if (is_string($ipStart) || is_string($ipEnd)){
$start = ip2long($ipStart);
$end = ip2long($ipEnd);
}
else{
$start = $ipStart;
$end = $ipEnd;
}
$result = array();
while($end >= $start){
$maxSize = 32;
while ($maxSize > 0){
$mask = hexdec(iMask($maxSize - 1));
$maskBase = $start & $mask;
if($maskBase != $start) break;
$maxSize--;
}
$x = log($end - $start + 1)/log(2);
$maxDiff = floor(32 - floor($x));
if($maxSize < $maxDiff){
$maxSize = $maxDiff;
}
$ip = long2ip($start);
array_push($result, "$ip/$maxSize");
$start += pow(2, (32-$maxSize));
}
return $result;
}
function iMask($s){
return base_convert((pow(2, 32) - pow(2, (32-$s))), 10, 16);
}
(note: corrected 'echo' to 'return' result)
I've tried all of the suggested ways of "feeding" the $ipStart and $ipEnd values to the function, and also to "echo" or "print" the resulting array, but all I get is the word "Array".
For example, after the function is defined, I try:
$ipStart = '8.8.8.8';
$ipEnd = '8.8.8.254';
echo iprange2cidr($ipStart, $ipEnd);
... I appologise for the novice question, I'm a PHP newbie. I'm just not sure how to use the function. Any guidance on what I'm doing wrong would be appreciated! My server uses PHP 7.1. Thank you.
Let's return $result instead.
function iprange2cidr($ipStart, $ipEnd){
....
return $result;
}
Then let's convert it to a string before we echo it:
$ipStart = '8.8.8.8';
$ipEnd = '8.8.8.254';
$range = iprange2cidr($ipStart, $ipEnd);
echo implode("\n",$range);
You can use print_r($result); to get human-readable output.
see doc for more info.
proper way of using function is to return value like
function iprange2cidr($ipStart, $ipEnd){
....
return $result;}
and then call the function like
$returnedVale = iprange2cidr($ipStart, $ipEnd);
$returnedVale = iprange2cidr($ipStart, $ipEnd);
echo"<pre>";print_r($returnedVale);echo"</pre>";
I was looking for a quick way to calculate the median of a list of numbers and came across this:
function array_median($array) {
// perhaps all non numeric values should filtered out of $array here?
$iCount = count($array);
if ($iCount == 0) {
return null;
}
// if we're down here it must mean $array
// has at least 1 item in the array.
$middle_index = floor($iCount / 2);
sort($array, SORT_NUMERIC);
$median = $array[$middle_index]; // assume an odd # of items
// Handle the even case by averaging the middle 2 items
if ($iCount % 2 == 0) {
$median = ($median + $array[$middle_index - 1]) / 2;
}
return $median;
}
This approach using sort() makes sense and is certainly the obvious approach. However, I was curious if a median heap would be faster. What was surprising was that when I implemented a simple median heap it is consistently significantly slower than the above method.
My simple MedianHeap class:
class MedianHeap{
private $lowerHeap;
private $higherHeap;
private $numbers = [];
public function __construct($numbers = null)
{
$this->lowerHeap = new SplMaxHeap();
$this->higherHeap = new SplMinHeap();
if (count($numbers)) {
$this->insertArray($numbers);
}
}
public function insertArray ($numbers) {
foreach($numbers as $number) {
$this->insert($number);
}
}
public function insert($number)
{
$this->numbers[] = $number;
if ($this->lowerHeap->count() == 0 || $number < $this->lowerHeap->top()) {
$this->lowerHeap->insert($number);
} else {
$this->higherHeap->insert($number);
}
$this->balance();
}
protected function balance()
{
$biggerHeap = $this->lowerHeap->count() > $this->higherHeap->count() ? $this->lowerHeap : $this->higherHeap;
$smallerHeap = $this->lowerHeap->count() > $this->higherHeap->count() ? $this->higherHeap : $this->lowerHeap;
if ($biggerHeap->count() - $smallerHeap->count() >= 2) {
$smallerHeap->insert($biggerHeap->extract());
}
}
public function getMedian()
{
if (!count($this->numbers)) {
return null;
}
$biggerHeap = $this->lowerHeap->count() > $this->higherHeap->count() ? $this->lowerHeap : $this->higherHeap;
$smallerHeap = $this->lowerHeap->count() > $this->higherHeap->count() ? $this->higherHeap : $this->lowerHeap;
if ($biggerHeap->count() == $smallerHeap->count()) {
return ($biggerHeap->top() + $smallerHeap->top())/2;
} else {
return $biggerHeap->top();
}
}
}
And then the code to benchmark:
$array = [];
for($i=0; $i<100000; $i++) {
$array[] = mt_rand(1,100000) / mt_rand(1,10000);
}
$t = microtime(true);
echo array_median($array);
echo PHP_EOL . 'Sort Median: ' . (microtime(true) - $t) . ' seconds';
echo PHP_EOL;
$t = microtime(true);
$list = new MedianHeap($array);
echo $list->getMedian();
echo PHP_EOL . 'Heap Median: '. (microtime(true) - $t) . ' seconds';
Is there something in PHP that makes using heaps for this inefficient somehow or is there something wrong with my implemenation?
class fruits
{
function g($str = 'fruits'){
$i=0;
$new_str = "";
while ($i < strlen($str)-1){
$new_str = $new_str + $str[$i+1];
$i = $i + 1;
}
return $new_str;
}
function f($str = 'fruits') {
if (strlen($str)== 0) {
return "";
}
else if (strlen($str)== 1)
{
return $str;
}
else
{
return $this->f($this->g($str)) + $str[0]; }
}
function h($n=1, $str = 'fruits'){
while ($n != 1){
if ($n % 2 == 0){
$n = $n/2;
}
else
{
$n = 3*$n + 1;
}
$str = $this->f($str);
}
return $str;
}
function pow($x, $y){
if (y==0)
{
return 1;
}
else
{
return $x * $this->pow($x, $y-1);
}
}
}
$obj = new fruits;
print(h(pow());
I only want to ask how to echo a function like this print(h(pow);?
First turn on error reporting with:
<?php
ini_set("display_errors", 1);
error_reporting(E_ALL);
?>
And you will see (Besides the typos):
Fatal error: Call to undefined function h() in ...
That is because you have a class with methods. So you have to take an instance of your class an call the method from it, e.g.
$obj = new fruits;
echo $obj->h($obj->pow(4, 5));
This is basic OOP PHP. Also I would highly recommed you to use more meaningful function and variable names!
I'm trying to do something like the following:
// assume $f is an arg to the wrapping function
$self = $this;
$func = function() use($f, $ctx, $self){
$self->remove($func, $ctx); // I want $func to be a reference to this anon function
$args = func_get_args();
call_user_func_array($f, $args);
};
Is it possible to reference the function assigned to $func from with the same function?
Try doing
$func = function() use (/*your variables,*/ &$func) {
var_dump($func);
return 1;
};
http://codepad.viper-7.com/cLd3Fu
Yes you can
See this example: http://php.net/manual/en/functions.anonymous.php#105564
Code from example:
<?php
$fib = function($n) use(&$fib) {
if($n == 0 || $n == 1) return 1;
return $fib($n - 1) + $fib($n - 2);
};
echo $fib(2) . "\n"; // 2
$lie = $fib;
$fib = function(){die('error');};//rewrite $fib variable
echo $lie(5); // error because $fib is referenced by closure
?>
Yes, it is possible if you use a variable by reference. For example:
$func = function($i) use(&$func) {
if ($i <= 0) {
return;
}
echo "Countdown: $i.\n";
$func($i - 1);
};
$func(3);