草庐IT

java - 由于数值精度错误而违反 compareTo 传递契约的影响

coder 2024-03-29 原文

我有一些数字要比较。它们代表通过不同空间的路径长度。

对我来说不幸的是,一些不精确导致了错误的比较。例如,在注意到错误的效果后,我发现我在进行这样的比较:

a = 384.527100541296
b = 384.52710054129614 // Note the trailing 14 

为了我的目的,a 和 b 应该是相等的。

我注意到 guava 有一个用于 double 的 fuzzyCompare() 方法,它似乎做了我想做的,忽略了一些这种精度:

private static final double COMPARISON_PRECISION=1e-10;

private static final Comparator<Double> fuzzyCompare= new Comparator<Double>(){
    public int compare(Double o1, Double o2) {
        return DoubleMath.fuzzyCompare(o1, o2, COMPARISON_PRECISION);
    }   
};

public int compareTo(Object o) {
    if (o instanceof Spam) {
       Spam other = (Spam) (o);
       return ComparisonChain.start()
       .compare(this.getLength(),other.getLength(),fuzzyCompare)
       //...
       .result();
    } else {
       throw new ClassCastException();
    }
}

关于模糊比较的警告并没有引起我的注意:

This is not a total ordering and is not suitable for use in Comparable.compareTo(T) implementations. In particular, it is not transitive

我的问题是,传递性的缺乏是一个真正的问题吗?如果是,它将如何呈现自己?我认为,如果比较确实被违反,它会抛出类似于 this question: Java error: Comparison method violates its general contract 的错误,并且即使针对我测试过的各种值,它也不会这样做。

或者也许因为 IllegalArgumentException 是一个运行时错误,我只是还没有遇到问题,因为只有一些不正当的值才会触发问题?

或者也许它现在做错了什么,只是非常微妙以至于我没有注意到它?

最佳答案

长话短说:

您的运算符不可传递。考虑 a = 0 , b = 0.6 , c = 1.2公差为 1 . a==b , b==c但是a!=c .解决方案是将您的值划分为类(例如通过舍入或截断)并使用 Double.compare()以保持传递性。

详细解释:

首先让我们讨论在使用 fuzzyCompare(double, double, double) 时您的数据是否可传递:

虽然在大多数情况下您的数据将是可传递的,但可以生成不是可传递的样本。让我们采用以下值:

a = 384.52710054120
b = 384.52710054126
c = 384.52710054132

如您所见,使用我们的新指标,以下内容为真:a==b , b==c ,但是a!=c .可以看到,你违反了transitivity .

如果您的 Comparator 有问题吗?是不可传递的?

方法通过使用文档和/或注释来声明某些条件。 compare方法 promise 该方法是可传递的。在传递性不重要的情况下,违反该 promise 可能没问题,但依赖于该 promise 的代码可能会被破坏。

如果传递性的 promise 被破坏,可能无法运行的代码示例是什么?

让我们创建一个场景,其中我们有 3 个类型为 Foo 的元素根据一些 Comparator 是不可传递的称为 fooComparator .我们称它们为f1 , f2f3 .

Comparator<Foo> fooComparator = new Comparator<Foo>(){
    public int compare(Foo o1, Foo o2) {
        // some non-transitive return value
    }   
};

由于它们不可传递,我们假设 f0 <>f1 , f1 <>f2 , f2 <>f0成立。 如果你把它们放在一个列表中并尝试 sort() 会发生什么?他们?

List<Foo> foos = new LinkedList<>();
Collections.addAll(f1, f2, f3)
Collections.sort(foos, fooComparator);

如何解决问题

您可以通过将数据映射到另一个数据集并使用在该数据集上定义的传递运算符来创建传递运算符。让我们将实数映射到精度较低的实数。

考虑以下值:

a = 0.01; b = 0.05; c = 0.13; d = 0.19; e = 0.21

如果将它们截断到第二位 ( Math.truncate(x * 10)/10 ) 并使用 Double.compare() , 传递性被保留。

你可以看到我们已经将我们的值分为三类{a, b} < {c, d} < {e} .肯定有一些重要的定理证明是这样的,但我不记得它的名字了..

关于java - 由于数值精度错误而违反 compareTo 传递契约的影响,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47018744/

