Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.

Differences Between: [Versions 400 and 402] [Versions 401 and 402]

   1  <?php
   2  
   3  namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions;
   4  
   5  use PhpOffice\PhpSpreadsheet\Calculation\Functions;
   6  use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
   7  
   8  class NewtonRaphson
   9  {
  10      private const MAX_ITERATIONS = 256;
  11  
  12      /** @var callable */
  13      protected $callback;
  14  
  15      public function __construct(callable $callback)
  16      {
  17          $this->callback = $callback;
  18      }
  19  
  20      /** @return float|string */
  21      public function execute(float $probability)
  22      {
  23          $xLo = 100;
  24          $xHi = 0;
  25  
  26          $dx = 1;
  27          $x = $xNew = 1;
  28          $i = 0;
  29  
  30          while ((abs($dx) > Functions::PRECISION) && ($i++ < self::MAX_ITERATIONS)) {
  31              // Apply Newton-Raphson step
  32              $result = call_user_func($this->callback, $x);
  33              $error = $result - $probability;
  34  
  35              if ($error == 0.0) {
  36                  $dx = 0;
  37              } elseif ($error < 0.0) {
  38                  $xLo = $x;
  39              } else {
  40                  $xHi = $x;
  41              }
  42  
  43              // Avoid division by zero
  44              if ($result != 0.0) {
  45                  $dx = $error / $result;
  46                  $xNew = $x - $dx;
  47              }
  48  
  49              // If the NR fails to converge (which for example may be the
  50              // case if the initial guess is too rough) we apply a bisection
  51              // step to determine a more narrow interval around the root.
  52              if (($xNew < $xLo) || ($xNew > $xHi) || ($result == 0.0)) {
  53                  $xNew = ($xLo + $xHi) / 2;
  54                  $dx = $xNew - $x;
  55              }
  56              $x = $xNew;
  57          }
  58  
  59          if ($i == self::MAX_ITERATIONS) {
  60              return ExcelError::NA();
  61          }
  62  
  63          return $x;
  64      }
  65  }