This question already has answers here:
“Comparison method violates its general contract!”

(11个答案)


4年前关闭。




我一直在努力解决这个问题,但没有设法做到这一点。

简而言之,我编写了一个蜂巢算法,其中的一种预突变是按与已排序块之前的点的距离对点块进行排序。

此排列使用比较器

public class PointDistanceComparator implements Comparator {

    @Override
    public int compare(Object arg0, Object arg1) {
        double resultDouble = ((Point) arg1).getSortUsageDistance()-((Point) arg0).getSortUsageDistance();
        if(resultDouble>0){
            return 1;
        }
        else if(resultDouble==0){
            return 0;
        }
        else{
            return -1;
        }
    }

}


我计算块中每个点到上一个点的距离:

List<Point> pointsVector = new ArrayList<Point>();
double distance = 0;
Point point2 = pointsToVisit.get(visitedPoints.get(visitedPointsPossibleInputStartingIndex));
for(int k = visitedPointsPossibleInputStartingIndex+1; k < visitedPointsPossibleInputEndingIndex; k++){
    Point point = pointsToVisit.get(visitedPoints.get(k));
    distance = Utils.getDistanceKm(point2, point);
    point.setSortUsageDistance(distance);
    pointsVector.add(point);
}


我尝试对其进行排序:

try{
    PointDistanceComparator pdComparator = new PointDistanceComparator();
    pointsVector.sort(pdComparator);
    int pointsVectorIndex = 0;
    for(int k = visitedPointsPossibleInputStartingIndex+1; k < visitedPointsPossibleInputEndingIndex; k++){
        visitedPoints.set(k, pointsVector.get(pointsVectorIndex).getIndex());
        pointsVectorIndex++;
    }
}
catch(Exception e){
    System.out.println("Unsortable route: ");
    for(Point point : pointsVector){
        System.out.println(point.getSortUsageDistance());
    }
    e.printStackTrace();
}


我得到的结果(针对高分)是:

Unsortable route:
2.409437209114269
4.195074884990501
0.9691536825922977
1.1818593906071124
3.7959341231055044
1.344833460712328
2.7808472396551256
2.3341362332820377
3.0826195327369685
5.981871507031457
4.096491609253349
2.6730445628945447
3.6026805136626736
5.070192970603796
6.525798962460061
2.437658869598336
2.3249264696009666
2.22717482314044
1.3205919751367337
1.4326093612218957
5.032187900596256
2.6186056819000028
3.715867402052429
2.905908208286016
1.25868451375791
1.5362377319604628
3.4961506217046376
2.961495413336175
1.9345437912998407
4.49333274460376
3.2997943500252442
4.5252963191878175
5.336224710120464


哪怕是excel也可以很好地排序(需要将。交换为)。

堆栈跟踪:

java.lang.IllegalArgumentException: Comparison method violates its general contract!
    at java.util.TimSort.mergeHi(Unknown Source)
    at java.util.TimSort.mergeAt(Unknown Source)
    at java.util.TimSort.mergeCollapse(Unknown Source)
    at java.util.TimSort.sort(Unknown Source)
    at java.util.Arrays.sort(Unknown Source)
    at java.util.ArrayList.sort(Unknown Source)
    at beeAlgorithm.BeeHive.sortBlockByDistanceToPrecedingPoint(BeeHive.java:334)
    at beeAlgorithm.BeeHive.permuteRoute(BeeHive.java:172)
    at beeAlgorithm.BeeHive.searchRouteNeighbourhood(BeeHive.java:144)
    at beeAlgorithm.BeeHive.iterateOverRoute(BeeHive.java:130)
    at beeAlgorithm.BeeHive.iterateOverAllRoutes(BeeHive.java:123)
    at beeAlgorithmAgents.BeeHiveAgent$1.action(BeeHiveAgent.java:114)
    at jade.core.behaviours.Behaviour.actionWrapper(Behaviour.java:344)
    at jade.core.Agent$ActiveLifeCycle.execute(Agent.java:1552)
    at jade.core.Agent.run(Agent.java:1491)
    at java.lang.Thread.run(Unknown Source)


