Skip to content
This repository was archived by the owner on Jan 31, 2020. It is now read-only.

Commit 0828ee6

Browse files
committed
Merge branch 'hotfix/218'
Close #218 Fixes #215
2 parents b9731ea + d67fd4a commit 0828ee6

File tree

3 files changed

+52
-6
lines changed

3 files changed

+52
-6
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ All notable changes to this project will be documented in this file, in reverse
2222

2323
### Fixed
2424

25-
- Nothing.
25+
- [#218](https://github.com/zendframework/zend-validator/pull/218) fixes a precision issue with the `Step` validator.
2626

2727
## 2.10.2 - 2018-02-01
2828

src/Step.php

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,9 @@ public function isValid($value)
122122

123123
$this->setValue($value);
124124

125-
$fmod = $this->fmod($value - $this->baseValue, $this->step);
125+
$substract = $this->sub($value, $this->baseValue);
126+
127+
$fmod = $this->fmod($substract, $this->step);
126128

127129
if ($fmod !== 0.0 && $fmod !== $this->step) {
128130
$this->error(self::NOT_STEP);
@@ -146,10 +148,31 @@ protected function fmod($x, $y)
146148
}
147149

148150
//find the maximum precision from both input params to give accurate results
149-
$xFloatSegment = substr($x, strpos($x, '.') + 1) ?: '';
150-
$yFloatSegment = substr($y, strpos($y, '.') + 1) ?: '';
151-
$precision = strlen($xFloatSegment) + strlen($yFloatSegment);
151+
$precision = $this->getPrecision($x) + $this->getPrecision($y);
152152

153153
return round($x - $y * floor($x / $y), $precision);
154154
}
155+
156+
/**
157+
* replaces the internal substraction operation which give wrong results on some cases
158+
*
159+
* @param float $x
160+
* @param float $y
161+
* @return float
162+
*/
163+
private function sub($x, $y)
164+
{
165+
$precision = $this->getPrecision($x) + $this->getPrecision($y);
166+
return round($x - $y, $precision);
167+
}
168+
169+
/**
170+
* @param float $float
171+
* @return int
172+
*/
173+
private function getPrecision($float)
174+
{
175+
$segment = substr($float, strpos($float, '.') + 1);
176+
return $segment ? strlen($segment) : 0;
177+
}
155178
}

test/StepTest.php

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,29 @@ public function testDecimalStep($value, $expected)
124124
$this->assertSame($expected, $validator->isValid($value));
125125
}
126126

127+
128+
public function decimalStepSubstractionBugValues()
129+
{
130+
return [
131+
'base-value-20' => [20, 20.06, true],
132+
'base-value-40' => [40, 40.09, true],
133+
'base-value-50' => [50, 50.09, true],
134+
];
135+
}
136+
137+
/**
138+
* @dataProvider decimalStepSubstractionBugValues
139+
*/
140+
public function testDecimalStepSubstractionBug($baseValue, $value, $expected)
141+
{
142+
$validator = new Validator\Step([
143+
'baseValue' => $baseValue,
144+
'step' => 0.01
145+
]);
146+
147+
$this->assertSame($expected, $validator->isValid($value));
148+
}
149+
127150
public function decimalHundredthStepValues()
128151
{
129152
return [
@@ -151,7 +174,7 @@ public function decimalHundredthStepValues()
151174
/**
152175
* @dataProvider decimalHundredthStepValues
153176
*/
154-
public function testDecimalStep2($value, $expected)
177+
public function testdecimalHundredthStep($value, $expected)
155178
{
156179
$validator = new Validator\Step([
157180
'baseValue' => 0,

0 commit comments

Comments
 (0)