Skip to content

Commit

Permalink
Converting Statistical functions to be array-enabled (phase #2) (PHPO…
Browse files Browse the repository at this point in the history
  • Loading branch information
Mark Baker committed Feb 15, 2022
1 parent f1cb75e commit cdbe5c7
Show file tree
Hide file tree
Showing 15 changed files with 349 additions and 36 deletions.
18 changes: 9 additions & 9 deletions src/PhpSpreadsheet/Calculation/Statistical.php
Original file line number Diff line number Diff line change
Expand Up @@ -1155,7 +1155,7 @@ public static function NEGBINOMDIST($failures, $successes, $probability)
* @param mixed $stdDev Standard Deviation
* @param mixed $cumulative
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
*/
public static function NORMDIST($value, $mean, $stdDev, $cumulative)
{
Expand All @@ -1176,7 +1176,7 @@ public static function NORMDIST($value, $mean, $stdDev, $cumulative)
* @param mixed $mean Mean Value
* @param mixed $stdDev Standard Deviation
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
*/
public static function NORMINV($probability, $mean, $stdDev)
{
Expand All @@ -1197,7 +1197,7 @@ public static function NORMINV($probability, $mean, $stdDev)
*
* @param mixed $value
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
*/
public static function NORMSDIST($value)
{
Expand All @@ -1219,7 +1219,7 @@ public static function NORMSDIST($value)
* @param mixed $value
* @param mixed $cumulative
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
*/
public static function NORMSDIST2($value, $cumulative)
{
Expand All @@ -1238,7 +1238,7 @@ public static function NORMSDIST2($value, $cumulative)
*
* @param mixed $value
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
*/
public static function NORMSINV($value)
{
Expand Down Expand Up @@ -1331,7 +1331,7 @@ public static function PERMUT($numObjs, $numInSet)
* @param mixed $mean Mean Value
* @param mixed $cumulative
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
*/
public static function POISSON($value, $mean, $cumulative)
{
Expand Down Expand Up @@ -1610,7 +1610,7 @@ public static function STEYX($yValues, $xValues)
* @param float $degrees degrees of freedom
* @param float $tails number of tails (1 or 2)
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
*/
public static function TDIST($value, $degrees, $tails)
{
Expand All @@ -1630,7 +1630,7 @@ public static function TDIST($value, $degrees, $tails)
* @param float $probability Probability for the function
* @param float $degrees degrees of freedom
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
*/
public static function TINV($probability, $degrees)
{
Expand Down Expand Up @@ -1787,7 +1787,7 @@ public static function VARPA(...$args)
* @param float $beta Beta Parameter
* @param bool $cumulative
*
* @return float|string (string if result is an error)
* @return array|float|string (string if result is an error)
*/
public static function WEIBULL($value, $alpha, $beta, $cumulative)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions;

use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Engineering;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;

class Normal
{
use ArrayEnabled;

public const SQRT2PI = 2.5066282746310005024157652848110452530069867406099;

/**
Expand All @@ -18,17 +21,23 @@ class Normal
* testing.
*
* @param mixed $value Float value for which we want the probability
* Or can be an array of values
* @param mixed $mean Mean value as a float
* Or can be an array of values
* @param mixed $stdDev Standard Deviation as a float
* Or can be an array of values
* @param mixed $cumulative Boolean value indicating if we want the cdf (true) or the pdf (false)
* Or can be an array of values
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
* If an array of numbers is passed as an argument, then the returned result will also be an array
* with the same dimensions
*/
public static function distribution($value, $mean, $stdDev, $cumulative)
{
$value = Functions::flattenSingleValue($value);
$mean = Functions::flattenSingleValue($mean);
$stdDev = Functions::flattenSingleValue($stdDev);
if (is_array($value) || is_array($mean) || is_array($stdDev) || is_array($cumulative)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $mean, $stdDev, $cumulative);
}

try {
$value = DistributionValidations::validateFloat($value);
Expand Down Expand Up @@ -56,16 +65,21 @@ public static function distribution($value, $mean, $stdDev, $cumulative)
* Returns the inverse of the normal cumulative distribution for the specified mean and standard deviation.
*
* @param mixed $probability Float probability for which we want the value
* Or can be an array of values
* @param mixed $mean Mean Value as a float
* Or can be an array of values
* @param mixed $stdDev Standard Deviation as a float
* Or can be an array of values
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
* If an array of numbers is passed as an argument, then the returned result will also be an array
* with the same dimensions
*/
public static function inverse($probability, $mean, $stdDev)
{
$probability = Functions::flattenSingleValue($probability);
$mean = Functions::flattenSingleValue($mean);
$stdDev = Functions::flattenSingleValue($stdDev);
if (is_array($probability) || is_array($mean) || is_array($stdDev)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $probability, $mean, $stdDev);
}

try {
$probability = DistributionValidations::validateProbability($probability);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions;

use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;
use PhpOffice\PhpSpreadsheet\Calculation\MathTrig;

class Poisson
{
use ArrayEnabled;

/**
* POISSON.
*
Expand All @@ -16,15 +19,21 @@ class Poisson
* cars arriving at a toll plaza in 1 minute.
*
* @param mixed $value Float value for which we want the probability
* Or can be an array of values
* @param mixed $mean Mean value as a float
* Or can be an array of values
* @param mixed $cumulative Boolean value indicating if we want the cdf (true) or the pdf (false)
* Or can be an array of values
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
* If an array of numbers is passed as an argument, then the returned result will also be an array
* with the same dimensions
*/
public static function distribution($value, $mean, $cumulative)
{
$value = Functions::flattenSingleValue($value);
$mean = Functions::flattenSingleValue($mean);
if (is_array($value) || is_array($mean) || is_array($cumulative)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $mean, $cumulative);
}

try {
$value = DistributionValidations::validateFloat($value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,16 @@ class StandardNormal
* a mean of 0 (zero) and a standard deviation of one. Use this function in place of a
* table of standard normal curve areas.
*
* NOTE: We don't need to check for arrays to array-enable this function, because that is already
* handled by the logic in Normal::distribution()
* All we need to do is pass the value through as scalar or as array.
*
* @param mixed $value Float value for which we want the probability
* Or can be an array of values
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
* If an array of numbers is passed as an argument, then the returned result will also be an array
* with the same dimensions
*/
public static function cumulative($value)
{
Expand All @@ -34,10 +41,18 @@ public static function cumulative($value)
* a mean of 0 (zero) and a standard deviation of one. Use this function in place of a
* table of standard normal curve areas.
*
* NOTE: We don't need to check for arrays to array-enable this function, because that is already
* handled by the logic in Normal::distribution()
* All we need to do is pass the value and cumulative through as scalar or as array.
*
* @param mixed $value Float value for which we want the probability
* Or can be an array of values
* @param mixed $cumulative Boolean value indicating if we want the cdf (true) or the pdf (false)
* Or can be an array of values
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
* If an array of numbers is passed as an argument, then the returned result will also be an array
* with the same dimensions
*/
public static function distribution($value, $cumulative)
{
Expand All @@ -49,9 +64,16 @@ public static function distribution($value, $cumulative)
*
* Returns the inverse of the standard normal cumulative distribution
*
* @param mixed $value Float probability for which we want the value
* @param mixed $value float probability for which we want the value
* Or can be an array of values
*
* NOTE: We don't need to check for arrays to array-enable this function, because that is already
* handled by the logic in Normal::inverse()
* All we need to do is pass the value through as scalar or as array
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
* If an array of numbers is passed as an argument, then the returned result will also be an array
* with the same dimensions
*/
public static function inverse($value)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,14 @@

namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions;

use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;

class StudentT
{
use ArrayEnabled;

private const MAX_ITERATIONS = 256;

/**
Expand All @@ -15,16 +18,21 @@ class StudentT
* Returns the probability of Student's T distribution.
*
* @param mixed $value Float value for the distribution
* Or can be an array of values
* @param mixed $degrees Integer value for degrees of freedom
* Or can be an array of values
* @param mixed $tails Integer value for the number of tails (1 or 2)
* Or can be an array of values
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
* If an array of numbers is passed as an argument, then the returned result will also be an array
* with the same dimensions
*/
public static function distribution($value, $degrees, $tails)
{
$value = Functions::flattenSingleValue($value);
$degrees = Functions::flattenSingleValue($degrees);
$tails = Functions::flattenSingleValue($tails);
if (is_array($value) || is_array($degrees) || is_array($tails)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $degrees, $tails);
}

try {
$value = DistributionValidations::validateFloat($value);
Expand All @@ -47,14 +55,19 @@ public static function distribution($value, $degrees, $tails)
* Returns the one-tailed probability of the chi-squared distribution.
*
* @param mixed $probability Float probability for the function
* Or can be an array of values
* @param mixed $degrees Integer value for degrees of freedom
* Or can be an array of values
*
* @return float|string The result, or a string containing an error
* @return array|float|string The result, or a string containing an error
* If an array of numbers is passed as an argument, then the returned result will also be an array
* with the same dimensions
*/
public static function inverse($probability, $degrees)
{
$probability = Functions::flattenSingleValue($probability);
$degrees = Functions::flattenSingleValue($degrees);
if (is_array($probability) || is_array($degrees)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $probability, $degrees);
}

try {
$probability = DistributionValidations::validateProbability($probability);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,30 +2,38 @@

namespace PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions;

use PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use PhpOffice\PhpSpreadsheet\Calculation\Exception;
use PhpOffice\PhpSpreadsheet\Calculation\Functions;

class Weibull
{
use ArrayEnabled;

/**
* WEIBULL.
*
* Returns the Weibull distribution. Use this distribution in reliability
* analysis, such as calculating a device's mean time to failure.
*
* @param mixed $value Float value for the distribution
* Or can be an array of values
* @param mixed $alpha Float alpha Parameter
* Or can be an array of values
* @param mixed $beta Float beta Parameter
* Or can be an array of values
* @param mixed $cumulative Boolean value indicating if we want the cdf (true) or the pdf (false)
* Or can be an array of values
*
* @return float|string (string if result is an error)
* @return array|float|string (string if result is an error)
* If an array of numbers is passed as an argument, then the returned result will also be an array
* with the same dimensions
*/
public static function distribution($value, $alpha, $beta, $cumulative)
{
$value = Functions::flattenSingleValue($value);
$alpha = Functions::flattenSingleValue($alpha);
$beta = Functions::flattenSingleValue($beta);
$cumulative = Functions::flattenSingleValue($cumulative);
if (is_array($value) || is_array($alpha) || is_array($beta) || is_array($cumulative)) {
return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $alpha, $beta, $cumulative);
}

try {
$value = DistributionValidations::validateFloat($value);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace PhpOffice\PhpSpreadsheetTests\Calculation\Functions\Statistical;

use PhpOffice\PhpSpreadsheet\Calculation\Calculation;
use PhpOffice\PhpSpreadsheet\Calculation\Statistical;
use PHPUnit\Framework\TestCase;

Expand All @@ -22,4 +23,32 @@ public function providerNORMDIST(): array
{
return require 'tests/data/Calculation/Statistical/NORMDIST.php';
}

/**
* @dataProvider providerNormDistArray
*/
public function testNormDistArray(array $expectedResult, string $values, string $mean, string $stdDev): void
{
$calculation = Calculation::getInstance();

$formula = "=NORMDIST({$values}, {$mean}, {$stdDev}, false)";
$result = $calculation->_calculateFormulaValue($formula);
self::assertEqualsWithDelta($expectedResult, $result, 1.0e-14);
}

public function providerNormDistArray(): array
{
return [
'row/column vectors' => [
[
[0.04324582990797181, 0.03549422283581691, 0.026885636057682592],
[0.07365402806066465, 0.038837210996642585, 0.015790031660178828],
[0.12098536225957167, 0.0022159242059690033, 7.991870553452737E-6],
],
'12',
'{10, 6, 3}',
'{9; 5; 2}',
],
];
}
}
Loading

0 comments on commit cdbe5c7

Please sign in to comment.