{"record":{"id":"99ccd3d745a119dc","repo":"sebastianbergmann/comparator","slug":"failed-asserting-that-two-number-objects-are-equal","errorCode":null,"errorMessage":"Failed asserting that two Number objects are equal.","messagePattern":"Failed asserting that two Number objects are equal\\.","errorType":"exception","errorClass":"ComparisonFailure","httpStatus":null,"severity":"error","filePath":"src/NumberComparator.php","lineNumber":61,"sourceCode":"    public function assertEquals(mixed $expected, mixed $actual, float $delta = 0.0, bool $canonicalize = false, bool $ignoreCase = false, array &$processed = []): void\n    {\n        if (!$expected instanceof Number) {\n            assert(is_int($expected) || is_string($expected) && is_numeric($expected));\n\n            $expected = new Number($expected);\n        }\n\n        if (!$actual instanceof Number) {\n            assert(is_int($actual) || is_string($actual) && is_numeric($actual));\n\n            $actual = new Number($actual);\n        }\n\n        /** @phpstan-ignore argument.type */\n        $deltaNumber = new Number(number_format($delta, max($expected->scale, $actual->scale)));\n\n        if ($actual < $expected - $deltaNumber || $actual > $expected + $deltaNumber) {\n            throw new ComparisonFailure(\n                $expected,\n                $actual,\n                (string) $expected,\n                (string) $actual,\n                'Failed asserting that two Number objects are equal.',\n                $this->contextLines(),\n            );\n        }\n    }\n}\n","sourceCodeStart":43,"sourceCodeEnd":72,"githubUrl":"https://github.com/sebastianbergmann/comparator/blob/00837a9d227b4e123b0b42a91736960f6b0b3583/src/NumberComparator.php#L43-L72","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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"],"exampleFix":"// before\n$this->assertEquals(new Number('0.30'), new Number('0.1') + new Number('0.2')); // 0.3 vs 0.30 fails at delta 0\n// after\n$this->assertEqualsWithDelta(new Number('0.30'), new Number('0.1') + new Number('0.2'), 0.001);","handlingStrategy":"validation","validationCode":"if (abs((float)(string)$actual - (float)(string)$expected) > $tolerance) {\n    throw new InvalidArgumentException('Number values differ beyond tolerance');\n}","typeGuard":"function isBcNumber(mixed $v): bool { return $v instanceof \\BcMath\\Number || is_int($v) || (is_string($v) && is_numeric($v)); }","tryCatchPattern":"try {\n    $comparator->assertEquals($expected, $actual, $delta);\n} catch (ComparisonFailure $e) {\n    // log both string representations from $e->getExpected()/getActual()\n}","preventionTips":["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"],"tags":["php","phpunit","bcmath","decimal","assertion"],"backgroundTag":"value-out-of-range","analyzedSha":"00837a9d227b4e123b0b42a91736960f6b0b3583","analyzedAt":"2026-09-15T03:36:55.154Z","contentChangedAt":"2026-09-15T03:36:55.154Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}