# tablepress/3.4/libraries/vendor/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php

TablePress – Tables in WordPress made easy, version 3.4. 272 lines.

- Page: https://pluginprobe.com/plugins/tablepress/3.4/code/libraries/vendor/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php
- Raw: https://pluginprobe.com/plugins/tablepress/3.4/raw/libraries/vendor/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php
- Modified: 2026-09-30T03:50:46+00:00

Line numbers below start at 1. Link to a line or a range by appending a fragment to the
page URL, for example `https://pluginprobe.com/plugins/tablepress/3.4/code/libraries/vendor/PhpSpreadsheet/Calculation/Statistical/Distributions/ChiSquared.php#L10-L20`.

```php
<?php

namespace TablePress\PhpOffice\PhpSpreadsheet\Calculation\Statistical\Distributions;

use TablePress\PhpOffice\PhpSpreadsheet\Calculation\ArrayEnabled;
use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Exception;
use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Functions;
use TablePress\PhpOffice\PhpSpreadsheet\Calculation\Information\ExcelError;

class ChiSquared
{
	use ArrayEnabled;

	private const EPS = 2.22e-16;

	/**
	 * CHIDIST.
	 *
	 * Returns the one-tailed probability of the chi-squared distribution.
	 *
	 * @param mixed $value Float value for which we want the probability
	 *                      Or can be an array of values
	 * @param mixed $degrees Integer degrees of freedom
	 *                      Or can be an array of values
	 *
	 * @return array<mixed>|float|int|string 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 distributionRightTail($value, $degrees)
	{
		if (is_array($value) || is_array($degrees)) {
			return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $degrees);
		}

		try {
			$value = DistributionValidations::validateFloat($value);
			$degrees = DistributionValidations::validateInt($degrees);
		} catch (Exception $e) {
			return $e->getMessage();
		}

		if ($degrees < 1) {
			return ExcelError::NAN();
		}
		if ($value < 0) {
			if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) {
				return 1;
			}

			return ExcelError::NAN();
		}

		return Gamma::regularizedGammaQ($degrees / 2, $value / 2);
	}

	/**
	 * CHIDIST.
	 *
	 * Returns the one-tailed probability of the chi-squared distribution.
	 *
	 * @param mixed $value Float value for which we want the probability
	 *                      Or can be an array of values
	 * @param mixed $degrees Integer degrees of freedom
	 *                      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 array<mixed>|float|int|string 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 distributionLeftTail($value, $degrees, $cumulative)
	{
		if (is_array($value) || is_array($degrees) || is_array($cumulative)) {
			return self::evaluateArrayArguments([self::class, __FUNCTION__], $value, $degrees, $cumulative);
		}

		try {
			$value = DistributionValidations::validateFloat($value);
			$degrees = DistributionValidations::validateInt($degrees);
			$cumulative = DistributionValidations::validateBool($cumulative);
		} catch (Exception $e) {
			return $e->getMessage();
		}

		if ($degrees < 1) {
			return ExcelError::NAN();
		}
		if ($value < 0) {
			if (Functions::getCompatibilityMode() == Functions::COMPATIBILITY_GNUMERIC) {
				return 1;
			}

			return ExcelError::NAN();
		}

		if ($cumulative === true) {
			$temp = self::distributionRightTail($value, $degrees);

			return 1 - (is_numeric($temp) ? $temp : 0);
		}

		if ($value == 0.0) {
			if ($degrees === 2) {
				return 0.5;
			}

			return ($degrees === 1) ? INF : 0.0;
		}

		// Log domain, so large degrees of freedom cannot overflow Gamma(d/2).
		return exp((($degrees / 2) - 1) * log($value) - $value / 2 - ($degrees / 2) * M_LN2 - Gamma::logGamma($degrees / 2));
	}

	/**
	 * CHIINV.
	 *
	 * Returns the inverse of the right-tailed probability of the chi-squared distribution.
	 *
	 * @param mixed $probability Float probability at which you want to evaluate the distribution
	 *                      Or can be an array of values
	 * @param mixed $degrees Integer degrees of freedom
	 *                      Or can be an array of values
	 *
	 * @return array<mixed>|float|string 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 inverseRightTail($probability, $degrees)
	{
		if (is_array($probability) || is_array($degrees)) {
			return self::evaluateArrayArguments([self::class, __FUNCTION__], $probability, $degrees);
		}

		try {
			$probability = DistributionValidations::validateProbability($probability);
			$degrees = DistributionValidations::validateInt($degrees);
		} catch (Exception $e) {
			return $e->getMessage();
		}

		if ($degrees < 1) {
			return ExcelError::NAN();
		}

		$callback = fn (float $value): float => Gamma::regularizedGammaQ($degrees / 2, $value / 2);

		$newtonRaphson = new NewtonRaphson($callback);

		return $newtonRaphson->execute($probability);
	}

	/**
	 * CHIINV.
	 *
	 * Returns the inverse of the left-tailed probability of the chi-squared distribution.
	 *
	 * @param mixed $probability Float probability at which you want to evaluate the distribution
	 *                      Or can be an array of values
	 * @param mixed $degrees Integer degrees of freedom
	 *                      Or can be an array of values
	 *
	 * @return array<mixed>|float|string 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 inverseLeftTail($probability, $degrees)
	{
		if (is_array($probability) || is_array($degrees)) {
			return self::evaluateArrayArguments([self::class, __FUNCTION__], $probability, $degrees);
		}

		try {
			$probability = DistributionValidations::validateProbability($probability);
			$degrees = DistributionValidations::validateInt($degrees);
		} catch (Exception $e) {
			return $e->getMessage();
		}

		if ($degrees < 1) {
			return ExcelError::NAN();
		}

		return self::inverseLeftTailCalculation($probability, $degrees);
	}

	/**
				 * CHITEST.
				 *
				 * Uses the chi-square test to calculate the probability that the differences between two supplied data sets
				 *      (of observed and expected frequencies), are likely to be simply due to sampling error,
				 *      or if they are likely to be real.
				 *
				 * @param float[] $actual an array of observed frequencies
				 * @param float[] $expected an array of expected frequencies
				 * @return float|string
				 */
				public static function test($actual, $expected)
	{
		$rows = count($actual);
		/** @var float[] */
		$actual = Functions::flattenArray($actual);
		/** @var float[] */
		$expected = Functions::flattenArray($expected);
		$columns = intdiv(count($actual), $rows);

		$countActuals = count($actual);
		$countExpected = count($expected);
		if ($countActuals !== $countExpected || $countActuals === 1) {
			return ExcelError::NAN();
		}

		$result = 0.0;
		for ($i = 0; $i < $countActuals; ++$i) {
			if ($expected[$i] == 0.0) {
				return ExcelError::DIV0();
			} elseif ($expected[$i] < 0.0) {
				return ExcelError::NAN();
			}
			$result += (($actual[$i] - $expected[$i]) ** 2) / $expected[$i];
		}

		$degrees = self::degrees($rows, $columns);

		/** @var float|string */
		$result = Functions::scalar(self::distributionRightTail($result, $degrees));

		return $result;
	}

	protected static function degrees(int $rows, int $columns): int
	{
		if ($rows === 1) {
			return $columns - 1;
		} elseif ($columns === 1) {
			return $rows - 1;
		}

		return ($columns - 1) * ($rows - 1);
	}

	private static function inverseLeftTailCalculation(float $probability, int $degrees): float
	{
		// bracket the root
		$min = 0;
		$sd = sqrt(2.0 * $degrees);
		$max = 2 * $sd;
		$s = -1;

		while ($s * self::pchisq($max, $degrees) > $probability * $s) {
			$min = $max;
			$max += 2 * $sd;
		}

		// Find root using bisection
		$chi2 = 0.5 * ($min + $max);

		while (($max - $min) > self::EPS * $chi2) {
			if ($s * self::pchisq($chi2, $degrees) > $probability * $s) {
				$min = $chi2;
			} else {
				$max = $chi2;
			}
			$chi2 = 0.5 * ($min + $max);
		}

		return $chi2;
	}

	private static function pchisq(float $chi2, int $degrees): float
	{
		return Gamma::regularizedGammaP($degrees / 2, 0.5 * $chi2);
	}
}

```
