opened
zz85
username_0
- useful for floating point inaccuracies
- API should be backward compatible
- see #7346

@username_1
Vector Equals uses Number Epsilon Tolerance
issue
created
WestLangley
username_1
I do not think this is useful since you have chosen to hardwire `number.EPSILON`.

For reasons I gave in #7346, I would just not change the `equals` method. Instead, as [suggested](https://github.com/mrdoob/three.js/issues/7346#issuecomment-148644396) by @username_2, I would add

    Vector2.distanceToManhattan( v );
    Vector3.distanceToManhattan( v );

That way, users can use whatever distance metric they prefer when they want to check for closeness -- manhattan, Euclidean or custom.
comment
created
zz85
username_0
should yield true without having think about tolerances or manhattan distances...
comment
created
Usnul
username_2
here's a more concrete criticism of having approximate equals:
```js
Vector2.prototype.equals = function(other){
if(this.x !== other.x){
return false;
}else if(this.y !== other.y){
return false;
}else{
return true;
}
}
``` 
that will need up 1 comparison operation at best and 2 at worst, there's also 1 possible branch in here (after optimization). Consider this:
```js
Vector2.prototype.equals = function(other, distanceError){
var dX = this.x - other.x;
var dY = this.y - other.y;
var dS = dX*dX +dY*dY;
var d = Math.sqrt(dS);
if(d < distanceError){
return true;
}else{
return false;
}
}
```

that's 3 ADD, 2 MULTIPLY, 1 sqrt (however that's implemented) and the same 1 branch. It will also probably take 3 extra registers compared to previous solution.

manhattan variation:
```js
Vector2.prototype.equals = function(other, distanceError){
var dX = Math.abs(this.x - other.x);
var dY = Math.abs(this.y - other.y);
if(dX > distanceError){
return false;
}else if(dY > distanceError){
return false;
}else{
return true;
}
}
```
2 adds, not sure if Math.abs will result in extra ops or not. I guess it's 2 extra registers. The point is - it's extra complexity for very little benefit. Here's an interesting example to boot:
```js
var d = new Vector2(0,Number.EPSILON);
var original = new Vector2(0,0);

var t0 = original.clone();
var t1 = t0.clone().add(d);

for(var i=0; i<1000000; i++){
if(t0.equals(t1)){
t0.copy(t1);
t1.add(d);
}
}

//so, logically t1 === original ?
var totallyTrue = t1.equals(original);

```
comment
created
WestLangley
username_1
@username_0 Yes, but I do not believe your approach is a valid one. Using your method, I get

    new THREE.Vector2( 0, 10.3 ).equals( new THREE.Vector2( 0, 10.2 + 0.1 ) ); // false

I also do not think a method `equals()` should return `true` when the vector components are not equal.
comment
created
zz85
username_0
@username_1 ah too bad, your example is valid.

What do you think of  a `.equals(v)` that uses Number.EPSILON as default, then `.equals(v, biggerTolerance)` if tolerance needs to be adjusted?
comment
created
WestLangley
username_1
@username_0 My opinion is still what I stated in my first comment above: https://github.com/mrdoob/three.js/pull/9170#issuecomment-226942778.

I do not think we should impose a particular distance metric on users, and I do not think we should redefine the meaning of "equals".
comment
created
zz85
username_0
🤔... opinions noted. Though I think `.equals()` usually an overridable implementation, I guess I'll drop this for now too.
comment