diff --git a/src/Reactant/Jobs/RebuildReactionAggregatesJob.php b/src/Reactant/Jobs/RebuildReactionAggregatesJob.php index 28f54c2f..cba96f06 100644 --- a/src/Reactant/Jobs/RebuildReactionAggregatesJob.php +++ b/src/Reactant/Jobs/RebuildReactionAggregatesJob.php @@ -70,13 +70,15 @@ private function recountReactionTotal(): void } $totalCount = ReactionTotal::COUNT_DEFAULT; - $totalWeight = ReactionTotal::WEIGHT_DEFAULT; + $totalWeight = 0; foreach ($counters as $counter) { $totalCount += $counter->getCount(); - $totalWeight += $counter->getWeight(); + $totalWeight += intval($counter->getWeight() * 100); } + $totalWeight = $totalWeight / 100; + $reactionTotal = $this->findOrCreateReactionTotal(); /** @var \Cog\Laravel\Love\Reactant\ReactionTotal\Models\ReactionTotal $reactionTotal */ diff --git a/tests/Unit/Console/Commands/RecountTest.php b/tests/Unit/Console/Commands/RecountTest.php index f2e755fe..2f542075 100644 --- a/tests/Unit/Console/Commands/RecountTest.php +++ b/tests/Unit/Console/Commands/RecountTest.php @@ -906,6 +906,43 @@ public function it_resets_reaction_total_weight_on_recount(): void $this->assertSame(0.0, $reactant2->reactionTotal->weight); } + /** @test */ + public function it_sums_reaction_total_weight_with_floating_point_issue(): void + { + $reactionType = ReactionType::factory()->create(['mass' => 1]); + $reactant1 = Reactant::factory()->create(); + $reactant2 = Reactant::factory()->create(); + Reaction::factory()->create([ + 'reaction_type_id' => $reactionType->getKey(), + 'reactant_id' => $reactant1, + 'rate' => 0.2, + ]); + Reaction::factory()->create([ + 'reaction_type_id' => $reactionType->getKey(), + 'reactant_id' => $reactant1, + 'rate' => 0.1, + ]); + Reaction::factory()->create([ + 'reaction_type_id' => $reactionType->getKey(), + 'reactant_id' => $reactant2, + 'rate' => 0.01, + ]); + Reaction::factory()->create([ + 'reaction_type_id' => $reactionType->getKey(), + 'reactant_id' => $reactant2, + 'rate' => 0.01, + ]); + + $this->artisan('love:recount'); + + /** + * @see https://www.php.net/manual/en/language.types.float.php#language.types.float.comparison + */ + $epsilon = 0.0000000000000001; + $this->assertTrue(abs($reactant1->reactionTotal->weight - 0.3) < $epsilon); + $this->assertTrue(abs($reactant2->reactionTotal->weight - 0.02) < $epsilon); + } + private function reactionsCount( ReactantInterface $reactant, ReactionTypeInterface $reactionType