有关java - 由于数值精度错误而违反 compareTo 传递契约的影响的更多相关文章

  1. ruby-on-rails - 由于 "wkhtmltopdf",PDFKIT 显然无法正常工作 - 2

    我在从html页面生成PDF时遇到问题。我正在使用PDFkit。在安装它的过程中,我注意到我需要wkhtmltopdf。所以我也安装了它。我做了PDFkit的文档所说的一切......现在我在尝试加载PDF时遇到了这个错误。这里是错误:commandfailed:"/usr/local/bin/wkhtmltopdf""--margin-right""0.75in""--page-size""Letter""--margin-top""0.75in""--margin-bottom""0.75in""--encoding""UTF-8""--margin-left""0.75in""-

  2. ruby-on-rails - 如果为空或不验证数值,则使属性默认为 0 - 2

    我希望我的UserPrice模型的属性在它们为空或不验证数值时默认为0。这些属性是tax_rate、shipping_cost和price。classCreateUserPrices8,:scale=>2t.decimal:tax_rate,:precision=>8,:scale=>2t.decimal:shipping_cost,:precision=>8,:scale=>2endendend起初,我将所有3列的:default=>0放在表格中,但我不想要这样,因为它已经填充了字段,我想使用占位符。这是我的UserPrice模型:classUserPrice回答before_val

  3. java - 等价于 Java 中的 Ruby Hash - 2

    我真的很习惯使用Ruby编写以下代码:my_hash={}my_hash['test']=1Java中对应的数据结构是什么? 最佳答案 HashMapmap=newHashMap();map.put("test",1);我假设? 关于java-等价于Java中的RubyHash,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.com/questions/22737685/

  4. ruby - rails 3 redirect_to 将参数传递给命名路由 - 2

    我没有找到太多关于如何执行此操作的信息,尽管有很多关于如何使用像这样的redirect_to将参数传递给重定向的建议:action=>'something',:controller=>'something'在我的应用程序中,我在路由文件中有以下内容match'profile'=>'User#show'我的表演Action是这样的defshow@user=User.find(params[:user])@title=@user.first_nameend重定向发生在同一个用户Controller中,就像这样defregister@title="Registration"@user=Use

  5. java - 从 JRuby 调用 Java 类的问题 - 2

    我正在尝试使用boilerpipe来自JRuby。我看过guide从JRuby调用Java,并成功地将它与另一个Java包一起使用,但无法弄清楚为什么同样的东西不能用于boilerpipe。我正在尝试基本上从JRuby中执行与此Java等效的操作:URLurl=newURL("http://www.example.com/some-location/index.html");Stringtext=ArticleExtractor.INSTANCE.getText(url);在JRuby中试过这个:require'java'url=java.net.URL.new("http://www

  6. ruby-on-rails - 如何生成传递一些自定义参数的 `link_to` URL? - 2

    我正在使用RubyonRails3.0.9,我想生成一个传递一些自定义参数的link_toURL。也就是说,有一个articles_path(www.my_web_site_name.com/articles)我想生成如下内容:link_to'Samplelinktitle',...#HereIshouldimplementthecode#=>'http://www.my_web_site_name.com/articles?param1=value1¶m2=value2&...我如何编写link_to语句“alàRubyonRailsWay”以实现该目的?如果我想通过传递一些

  7. ruby-on-rails - 添加回形针新样式不影响旧上传的图像 - 2

    我有带有Logo图像的公司模型has_attached_file:logo我用他们的Logo创建了许多公司。现在,我需要添加新样式has_attached_file:logo,:styles=>{:small=>"30x15>",:medium=>"155x85>"}我是否应该重新上传所有旧数据以重新生成新样式?我不这么认为……或者有什么rake任务可以重新生成样式吗? 最佳答案 参见Thumbnail-Generation.如果rake任务不适合你,你应该能够在控制台中使用一个片段来调用重新处理!关于相关公司

  8. java - 我的模型类或其他类中应该有逻辑吗 - 2

    我只想对我一直在思考的这个问题有其他意见,例如我有classuser_controller和classuserclassUserattr_accessor:name,:usernameendclassUserController//dosomethingaboutanythingaboutusersend问题是我的User类中是否应该有逻辑user=User.newuser.do_something(user1)oritshouldbeuser_controller=UserController.newuser_controller.do_something(user1,user2)我

  9. java - 什么相当于 ruby​​ 的 rack 或 python 的 Java wsgi? - 2

    什么是ruby​​的rack或python的Java的wsgi?还有一个路由库。 最佳答案 来自Python标准PEP333:Bycontrast,althoughJavahasjustasmanywebapplicationframeworksavailable,Java's"servlet"APImakesitpossibleforapplicationswrittenwithanyJavawebapplicationframeworktoruninanywebserverthatsupportstheservletAPI.ht

  10. ruby - 在 Ruby 中按名称传递函数 - 2

    如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只

随机推荐