[
https://issues.apache.org/jira/browse/GEOMETRY-162?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=17807259#comment-17807259
]
Gilles Sadowski commented on GEOMETRY-162:
------------------------------------------
Hi.
Please edit the description and enclose code excerpts between "\{code}" tags
(this will avoid spurious interpretation of certain character sequences by the
JIRA software).
{quote}I've prepared a couple of simple unit tests in `Vector2DTest` and
`Vector3DTest` classes illustrating the issue.
{quote}
To help the reviewers, could you please attach "patch" files to this report, or
open pull requests (one with unit tests failing with the current code, and one
with the proposed fix)?
{quote}[...] same value of hash code is returned where it is expected to be
different for non-identical instances [...]
{quote}
When 2 instances are deemed equal (according to the
[{{equals}}|https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#equals-java.lang.Object-]
method), their hash codes must be equal.
Although desirable, the hash code is not _required_ to be different for
different instances (excerpt from
[{{hashCode}}|https://docs.oracle.com/javase/8/docs/api/java/lang/Object.html#hashCode--]
doc):
{noformat}
As much as is reasonably practical, the hashCode method defined by class Object
does return distinct integers for distinct objects.
{noformat}
However, what you noticed is probably unintentional, and should thus be
addressed. Thank you for the report!
> Hash collision for vectors symmetrical about coordinate hyperplanes
> -------------------------------------------------------------------
>
> Key: GEOMETRY-162
> URL: https://issues.apache.org/jira/browse/GEOMETRY-162
> Project: Commons Geometry
> Issue Type: Bug
> Components: euclidean2D, euclidean3D
> Reporter: Ivan Shuba
> Priority: Minor
> Labels: Bug
>
> h1. Overview
> This issue is related to that the same value of hash code is returned where
> it is expected to be different for non-identical instances of `Vector2D` and
> `Vector3D` classes.
> In particular, for 2D case, if we generate a pair of vectors which are
> symmetrical about the X, or Y coordinate axes, then both such vectors will
> return same hash code value. For 3D case, the hash code seems to be equal
> only if the vectors are symmetrical about YZ plane.
> h2. Examples
> The following examples illustrate the problem and can be easily reproduced.
> h4. The Vector2D case, symmetrical about Y axis
> For example, if we have a following pair of collinear `Vector2D` instances:
> {{Vector2D a = Vector2D.of(-10.0, 0); //400556032}}
> {{Vector2D b = Vector2D.of(+10.0, 0); //400556032}}
> Then they both will return a value of 400556032 if the `hashCode()` method is
> called.
> The same will happen if we make non-collinear pair of symmetrical vectors (
> with non-zero value of Y coordinate ):
> {{Vector2D a = Vector2D.of(-20.0, 10.0); //-326631424}}
> {{Vector2D b = Vector2D.of(+20.0, 10.0); //-326631424}}
> h4. The Vector2D case, symmetrical about X axis
> The same holds if we consider a pair of vectors symmetrical about X axis
> {{Vector2D a = Vector2D.of(10.0, -30.0); //-1251213312}}
> {{Vector2D b = Vector2D.of(10.0, +30.0); //-1251213312}}
> Even if we generate arbitrary random number to test the issue, the vectors
> will still return the same hash code value.
> final double ANY = Math.random();
> {{int hashA = Vector2D.of(10.0, ANY); }}
> {{int hashB = Vector2D.of(10.0, ANY); }}
> {{Assertions.assertNotEquals(hashA, hashB); // fails}}
> h4. The Vector3D case
> For Vector3D class, the issue seems to arise only if the instances are
> symmetrical about YZ plane.
>
> {{final double ANY = Math.random();}}
> {{final double NEG = -ANY;}}
> {{final double POS = +ANY;}}
> {{int negX = Vector3D.of(NEG, 0.0, 0.0);}}
> {{int posX = Vector3D.of(POS, 0.0, 0.0);}}
> int negY = Vector3D.of(0.0, NEG, 0.0);{{int posY = Vector3D.of(0.0, POS,
> 0.0);}}
> {{int negZ = Vector3D.of(0.0, 0.0, NEG);}}
> {{int posZ = Vector3D.of(0.0, 0.0, POS);}}
> {{Assertions.assertNotEquals(negX, posX); // fails}}
> {{Assertions.assertNotEquals(negY, posY); // passes}}
> {{Assertions.assertNotEquals(negZ, posZ); // passes}}
> h2. Possible solution
> To avoid clashes one could use modified version of the `hashCode` method.
> Here's one for Vector3D class:
>
> {{@Override}}
> {{public int hashCode() {}}
> {{ int result;}}
> {{ long temp;}}
> {{ temp = Double.doubleToLongBits(x);}}
> {{ result = (int) (temp ^ (temp >>> 32));}}
> {{ temp = Double.doubleToLongBits(y);}}
> {{ result = 31 * result + (int) (temp ^ (temp >>> 32));}}
> {{ temp = Double.doubleToLongBits(z);}}
> {{ result = 31 * result + (int) (temp ^ (temp >>> 32));}}
> {{ return result;}}
> {{}}}
>
> P.S. I've prepared a couple of simple unit tests in `Vector2DTest` and
> `Vector3DTest` classes illustrating the issue.
--
This message was sent by Atlassian Jira
(v8.20.10#820010)