假设我们有Set<Double>
的实现。它包含以下值:[2.0, 5.0, 7.0]
。
contains(2.0001d)
在这种情况下返回false
,因为double
的值是通过完全匹配进行比较的。
是否可以为boolean contains(Object o)
方法设置一些双精度?
如果不可能,除了将值存储在顺序集合中,对其进行迭代并比较每个值之外,您建议什么解决方法?
答案 0 :(得分:6)
Set.contains
有一个基于等式的精确定义:
更正式地讲,当且仅当该集合包含元素
true
时返回(o==null ? e==null : o.equals(e))
。
它使用除平等之外的任何东西都违反了该方法的契约。平等有一个精确的定义,说它必须是可传递的(在其他属性中)。使用容差的相等方法不是可传递的。
因此,Set.contains
无法允许公差。
但是,这并不是说您不应该检查集合中是否包含某个值的公差范围内的值-请勿尝试超载contains
的概念来做到这一点
例如,您可以有一个采用NavigableSet
(例如TreeSet
)并使用其subSet
method的方法:
static boolean containsApprox(NavigableSet<Double> set, double target, double eps) {
return !set.subSet(target - eps, true, target + eps, true).isEmpty();
}
这仅请求集合中从target-eps
到target+eps
(包括true
参数所指示)的部分。如果这是非空的,则eps
的{{1}}中的集合中有一个值。
这显然是与标准target
分开的概念,因此可以执行包含不共享相同属性的包含检查。
您无法对Set.contains
进行同样的subSet
技巧,因为它是无序映射-没有有效的方法来提取给定范围内的值。您必须像Sun's answer中那样遍历整个集合,以寻找匹配的值。
答案 1 :(得分:3)
例如,可以使用anyMatch
,根据.
之后的前两位进行比较:
Set<Double> set = Set.of(2.0, 5.0, 7.0);
Double compared = 2.0001d;
System.out.println(
set.stream().anyMatch(aDouble ->
Math.floor(aDouble * 100) / 100 == Math.floor(compared * 100) / 100
));
答案 2 :(得分:2)
我可以看到三个选项:
double
包装类并重新定义equals方法TreeSet
和自定义比较器请注意,从填充集合的顺序会影响保留元素的角度来看,后两个选项可能令人满意,也可能不令人满意。例如,如果将精度设置为0.01,然后再加上0.01,然后再加上0.011,然后再加上0.02,则该组中将有两个元素(0.01和0.02)。如果先加上0.011,再加上0.01,然后再加上0.02,那么您将只有一个元素:0.011。我不知道您的用例是否有问题。
最后一个选项可能看起来像这样:
static Set<Double> setWithPrecision(double epsilon) {
return new TreeSet<> ((d1, d2) -> {
if (d1 <= d2 - epsilon) return -1;
if (d1 >= d2 + epsilon) return 1;
return 0;
});
}
示例用法:
Set<Double> set = setWithPrecision(0.01);
set.add(0d);
set.add(0.00001d);
set.add(0.01d);
set.add(0.02d);
System.out.println(set); // [0.0, 0.01, 0.02]
答案 3 :(得分:0)
假设您的HashSet#contains
调用点在某种程度上可以从某个地方接收到Double
的方法中,则可以简单地设置Double
的精度。尽管Double
不提供开箱即用的Double
对象四舍五入的方式,但是您可以很好地创建一个四舍五入的助手,该助手将接受您想要达到的精度并返回四舍五入的数字。>
例如:
public static Double roundToPrecision(Double number, int precision) {
return BigDecimal.valueOf(number)
.setScale(precision, RoundingMode.DOWN)
.doubleValue();
}
传递2.0001d
会有效地导致这一过程转向2.0
。