Last active
August 29, 2015 14:07
-
-
Save mermshaus/e09579f882c1736c2e09 to your computer and use it in GitHub Desktop.
findIntersection - Tries to find the first intersection of functions $f and $g within a given interval
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Tries to find the first intersection of functions $f and $g within a given | |
* interval | |
* | |
* $discardExceptions allows $f and $g to reject/skip certain values (e. g. | |
* because of division by zero) by throwing an exception without having to stop | |
* the whole calculation. | |
* | |
* In theory, all intersections in the interval could be returned, not just the | |
* first one. But I couldn't be bothered to figure out whether the next | |
* intersection really is a *new* intersection and what to do when $f and $g | |
* have the same definition. | |
* | |
* @param Closure $f | |
* @param Closure $g | |
* @param int|float $from | |
* @param int|float $to | |
* @param int|float $step | |
* @param int|float $epsilon | |
* @param bool $discardExceptions | |
* @return array | |
* @throws InvalidArgumentException | |
* @throws Exception | |
*/ | |
function findIntersection(Closure $f, Closure $g, $from, $to, $step, $epsilon = 0.00001, $discardExceptions = true) | |
{ | |
$info = new ReflectionFunction($f); | |
if ($info->getNumberOfParameters() !== 1) { | |
throw new InvalidArgumentException('$f must accept exactly one parameter'); | |
} | |
$info = new ReflectionFunction($g); | |
if ($info->getNumberOfParameters() !== 1) { | |
throw new InvalidArgumentException('$g must accept exactly one parameter'); | |
} | |
if (!is_int($from) && !is_float($from)) { | |
throw new InvalidArgumentException('$from must be int|float'); | |
} | |
if (!is_int($to) && !is_float($to)) { | |
throw new InvalidArgumentException('$to must be int|float'); | |
} | |
if (!is_int($step) && !is_float($step)) { | |
throw new InvalidArgumentException('$step must be int|float'); | |
} | |
if ((float) $step === 0.0) { | |
throw new InvalidArgumentException('$step cannot be 0'); | |
} | |
if ( | |
$from - $to > 0 && $step > 0 | |
|| $from - $to < 0 && $step < 0 | |
) { | |
throw new InvalidArgumentException('Stepping in the wrong direction'); | |
} | |
if (!is_int($epsilon) && !is_float($epsilon)) { | |
throw new InvalidArgumentException('$epsilon must be int|float'); | |
} | |
if (!is_bool($discardExceptions)) { | |
throw new InvalidArgumentException('$discardExceptions must be bool'); | |
} | |
$ignoreActiveIteration = false; | |
$tmpf = 0; | |
$tmpg = 0; | |
$intersections = array(); | |
$x = (float) $from; | |
do { | |
try { | |
$tmpf = $f($x); | |
$tmpg = $g($x); | |
} catch (Exception $e) { | |
if ($discardExceptions) { | |
$ignoreActiveIteration = true; | |
} else { | |
throw $e; | |
} | |
} | |
if ($ignoreActiveIteration) { | |
// reset for next iteration | |
$ignoreActiveIteration = false; | |
} elseif (abs($tmpf - $tmpg) <= $epsilon) { | |
$intersections[] = $x; | |
break; | |
} | |
$x += $step; | |
if ($x > $to) { | |
break; | |
} | |
} while (true); | |
return $intersections; | |
} | |
$f = function ($x) { return pow($x, 2) - 1; }; | |
$g = function ($x) { return sin($x); }; | |
var_dump(findIntersection($f, $g, -2, 2, 0.001, 0.001)); | |
// http://www.wolframalpha.com/input/?i=x^2+-1+%3D+sin+x | |
// array(1) { | |
// [0]=> | |
// float(-0.63700000000011) | |
// } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment