issue-#215 - fix the step validator caused by a precision error when substracting
MODIFY
src/Step.php
src/Step.php
@@ -122,7 +122,9 @@ class Step extends AbstractValidator
$this->setValue($value);
- $fmod = $this->fmod($value - $this->baseValue, $this->step);
+ $substract = $this->sub($value, $this->baseValue);
+
+ $fmod = $this->fmod($substract, $this->step);
if ($fmod !== 0.0 && $fmod !== $this->step) {
$this->error(self::NOT_STEP);
@@ -146,10 +148,27 @@ class Step extends AbstractValidator
}
//find the maximum precision from both input params to give accurate results
- $xFloatSegment = substr($x, strpos($x, '.') + 1) ?: '';
- $yFloatSegment = substr($y, strpos($y, '.') + 1) ?: '';
- $precision = strlen($xFloatSegment) + strlen($yFloatSegment);
+ $precision = $this->getPrecision($x) + $this->getPrecision($y);
return round($x - $y * floor($x / $y), $precision);
}
+
+ /**
+ * replaces the internal substraction operation which give wrong results on some cases
+ *
+ * @param float $x
+ * @param float $y
+ * @return float
+ */
+ private function sub($x, $y)
+ {
+ $precision = $this->getPrecision($x) + $this->getPrecision($y);
+ return round($x - $y, $precision);
+ }
+
+ private function getPrecision($float)
+ {
+ $segment = substr($float, strpos($float, '.') + 1);
+ return $segment ? strlen($segment) : 0;
+ }
}

MODIFY
test/StepTest.php
test/StepTest.php
@@ -124,6 +124,29 @@ class StepTest extends TestCase
$this->assertSame($expected, $validator->isValid($value));
}
+
+ public function decimalStepSubstractionBugValues()
+ {
+ return [
+ 'base-value-20' => [20, 20.06, true],
+ 'base-value-40' => [40, 40.09, true],
+ 'base-value-50' => [50, 50.09, true],
+ ];
+ }
+
+ /**
+ * @dataProvider decimalStepSubstractionBugValues
+ */
+ public function testDecimalStepSubstractionBug($baseValue, $value, $expected)
+ {
+ $validator = new Validator\Step([
+ 'baseValue' => $baseValue,
+ 'step' => 0.01
+ ]);
+
+ $this->assertSame($expected, $validator->isValid($value));
+ }
+
public function decimalHundredthStepValues()
{
return [
@@ -151,7 +174,7 @@ class StepTest extends TestCase
/**
* @dataProvider decimalHundredthStepValues
*/
- public function testDecimalStep2($value, $expected)
+ public function testdecimalHundredthStep($value, $expected)
{
$validator = new Validator\Step([
'baseValue' => 0,

issue-#215 - fix the step validator caused by a precision error when substracting