代码之家  ›  专栏  ›  技术社区  ›  Tom Hawtin - tackline

为什么我的简单比较器坏了?

  •  17
  • Tom Hawtin - tackline  · 技术社区  · 17 年前

    我有一门课,我把它简化为:

    final class Thing {
        private final int value;
        public Thing(int value) {
            this.value = value;
        }
        public int getValue() {
            return value;
        }
        @Override public String toString() {
            return Integer.toString(value);
        }
    }
    

    我想对这东西进行排序。所以我创造了一个简单的直升机:

    private static final Comparator<Thing> reverse = new Comparator<Thing>() {
        public int compare(Thing a, Thing b) {
            return a.getValue() - b.getValue();
        }
    };
    

    然后我用两个论点的形式 Arrays.sort .

    对于我的测试用例来说,这很好,但是有时候数组以一种奇怪但可重复的顺序结束时,它会出错。 怎么会这样?

    6 回复  |  直到 10 年前
        1
  •  20
  •   erickson    17 年前

    整数溢出…或者更准确地说,下溢。

    相反,做一个明确的比较:

    private static final Comparator<Thing> reverse = new Comparator<Thing>() {
        public int compare(Thing a, Thing b) {
          int av = a.getValue(), bv = b.getValue();
          return (av == bv) ? 0 : ((av < bv) ? -1 : +1);
        }
    };
    

    如果你确信两者之间的差异不会“环绕”,那么使用减法就可以了。例如,当相关值被约束为非负值时。

        2
  •  15
  •   Jason Cohen    17 年前

    不能使用减号创建比较。当绝对差超过 Integer.MAX_VALUE .

    相反,使用以下算法:

    int compareInts( int x, int y ) {
      if ( x < y ) return -1;
      if ( x > y ) return 1;
      return 0;
    }
    

    我喜欢在图书馆里这样做。

        3
  •  5
  •   Peter Lawrey    17 年前

    尝试

    System.out.println(Integer.MAX_Value - Integer.MIN_VALUE);
    

    这需要返回一个正数作为max_value>min_value,但会打印-1

        4
  •  4
  •   mustpax    17 年前

    当比较Java原语时,建议将它们转换为对象对应并依赖它们。 compareTo() 方法。

    在这种情况下,您可以执行以下操作:

    return Integer.valueOf(a.getValue()).compareTo(b.getValue())
    

    如果有疑问,请使用经过良好测试的库。

        5
  •  2
  •   Uri    17 年前

    你在那里投了什么样的数字?如果你的数字足够大,你可以把整数的最小值/最大值包装起来,结果会变得一团糟。

        6
  •  1
  •   MarkusQ    17 年前

    如果A的值是非常负值,而B的值是非常正值,那么您的回答将是非常错误的。

    iirc,int溢出在jvm中安静地环绕

    ——MarkusQ