是否可以为 Set<Double>.contains() 设置精度?

假设我们有一个Set<Double>. 它包含以下值:[2.0, 5.0, 7.0].

contains(2.0001d)在这种情况下返回,false因为double值是通过精确匹配进行比较的。

是否可以为boolean contains(Object o)方法设置一些双精度?

如果不可能,除了将值存储在顺序集合中,迭代它并比较每个值之外,您可以建议什么解决方法?


守着星空守着你
浏览 195回答 3
3回答

慕的地8271018

Set.contains 有一个基于平等的精确定义:&nbsp;更正式地说, true 当且仅当此集合包含一个元素 e 使得 (o==null ? e==null : o.equals(e))。它会违反合同的方法,它使用除平等以外的任何方法。并且相等有一个精确的定义,即它必须是可传递的(除其他属性外)。使用容差的相等方法不是可传递的。因此,没有办法Set.contains允许容差。然而,这并不是说你永远不应该检查一个集合是否包含某个值的容差范围内的值——只是不要试图重载contains这样做的概念。例如,您可以有一个采用 a NavigableSet(例如 a TreeSet)的subSet方法,并使用其方法:static boolean containsApprox(NavigableSet<Double> set, double target, double eps) {&nbsp; return !set.subSet(target - eps, true, target + eps, true).isEmpty();}这只是请求从target-eps到target+eps(包括true参数所指示的)运行的集合部分。如果这是非空的,则eps在target.这显然是一个独立于标准的概念Set.contains,因此可以执行不共享相同属性的包含检查。你不能subSet用 a做同样的把戏,HashMap因为它是一个无序映射 - 没有有效的方法来提取给定范围内的值。您将必须迭代整个集合,如Sun 的回答中所示,寻找匹配的值。

蝴蝶刀刀

可能您可以使用anyMatch,例如,根据后的前两位数字进行比较.:Set<Double> set = Set.of(2.0, 5.0, 7.0);Double compared = 2.0001d;System.out.println(&nbsp; &nbsp; &nbsp; &nbsp; set.stream().anyMatch(aDouble ->&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Math.floor(aDouble * 100) / 100 == Math.floor(compared * 100) / 100));

慕后森

我可以看到三个选项:在将数字添加到集合之前先对数字进行四舍五入编写一个double包装类并重新定义equals方法将 aTreeSet与自定义比较器一起使用请注意,最后两个选项可能令人满意,也可能不令人满意,因为您填充集合的顺序会影响保留哪些元素。例如,如果您将精度设置为 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) {&nbsp; return new TreeSet<> ((d1, d2) -> {&nbsp; &nbsp; if (d1 <= d2 - epsilon) return -1;&nbsp; &nbsp; if (d1 >= d2 + epsilon) return 1;&nbsp; &nbsp; return 0;&nbsp; });}使用示例: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]
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java