diff --git a/src/PhpSpreadsheet/Calculation/Statistical.php b/src/PhpSpreadsheet/Calculation/Statistical.php index eeee84fe..847fd47d 100644 --- a/src/PhpSpreadsheet/Calculation/Statistical.php +++ b/src/PhpSpreadsheet/Calculation/Statistical.php @@ -1022,12 +1022,20 @@ class Statistical // Loop through arguments $aArgs = Functions::flattenArrayIndexed($args); foreach ($aArgs as $k => $arg) { + // MS Excel does not count Booleans if passed as cell values, but they are counted if passed as literals + // OpenOffice Calc always counts Booleans + // Gnumeric never counts Booleans if ((is_bool($arg)) && - ((!Functions::isCellValue($k)) || (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_OPENOFFICE))) { + ((!Functions::isCellValue($k) && (Functions::getCompatibilityMode() === Functions::COMPATIBILITY_EXCEL)) || + (Functions::getCompatibilityMode() === Functions::COMPATIBILITY_OPENOFFICE))) { $arg = (int) $arg; } // Is it a numeric value? - if ((is_numeric($arg)) && (!is_string($arg))) { + // Strings containing numeric values are only counted if they are string literals (not cell values) + // and then only in MS Excel and in Open Office, not in Gnumeric + if (((is_numeric($arg)) && (!is_string($arg))) || + ((is_numeric($arg)) && (!Functions::isCellValue($k)) && + (Functions::getCompatibilityMode() !== Functions::COMPATIBILITY_GNUMERIC))) { ++$returnValue; } } @@ -1054,10 +1062,10 @@ class Statistical $returnValue = 0; // Loop through arguments - $aArgs = Functions::flattenArray($args); - foreach ($aArgs as $arg) { - // Is it a numeric, boolean or string value? - if ((is_numeric($arg)) || (is_bool($arg)) || ((is_string($arg) && ($arg != '')))) { + $aArgs = Functions::flattenArrayIndexed($args); + foreach ($aArgs as $k => $arg) { + // Nulls are counted if literals, but not if cell values + if ($arg !== null || (!Functions::isCellValue($k))) { ++$returnValue; } } @@ -1264,19 +1272,24 @@ class Statistical $alpha = Functions::flattenSingleValue($alpha); if ((is_numeric($trials)) && (is_numeric($probability)) && (is_numeric($alpha))) { + $trials = (int) $trials; + $trialsApprox = $trials; if ($trials < 0) { return Functions::NAN(); - } elseif (($probability < 0) || ($probability > 1)) { + } elseif (($probability < 0.0) || ($probability > 1.0)) { return Functions::NAN(); - } elseif (($alpha < 0) || ($alpha > 1)) { + } elseif (($alpha < 0.0) || ($alpha > 1.0)) { return Functions::NAN(); - } elseif ($alpha <= 0.5) { + } + + if ($alpha <= 0.5) { $t = sqrt(log(1 / ($alpha * $alpha))); $trialsApprox = 0 - ($t + (2.515517 + 0.802853 * $t + 0.010328 * $t * $t) / (1 + 1.432788 * $t + 0.189269 * $t * $t + 0.001308 * $t * $t * $t)); } else { $t = sqrt(log(1 / pow(1 - $alpha, 2))); $trialsApprox = $t - (2.515517 + 0.802853 * $t + 0.010328 * $t * $t) / (1 + 1.432788 * $t + 0.189269 * $t * $t + 0.001308 * $t * $t * $t); } + $Guess = floor($trials * $probability + $trialsApprox * sqrt($trials * $probability * (1 - $probability))); if ($Guess < 0) { $Guess = 0; diff --git a/src/PhpSpreadsheet/Style/Color.php b/src/PhpSpreadsheet/Style/Color.php index 0a2209e8..60e4a8ce 100644 --- a/src/PhpSpreadsheet/Style/Color.php +++ b/src/PhpSpreadsheet/Style/Color.php @@ -209,11 +209,8 @@ class Color extends Supervisor private static function getColourComponent($RGB, $offset, $hex = true) { $colour = substr($RGB, $offset, 2); - if (!$hex) { - $colour = hexdec($colour); - } - return $colour; + return ($hex) ? $colour : hexdec($colour); } /** @@ -268,7 +265,7 @@ class Color extends Supervisor */ public static function changeBrightness($hex, $adjustPercentage) { - $rgba = (strlen($hex) == 8); + $rgba = (strlen($hex) === 8); $red = self::getRed($hex, false); $green = self::getGreen($hex, false); @@ -300,9 +297,9 @@ class Color extends Supervisor } $rgb = strtoupper( - str_pad(dechex($red), 2, '0', 0) . - str_pad(dechex($green), 2, '0', 0) . - str_pad(dechex($blue), 2, '0', 0) + str_pad(dechex((int) $red), 2, '0', 0) . + str_pad(dechex((int) $green), 2, '0', 0) . + str_pad(dechex((int) $blue), 2, '0', 0) ); return (($rgba) ? 'FF' : '') . $rgb; diff --git a/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AveDevTest.php b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AveDevTest.php new file mode 100644 index 00000000..6babf483 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Calculation/Functions/Statistical/AveDevTest.php @@ -0,0 +1,31 @@ + Date::stringToExcel('1900-02-01'), + '0.2.A' => 0, + '0.3.A' => null, + '0.4.A' => 1.2, + '0.5.A' => '', + '0.6.A' => 2.4, + '0.7.A' => null, + '0.8.A' => '', + '0.9.A' => 3.6, + '0.10.A' => null, + '0.11.A' => '', + '0.12.A' => 4.8, + '0.13.A' => 'Not a numeric', + '0.14.A' => 6 + ], + ], + [ + 14, + [ + // No index indicates arguments passed as literals rather than cell values + // In this case, nuls are counted as well as numbers + Date::stringToExcel('1900-02-01'), + 0, + null, + 1.2, + '', + 2.4, + null, + '', + 3.6, + null, + '', + 4.8, + 'Not a numeric', + 6 + ], + ], +]; diff --git a/tests/data/Calculation/Statistical/COUNTBLANK.php b/tests/data/Calculation/Statistical/COUNTBLANK.php new file mode 100644 index 00000000..35b43167 --- /dev/null +++ b/tests/data/Calculation/Statistical/COUNTBLANK.php @@ -0,0 +1,8 @@ + 'A', + '0.2.A' => 1, + '0.3.A' => true, + '0.4.A' => 2.9, + '0.5.A' => false, + '0.6.A' => '3', + '0.7.A' => '', + '0.8.A' => null, + '0.9.A' => 9, + ], + ], + [ + 6, + [ + // No index indicates arguments passed as literals rather than cell values + // In this case, booleans are counted as well as numbers, as are numeric-value string literals + 'A', + 1, + true, + 2.9, + false, + '3', + '', + null, + 9, + ], + ], +]; diff --git a/tests/data/Calculation/Statistical/GnumericCOUNT.php b/tests/data/Calculation/Statistical/GnumericCOUNT.php new file mode 100644 index 00000000..1b496650 --- /dev/null +++ b/tests/data/Calculation/Statistical/GnumericCOUNT.php @@ -0,0 +1,34 @@ + 'A', + '0.2.A' => 1, + '0.3.A' => true, + '0.4.A' => 2.9, + '0.5.A' => false, + '0.6.A' => '3', + '0.7.A' => '', + '0.8.A' => null, + '0.9.A' => 9, + ], + ], + [ + 3, + [ + // No index indicates arguments passed as literals rather than cell values + 'A', + 1, + true, + 2.9, + false, + '3', + '', + null, + 9, + ], + ], +]; diff --git a/tests/data/Calculation/Statistical/OpenOfficeCOUNT.php b/tests/data/Calculation/Statistical/OpenOfficeCOUNT.php new file mode 100644 index 00000000..19026d31 --- /dev/null +++ b/tests/data/Calculation/Statistical/OpenOfficeCOUNT.php @@ -0,0 +1,36 @@ + 'A', + '0.2.A' => 1, + '0.3.A' => true, + '0.4.A' => 2.9, + '0.5.A' => false, + '0.6.A' => '3', + '0.7.A' => '', + '0.8.A' => null, + '0.9.A' => 9, + ], + ], + [ + 6, + [ + // No index indicates arguments passed as literals rather than cell values + // In this case, booleans are counted as well as numbers, as are numeric-value string literals + 'A', + 1, + true, + 2.9, + false, + '3', + '', + null, + 9, + ], + ], +]; diff --git a/tests/data/Calculation/Statistical/PERMUT.php b/tests/data/Calculation/Statistical/PERMUT.php new file mode 100644 index 00000000..bcaa3e0c --- /dev/null +++ b/tests/data/Calculation/Statistical/PERMUT.php @@ -0,0 +1,48 @@ +