Java Faster Equals method For float 类型
Java Faster Equals method For float type
据我所知set.add使用FastFloat的equals方法
对我来说重要的只是点后的前两位数(!!!),所以在 equals 方法中我使用 Math.abs() >= 0.001
来使 equals 更快,但我不明白为什么这个代码 return 2
而不是 1
因为 Math.abs(3.54 - 3.5405) < 0.001
代码:
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class st {
public class FastFloat {
private float ff;
public FastFloat(float ff) {
super();
this.ff = ff;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getOuterType().hashCode();
result = prime * result + Float.floatToIntBits(ff);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof FastFloat))
return false;
FastFloat other = (FastFloat) obj;
if (!getOuterType().equals(other.getOuterType()))
return false;
/* if (Float.floatToIntBits(ff) != Float.floatToIntBits(other.ff))
return false;*/
if (Math.abs(ff - other.ff) >= 0.001)
return false;
return true;
}
private st getOuterType() {
return st.this;
}
}
public static void main(String[] args) {
List<Set<FastFloat>> lsff = new ArrayList<>();
lsff.add(0, new HashSet<>());
Set<FastFloat> sff = lsff.get(0);
st x = new st();
sff.add(x.new FastFloat((float)3.54));
sff.add(x.new FastFloat((float)3.5405));
System.out.println(lsff.get(0).size());
}
}
您的 hashCode()
方法为 ff==3.54
和 ff==3.5405
给出了不同的结果,因此它们被分配给 HashSet
和您的 equals
方法的不同桶从未用于测试它们是否相等。
如果a.equals(b)
,a.hashCode()
必须等于b.hashCode()
。这就是合同。
来自 equals()
Javadoc:
Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.
如果你想为 float 实现 .equals()
/.hashCode()
并且一些 float 是相等的。因此,您可以将 class 与 HashSet
或 HashMap
.
一起使用
这样做的一种方法是从 Float.floatToInBits()
中去除最后 <23 位(当您去除二进制位而不是小数位时,保留 4 个有效的小数位,即去除大约 10 个二进制位)。您在 .equals()
和 .hashCode()
实现中使用结果 int。
我没有用二进制计算所以数字实际上不正确(如果你用十进制计算的例子)
- 1000000 等于 1000555 但与 999999 不同
- 1,00101 等于 1,0013 但不同于 1,00099
这种方法会产生有效的 .equals()
/.hashCode()
,但不会提供您想要的 Math.abs() < 0.001(在相同情况下,abs 会高很多(!)在某些情况下更低)。如果 属性 对您来说更重要,请不要使用 .equals()
/.hashCode()
并创建您自己的 collections.
您正在实施的 almost-equals 类型不符合 Object's contract for equals,因为它不可传递。
考虑 0、0.0009 和 0.0018 的情况。 Math.abs(0.0009 - 0)
小于 0.001,Math.abs(0.0018 - 0.009)
也是如此,但 Math.abs(0.0018 - 0)
大于 0.001。
拥有几乎等于方法并在某些情况下使用它很好,但是要使 HashSet
和其他哈希结构起作用,您需要 equals
和 hashCode
以符合 Object
合同。
如果唯一的原因是 "speed",请排除并发症并使用 Float
。
如果您有其他原因需要在 HashSet
中将不相等的浮点数组合在一起,有很多方法可以将它们划分为等价的 类,包括 [=21= 中讨论的方法].您还可以将其基于纯浮点运算,而无需提取和操作位模式。例如,基于除以 0.001:
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class st {
public class FastFloat {
private float ff;
private float fudgeFactor = 0.001f;
private float fudged;
public FastFloat(float ff) {
super();
this.ff = ff;
this.fudged = (float) Math.rint(ff / fudgeFactor);
}
@Override
public int hashCode() {
return Float.hashCode(fudged);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof FastFloat))
return false;
FastFloat other = (FastFloat) obj;
return Float.compare(this.fudged, other.fudged) == 0;
}
private st getOuterType() {
return st.this;
}
}
public static void main(String[] args) {
List<Set<FastFloat>> lsff = new ArrayList<>();
lsff.add(0, new HashSet<>());
Set<FastFloat> sff = lsff.get(0);
st x = new st();
sff.add(x.new FastFloat((float) 3.54));
sff.add(x.new FastFloat((float) 3.5405));
System.out.println(lsff.get(0).size());
sff.add(x.new FastFloat(0f));
System.out.println(lsff.get(0).size());
}
}
据我所知set.add使用FastFloat的equals方法
对我来说重要的只是点后的前两位数(!!!),所以在 equals 方法中我使用 Math.abs() >= 0.001
来使 equals 更快,但我不明白为什么这个代码 return 2
而不是 1
因为 Math.abs(3.54 - 3.5405) < 0.001
代码:
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class st {
public class FastFloat {
private float ff;
public FastFloat(float ff) {
super();
this.ff = ff;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getOuterType().hashCode();
result = prime * result + Float.floatToIntBits(ff);
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof FastFloat))
return false;
FastFloat other = (FastFloat) obj;
if (!getOuterType().equals(other.getOuterType()))
return false;
/* if (Float.floatToIntBits(ff) != Float.floatToIntBits(other.ff))
return false;*/
if (Math.abs(ff - other.ff) >= 0.001)
return false;
return true;
}
private st getOuterType() {
return st.this;
}
}
public static void main(String[] args) {
List<Set<FastFloat>> lsff = new ArrayList<>();
lsff.add(0, new HashSet<>());
Set<FastFloat> sff = lsff.get(0);
st x = new st();
sff.add(x.new FastFloat((float)3.54));
sff.add(x.new FastFloat((float)3.5405));
System.out.println(lsff.get(0).size());
}
}
您的 hashCode()
方法为 ff==3.54
和 ff==3.5405
给出了不同的结果,因此它们被分配给 HashSet
和您的 equals
方法的不同桶从未用于测试它们是否相等。
如果a.equals(b)
,a.hashCode()
必须等于b.hashCode()
。这就是合同。
来自 equals()
Javadoc:
Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.
如果你想为 float 实现 .equals()
/.hashCode()
并且一些 float 是相等的。因此,您可以将 class 与 HashSet
或 HashMap
.
这样做的一种方法是从 Float.floatToInBits()
中去除最后 <23 位(当您去除二进制位而不是小数位时,保留 4 个有效的小数位,即去除大约 10 个二进制位)。您在 .equals()
和 .hashCode()
实现中使用结果 int。
我没有用二进制计算所以数字实际上不正确(如果你用十进制计算的例子)
- 1000000 等于 1000555 但与 999999 不同
- 1,00101 等于 1,0013 但不同于 1,00099
这种方法会产生有效的 .equals()
/.hashCode()
,但不会提供您想要的 Math.abs() < 0.001(在相同情况下,abs 会高很多(!)在某些情况下更低)。如果 属性 对您来说更重要,请不要使用 .equals()
/.hashCode()
并创建您自己的 collections.
您正在实施的 almost-equals 类型不符合 Object's contract for equals,因为它不可传递。
考虑 0、0.0009 和 0.0018 的情况。 Math.abs(0.0009 - 0)
小于 0.001,Math.abs(0.0018 - 0.009)
也是如此,但 Math.abs(0.0018 - 0)
大于 0.001。
拥有几乎等于方法并在某些情况下使用它很好,但是要使 HashSet
和其他哈希结构起作用,您需要 equals
和 hashCode
以符合 Object
合同。
如果唯一的原因是 "speed",请排除并发症并使用 Float
。
如果您有其他原因需要在 HashSet
中将不相等的浮点数组合在一起,有很多方法可以将它们划分为等价的 类,包括 [=21= 中讨论的方法].您还可以将其基于纯浮点运算,而无需提取和操作位模式。例如,基于除以 0.001:
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class st {
public class FastFloat {
private float ff;
private float fudgeFactor = 0.001f;
private float fudged;
public FastFloat(float ff) {
super();
this.ff = ff;
this.fudged = (float) Math.rint(ff / fudgeFactor);
}
@Override
public int hashCode() {
return Float.hashCode(fudged);
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof FastFloat))
return false;
FastFloat other = (FastFloat) obj;
return Float.compare(this.fudged, other.fudged) == 0;
}
private st getOuterType() {
return st.this;
}
}
public static void main(String[] args) {
List<Set<FastFloat>> lsff = new ArrayList<>();
lsff.add(0, new HashSet<>());
Set<FastFloat> sff = lsff.get(0);
st x = new st();
sff.add(x.new FastFloat((float) 3.54));
sff.add(x.new FastFloat((float) 3.5405));
System.out.println(lsff.get(0).size());
sff.add(x.new FastFloat(0f));
System.out.println(lsff.get(0).size());
}
}