Memoizing fibonacci function in php - php

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

Laravel Eloquent How to get 1st and 3rd quartile on php?

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

How do I output PHP array function?

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>";

PHP find median using heap vs sort

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?

how to echo function in php like this print(h(pow)?

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!

Is it possible to reference an anonymous function from within itself in PHP?

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);

Categories