implement JS password scoring, td_stock approve logicc

This commit is contained in:
Thanakorn S
2026-04-30 15:14:42 +07:00
parent db5c47b6ca
commit ac4fd9a5ad
3147 changed files with 1298 additions and 343 deletions
@@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace ZxcvbnPhp\Math\Impl;
use ZxcvbnPhp\Math\BinomialProvider;
abstract class AbstractBinomialProvider implements BinomialProvider
{
public function binom(int $n, int $k): float
{
if ($k < 0 || $n < 0) {
throw new \DomainException("n and k must be non-negative");
}
if ($k > $n) {
return 0;
}
// $k and $n - $k will always produce the same value, so use smaller of the two
$k = min($k, $n - $k);
return $this->calculate($n, $k);
}
abstract protected function calculate(int $n, int $k): float;
}
@@ -0,0 +1,31 @@
<?php
declare(strict_types=1);
namespace ZxcvbnPhp\Math\Impl;
abstract class AbstractBinomialProviderWithFallback extends AbstractBinomialProvider
{
/**
* @var AbstractBinomialProvider|null
*/
private $fallback = null;
protected function calculate(int $n, int $k): float
{
return $this->tryCalculate($n, $k) ?? $this->getFallbackProvider()->calculate($n, $k);
}
abstract protected function tryCalculate(int $n, int $k): ?float;
abstract protected function initFallbackProvider(): AbstractBinomialProvider;
protected function getFallbackProvider(): AbstractBinomialProvider
{
if ($this->fallback === null) {
$this->fallback = $this->initFallbackProvider();
}
return $this->fallback;
}
}
@@ -0,0 +1,23 @@
<?php
declare(strict_types=1);
namespace ZxcvbnPhp\Math\Impl;
class BinomialProviderFloat64 extends AbstractBinomialProvider
{
protected function calculate(int $n, int $k): float
{
$c = 1.0;
for ($i = 1; $i <= $k; $i++, $n--) {
// We're aiming for $c * $n / $i, but the $c * $n part could cause us to lose precision, so use $c / $i * $n instead. The caveat
// here is that in order to get a precise answer, we need to minimize the chances of going above ~2^52. This is mitigated
// somewhat by dealing with whole part and the remainder separately, but it's not perfect and could overflow in practice, which
// would result in a loss of precision.
$c = floor($c / $i) * $n + floor(fmod($c, $i) * $n / $i);
}
return $c;
}
}
@@ -0,0 +1,33 @@
<?php
declare(strict_types=1);
namespace ZxcvbnPhp\Math\Impl;
use TypeError;
class BinomialProviderInt64 extends AbstractBinomialProviderWithFallback
{
protected function initFallbackProvider(): AbstractBinomialProvider
{
return new BinomialProviderFloat64();
}
protected function tryCalculate(int $n, int $k): ?float
{
try {
$c = 1;
for ($i = 1; $i <= $k; $i++, $n--) {
// We're aiming for $c * $n / $i, but the $c * $n part could overflow, so use $c / $i * $n instead. The caveat here is that in
// order to get a precise answer, we need to avoid floats, which means we need to deal with whole part and the remainder
// separately.
$c = intdiv($c, $i) * $n + intdiv($c % $i * $n, $i);
}
return (float)$c;
} catch (TypeError $ex) {
return null;
}
}
}
@@ -0,0 +1,17 @@
<?php
declare(strict_types=1);
namespace ZxcvbnPhp\Math\Impl;
class BinomialProviderPhp73Gmp extends AbstractBinomialProvider
{
/**
* @noinspection PhpElementIsNotAvailableInCurrentPhpVersionInspection
* @noinspection PhpComposerExtensionStubsInspection
*/
protected function calculate(int $n, int $k): float
{
return (float)gmp_strval(gmp_binomial($n, $k));
}
}