Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 400 and 401]

   1  <?php
   2  
   3  namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions;
   4  
   5  use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
   6  use PhpOffice\PhpSpreadsheet\Calculation\Exception;
   7  use PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;
   8  
   9  class LogNormal
  10  {
  11      use ArrayEnabled;
  12  
  13      /**
  14       * LOGNORMDIST.
  15       *
  16       * Returns the cumulative lognormal distribution of x, where ln(x) is normally distributed
  17       * with parameters mean and standard_dev.
  18       *
  19       * @param mixed $value Float value for which we want the probability
  20       *                      Or can be an array of values
  21       * @param mixed $mean Mean value as a float
  22       *                      Or can be an array of values
  23       * @param mixed $stdDev Standard Deviation as a float
  24       *                      Or can be an array of values
  25       *
  26       * @return array|float|string The result, or a string containing an error
  27       *         If an array of numbers is passed as an argument, then the returned result will also be an array
  28       *            with the same dimensions
  29       */
  30      public static function cumulative($value, $mean, $stdDev)
  31      {
  32          if (is_array($value) || is_array($mean) || is_array($stdDev)) {
  33              return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $mean, $stdDev);
  34          }
  35  
  36          try {
  37              $value = DistributionValidations::validateFloat($value);
  38              $mean = DistributionValidations::validateFloat($mean);
  39              $stdDev = DistributionValidations::validateFloat($stdDev);
  40          } catch (Exception $e) {
  41              return $e->getMessage();
  42          }
  43  
  44          if (($value <= 0) || ($stdDev <= 0)) {
  45              return ExcelError::NAN();
  46          }
  47  
  48          return StandardNormal::cumulative((log($value) - $mean) / $stdDev);
  49      }
  50  
  51      /**
  52       * LOGNORM.DIST.
  53       *
  54       * Returns the lognormal distribution of x, where ln(x) is normally distributed
  55       * with parameters mean and standard_dev.
  56       *
  57       * @param mixed $value Float value for which we want the probability
  58       *                      Or can be an array of values
  59       * @param mixed $mean Mean value as a float
  60       *                      Or can be an array of values
  61       * @param mixed $stdDev Standard Deviation as a float
  62       *                      Or can be an array of values
  63       * @param mixed $cumulative Boolean value indicating if we want the cdf (true) or the pdf (false)
  64       *                      Or can be an array of values
  65       *
  66       * @return array|float|string The result, or a string containing an error
  67       *         If an array of numbers is passed as an argument, then the returned result will also be an array
  68       *            with the same dimensions
  69       */
  70      public static function distribution($value, $mean, $stdDev, $cumulative = false)
  71      {
  72          if (is_array($value) || is_array($mean) || is_array($stdDev) || is_array($cumulative)) {
  73              return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $mean, $stdDev, $cumulative);
  74          }
  75  
  76          try {
  77              $value = DistributionValidations::validateFloat($value);
  78              $mean = DistributionValidations::validateFloat($mean);
  79              $stdDev = DistributionValidations::validateFloat($stdDev);
  80              $cumulative = DistributionValidations::validateBool($cumulative);
  81          } catch (Exception $e) {
  82              return $e->getMessage();
  83          }
  84  
  85          if (($value <= 0) || ($stdDev <= 0)) {
  86              return ExcelError::NAN();
  87          }
  88  
  89          if ($cumulative === true) {
  90              return StandardNormal::distribution((log($value) - $mean) / $stdDev, true);
  91          }
  92  
  93          return (1 / (sqrt(2 * M_PI) * $stdDev * $value)) *
  94              exp(0 - ((log($value) - $mean) ** 2 / (2 * $stdDev ** 2)));
  95      }
  96  
  97      /**
  98       * LOGINV.
  99       *
 100       * Returns the inverse of the lognormal cumulative distribution
 101       *
 102       * @param mixed $probability Float probability for which we want the value
 103       *                      Or can be an array of values
 104       * @param mixed $mean Mean Value as a float
 105       *                      Or can be an array of values
 106       * @param mixed $stdDev Standard Deviation as a float
 107       *                      Or can be an array of values
 108       *
 109       * @return array|float|string The result, or a string containing an error
 110       *         If an array of numbers is passed as an argument, then the returned result will also be an array
 111       *            with the same dimensions
 112       *
 113       * @TODO    Try implementing P J Acklam's refinement algorithm for greater
 114       *            accuracy if I can get my head round the mathematics
 115       *            (as described at) http://home.online.no/~pjacklam/notes/invnorm/
 116       */
 117      public static function inverse($probability, $mean, $stdDev)
 118      {
 119          if (is_array($probability) || is_array($mean) || is_array($stdDev)) {
 120              return self::evaluateArrayArguments([self::class, __FUNCTION__], $probability, $mean, $stdDev);
 121          }
 122  
 123          try {
 124              $probability = DistributionValidations::validateProbability($probability);
 125              $mean = DistributionValidations::validateFloat($mean);
 126              $stdDev = DistributionValidations::validateFloat($stdDev);
 127          } catch (Exception $e) {
 128              return $e->getMessage();
 129          }
 130  
 131          if ($stdDev <= 0) {
 132              return ExcelError::NAN();
 133          }
 134          /** @var float */
 135          $inverse = StandardNormal::inverse($probability);
 136  
 137          return exp($mean + $stdDev * $inverse);
 138      }
 139  }