sebastianbergmann/comparator · error · ComparisonFailure
Failed asserting that two Number objects are equal.
Error message
Failed asserting that two Number objects are equal.
What it means
NumberComparator compares BcMath\Number values (arbitrary-precision decimals) within an optional delta. It throws a ComparisonFailure when the actual value falls outside expected ± delta after both sides are normalized to Number objects at the maximum scale of the two operands.
Solutions
- Print both Number values from the failure diff and fix the arithmetic that produces the wrong result
- Pass an appropriate $delta to assertEquals to tolerate rounding differences
- Normalize scales with ->round() or ->setScale() (or number_format) on both sides before comparing
- Update the expected literal if the new precise value is correct
Example fix
// before
$this->assertEquals(new Number('0.30'), new Number('0.1') + new Number('0.2')); // 0.3 vs 0.30 fails at delta 0
// after
$this->assertEqualsWithDelta(new Number('0.30'), new Number('0.1') + new Number('0.2'), 0.001); Defensive patterns
Strategy: validation
Validate before calling
if (abs((float)(string)$actual - (float)(string)$expected) > $tolerance) {
throw new InvalidArgumentException('Number values differ beyond tolerance');
} Type guard
function isBcNumber(mixed $v): bool { return $v instanceof \BcMath\Number || is_int($v) || (is_string($v) && is_numeric($v)); } Try / catch
try {
$comparator->assertEquals($expected, $actual, $delta);
} catch (ComparisonFailure $e) {
// log both string representations from $e->getExpected()/getActual()
} Prevention
- Always pass an explicit delta when comparing computed bcmath results
- Align scales (->setScale/->round) on both operands before comparing
- Beware truncation vs rounding: bcmath truncates; format values deliberately before constructing Number
When it happens
Trigger: assertEquals() on two BcMath\Number values (possibly mixed with int/numeric-string) whose difference exceeds the given $delta, e.g. assertEquals(new Number('1.50'), new Number('2.00')) with delta 0 or too small.
Common situations: Testing money/decimal calculations where rounding or scale differences (1.5 vs 1.50 arithmetic results) make values differ; comparing bcmath results against literals without accounting for scale; passing a delta smaller than the accumulated floating/rounding error.
Understand the failure class
Background: "value must be between 0 and 1" / "out of range" / "must not be negative" errors: fixing range-validation failures across open-source libraries — this error's family across 42 libraries.
Related errors
- Failed asserting that two values of enumeration
- Failed asserting that
- is not instance of expected class " ".
- Failed asserting that two arrays are equal.
- Failed asserting that closure declared at
AI-assisted analysis of sebastianbergmann/comparator@00837a9d22 (2026-09-15).
Data as JSON: /api/errors/99ccd3d745a119dc.
Report an issue: GitHub.
Appendix: source
Thrown at src/NumberComparator.php:61
public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = false, bool $ignoreCase = false, array &$processed = []): void
{
if (!$expected instanceof Number) {
assert(is_int($expected) || is_string($expected) && is_numeric($expected));
$expected = new Number($expected);
}
if (!$actual instanceof Number) {
assert(is_int($actual) || is_string($actual) && is_numeric($actual));
$actual = new Number($actual);
}
/** @phpstan-ignore argument.type */
$deltaNumber = new Number(number_format($delta, max($expected->scale, $actual->scale)));
if ($actual < $expected - $deltaNumber || $actual > $expected + $deltaNumber) {
throw new ComparisonFailure(
$expected,
$actual,
(string) $expected,
(string) $actual,
'Failed asserting that two Number objects are equal.',
$this->contextLines(),
);
}
}
}
View on GitHub (pinned to 00837a9d22)