Modify numeric comparisons in calculation engine to make allowance for floating point imprecision

This commit is contained in:
MarkBaker 2015-01-17 22:51:48 +00:00
parent 16f2eb63a1
commit c089cfd53f
1 changed files with 19 additions and 6 deletions

View File

@ -1726,6 +1726,7 @@ class PHPExcel_Calculation {
if ($this->_savedPrecision < $setPrecision) { if ($this->_savedPrecision < $setPrecision) {
ini_set('precision',$setPrecision); ini_set('precision',$setPrecision);
} }
$this->delta = 1 * pow(10, -$setPrecision);
if ($workbook !== NULL) { if ($workbook !== NULL) {
self::$_workbookSets[$workbook->getID()] = $this; self::$_workbookSets[$workbook->getID()] = $this;
@ -3600,27 +3601,39 @@ class PHPExcel_Calculation {
break; break;
// Equality // Equality
case '=': case '=':
$result = ($operand1 == $operand2); if (is_numeric($operand1) && is_numeric($operand2)) {
$result = (abs($operand1 - $operand2) < $this->delta);
} else {
$result = strcmp($operand1, $operand2) == 0;
}
break; break;
// Greater than or equal // Greater than or equal
case '>=': case '>=':
if ($useLowercaseFirstComparison) { if (is_numeric($operand1) && is_numeric($operand2)) {
$result = ((abs($operand1 - $operand2) < $this->delta) || ($operand1 > $operand2));
} elseif ($useLowercaseFirstComparison) {
$result = $this->strcmpLowercaseFirst($operand1, $operand2) >= 0; $result = $this->strcmpLowercaseFirst($operand1, $operand2) >= 0;
} else { } else {
$result = ($operand1 >= $operand2); $result = strcmp($operand1, $operand2) >= 0;
} }
break; break;
// Less than or equal // Less than or equal
case '<=': case '<=':
if ($useLowercaseFirstComparison) { if (is_numeric($operand1) && is_numeric($operand2)) {
$result = ((abs($operand1 - $operand2) < $this->delta) || ($operand1 < $operand2));
} elseif ($useLowercaseFirstComparison) {
$result = $this->strcmpLowercaseFirst($operand1, $operand2) <= 0; $result = $this->strcmpLowercaseFirst($operand1, $operand2) <= 0;
} else { } else {
$result = ($operand1 <= $operand2); $result = strcmp($operand1, $operand2) <= 0;
} }
break; break;
// Inequality // Inequality
case '<>': case '<>':
$result = ($operand1 != $operand2); if (is_numeric($operand1) && is_numeric($operand2)) {
$result = (abs($operand1 - $operand2) > 1E-14);
} else {
$result = strcmp($operand1, $operand2) != 0;
}
break; break;
} }