据我所知set.add使用FastFloat的equals方法
对我来说重要的只是前点后两位数(!!!),所以在equals方法中使得等于更快我使用Math.abs() >= 0.001
但我不明白为什么这段代码会返回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());
}
}
答案 0 :(得分:3)
您的hashCode()
方法为ff==3.54
和ff==3.5405
提供了不同的结果,因此它们被分配到HashSet
的不同存储区,而您的equals
方法永远不会用于测试它们是否相等。
如果a.equals(b)
,a.hashCode()
必须等于b.hashCode()
。这是合同。
来自equals()
Javadoc:
请注意,通常需要在重写此方法时覆盖hashCode方法,以便维护hashCode方法的常规协定,该方法声明相等对象必须具有相等的哈希码。
答案 1 :(得分:1)
您实施的几乎等于的类型不符合Object's contract for equals,因为它不具有传递性。
考虑0,0.999和0.0018的情况。 Math.abs(0.0009 - 0)
与Math.abs(0.0018 - 0.009)
一样小于0.001,但Math.abs(0.0018 - 0)
大于0.001。
有一个几乎等于的方法,并在某些情况下使用它,但要使HashSet
和其他哈希结构有效,你需要equals
和hashCode
符合Object
合同。
如果唯一的原因是&#34;速度&#34;,摆脱并发症并使用Float
。
如果您还有其他原因需要在HashSet
中将不相等的浮点数组合在一起,有很多方法可以将它们划分为等价类,包括k5_'s answer中讨论的等价类。您还可以将其基于纯浮点运算,而无需提取和操作位模式。例如,将其基于除以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());
}
}
答案 2 :(得分:0)
如果你想为浮点数实现.equals()
/ .hashCode()
,一些浮点数是相等的。因此,您可以将自己的班级用于HashSet
或HashMap
。
这样做的一种方法是从Float.floatToInBits()
去除最后的&lt; 23位(当您删除不是十进制的二进制位置,以保留4个有效小数位,大约删除10个二进制位))。您可以在.equals()
和.hashCode()
实施中使用生成的int。
我没有用二进制进行数学运算,因此数字实际上并不正确(如果以十进制表示,则为例子)
此方法会产生有效的.equals()
/ .hashCode()
但不提供Math.abs()&lt;你想要的是0.001(在相同的情况下,abs会更高(!)更高,在某些情况下更低)。如果该属性对您更重要,请不要使用.equals()
/ .hashCode()
并创建自己的集合。