From 89b6abf93bcccf0a04c480b98b840fa07a4d00fd Mon Sep 17 00:00:00 2001 From: PHJ2000 <105151063+PHJ2000@users.noreply.github.com> Date: Mon, 5 Oct 2026 00:35:14 +0900 Subject: [PATCH] Fix long overflow in CosineSimilarity dot product Accumulate products in double so identical vectors with large integer components retain a cosine similarity of one. Individual products still use long arithmetic before being added to the accumulator. Add regression coverage for identical vectors with ordinary, maximum, and minimum integer components. The two large-component cases fail without the accumulator change. Generated-by: OpenAI Codex --- .../commons/text/similarity/CosineSimilarity.java | 2 +- .../text/similarity/CosineSimilarityTest.java | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/main/java/org/apache/commons/text/similarity/CosineSimilarity.java b/src/main/java/org/apache/commons/text/similarity/CosineSimilarity.java index 2c5a123b72..73fff3077b 100644 --- a/src/main/java/org/apache/commons/text/similarity/CosineSimilarity.java +++ b/src/main/java/org/apache/commons/text/similarity/CosineSimilarity.java @@ -86,7 +86,7 @@ public Double cosineSimilarity(final Map leftVector, fina * @return The dot product. */ private double dot(final Map leftVector, final Map rightVector, final Set intersection) { - long dotProduct = 0; + double dotProduct = 0; for (final CharSequence key : intersection) { dotProduct += leftVector.get(key) * (long) rightVector.get(key); } diff --git a/src/test/java/org/apache/commons/text/similarity/CosineSimilarityTest.java b/src/test/java/org/apache/commons/text/similarity/CosineSimilarityTest.java index 0f95908748..87769405de 100644 --- a/src/test/java/org/apache/commons/text/similarity/CosineSimilarityTest.java +++ b/src/test/java/org/apache/commons/text/similarity/CosineSimilarityTest.java @@ -24,9 +24,21 @@ import java.util.Map; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; class CosineSimilarityTest { + @ParameterizedTest + @ValueSource(ints = {1, Integer.MAX_VALUE, Integer.MIN_VALUE}) + void testCosineSimilarityOfIdenticalVectors(final int value) { + final Map vector = new HashMap<>(); + vector.put("a", value); + vector.put("b", value); + vector.put("c", value); + assertEquals(1.0, CosineSimilarity.INSTANCE.cosineSimilarity(vector, vector), 1e-12); + } + @Test void testCosineSimilarityReturningDoubleWhereByteValueIsZero() { final Map hashMap = new HashMap<>();