JAVA 比较器抛出错误(多线程执行)

JAVA Comparator throws error (multithreaded execution)

我一直在努力解决这个问题,但一直没成功。

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

这个排列使用比较器

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.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 代理)上 运行。

好像我的比较方法有漏洞,但我就是找不到。有什么线索吗?

编辑(固定):

似乎生成我的积分列表是问题所在。我不知道为什么它不起作用:

    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);
        }
    }

老实说,没有一个想法。创建点池时没有并发,尽管即使点保持 "null",我也会更快得到空指针异常。或许有人会遇到同样的问题,就放在这里吧。

接受了使用 BigDecimal 的答案,因为它最有可能回答任何可能的未来搜索

来自java.util.Comparator的Javadoc,比较器的一般契约如下:

It follows immediately from the contract for compare that the quotient is an equivalence relation on S, and that the imposed ordering is a total order on S. When we say that the ordering imposed by c on S is consistent with equals, we mean that the quotient for the ordering is the equivalence relation defined by the objects' equals(Object) method(s)

表示如果x.compare(y) == 0那么一定是x.equals(y) == true

从您的比较器看来,您执行了 double 数据类型减法并将该值与 0 进行比较,而众所周知,double 的弱点是精度有限。对 double 的数学运算会导致精度损失,使两个看似相等的 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