它在多线程环境(JADE代理)上运行。

似乎我的compare方法有一个漏洞,但我只是找不到。有什么线索吗?

编辑(固定):

问题似乎是生成我的积分列表。关于它为什么不起作用,我没有任何线索:

    List<Point> points = new ArrayList<Point>();
    for(int l = 0; l < algInputParameters.getPointsAmount(); l++){
        Point point = null;
        if(l == 0){
            point = new Point(0, 24*1024, 0, 0, 0, 0, 0);
            if(algInputParameters.isCityCiechanow()){
                point.generatePositionForCiechanow(random);
            }
            else if(algInputParameters.isCityTorun()){
                point.generatePositionForTorun(random);
            }
            else{
                point.generatePositionForWarsaw(random);
            }
        }
        else{
            point = new Point(0, 0, l, visitTime, 0, 0, 0);
            point.generateHours(random, startHour, endHour, duration);
            if(algInputParameters.isCityCiechanow()){
                point.generatePositionForCiechanow(random);
            }
            else if(algInputParameters.isCityTorun()){
                point.generatePositionForTorun(random);
            }
            else{
                point.generatePositionForWarsaw(random);
            }
        }
        points.add(point);
    }


但曾与:

    List<Point> points = new ArrayList<Point>();
    for(int l = 0; l <algInputParameters.getBeeAmount(); l++){
        if(l == 0){
            Point point = new Point(0, 24*1024, 0, 0, 0, 0, 0);
            if(algInputParameters.isCityCiechanow()){
                point.generatePositionForCiechanow(random);
            }
            else if(algInputParameters.isCityTorun()){
                point.generatePositionForTorun(random);
            }
            else if(algInputParameters.isCityWarszawa()){
                point.generatePositionForWarsaw(random);
            }
            points.add(point);
        }
        else{
            Point point = new Point(0, 0, l, visitTime, 0, 0, 0);
            point.generateHours(random, startHour, endHour, duration);
            if(algInputParameters.isCityCiechanow()){
                point.generatePositionForCiechanow(random);
            }
            else if(algInputParameters.isCityTorun()){
                point.generatePositionForTorun(random);
            }
            else if(algInputParameters.isCityWarszawa()){
                point.generatePositionForWarsaw(random);
            }
            points.add(point);
        }
    }


老实说,没有一个主意。创建Points池时没有并发性,即使Point保持为“ null”,我也会更快地得到null指针异常。也许有些人会遇到同样的问题,只是将其留在这里。

接受使用BigDecimal用法的答案,因为它很可能回答将来可能出现的任何搜索

最佳答案

根据java.util.Comparator的Javadoc,比较器的常规协定如下:


从比较合同中可以立即得出,商是S上的等价关系,而施加的排序是S上的总阶。当我们说c施加在S上的排序与equals一致时,表示排序的商是由对象的equals(Object)方法定义的等价关系


表示如果x.compare(y) == 0则必须为x.equals(y) == true

从比较器看来,您进行了double数据类型减法,并将该值与0进行了比较,而众所周知,double的缺点是精度有限。对double进行数学运算可能会导致精度损失,使看上去相等的2 double实际上不是。这个link确切地表明了我的意思。

另一个好的摘录如下:

System.out.println( 0.1f + 0.1f + 0.1f + 0.1f + 0.1f + 0.1f + 0.1f + 0.1f + 0.1f + 0.1f );
System.out.println( 0.1d + 0.1d + 0.1d + 0.1d + 0.1d + 0.1d + 0.1d + 0.1d + 0.1d + 0.1d );

1.0000001
0.9999999999999999


十次加0.1,您期望精确到1(一)。但是你不是。

我建议您在需要适当比较时使用BigDecimal

10-05 20:24
查看更多