【问题标题】:Test Case failing when expected is equal to output预期失败时测试用例等于输出
【发布时间】:2014-03-14 18:03:16
【问题描述】:

在我详细介绍之前,是的,这是一项家庭作业。不,我不想要答案,只是提示和/或建议尝试这个或那个。

问题由此引入:

创建一个类 ExactNumber,它使用两个名为 left 的长属性 和右(代表左边的数字部分 和小数点右边)。例如,3.75 将 由 new ExactNumber(3, 7500000000000000L) 表示。注意 L 上 告诉 Java 大数的结尾是 long。这翻译 至:3 + 7500000000000000/10000000000000000 = 3.75

这是我的代码:

public class ExactNumber {
    private long left;
    private long right;

    public ExactNumber(long left, long right) {
        this.left = left;
        this.right = right;
    }

    public String toString() {
        return String.valueOf(doubleValue());
    }

    public double doubleValue() {
        return ((double) left +  (double) (right/ 100000000000000L) / 100);
    }

    public int compareTo (ExactNumber exactNumber) {
        if(exactNumber.left < left) {
            return 1;
        }
        else if (exactNumber.left == left) {
            if (exactNumber.right < right) {
                return 1;
            }
            else if (exactNumber.right == right) {
                return 0;
            }
            else {
                return -1;
            }
        }
        else {
            return -1;
        }
    }

    public boolean equal(ExactNumber thisobject) {
        if (thisobject instanceof ExactNumber) {
            if (thisobject.doubleValue() == this.doubleValue()) {
                return true;
            }
            else {
                return false;
            }
        }
        else {
            return false;
        }
    }

    public double add(ExactNumber exactNumber) {;
        return ((left+exactNumber.left) + (double)((right+exactNumber.right)*1E-16));
    }
}

我的问题是,当预期值等于实际值时,测试会出现错误。以下是测试用例(注意:还有更多测试用例,但它们通过了 JUnit 测试):

public class TestExactNumber extends TestCase {
    ExactNumber threesevenfive = new ExactNumber(3, 7500000000000000L);
    ExactNumber threesevenfive_andalittlebit = new ExactNumber(3, 7500000000000001L);
    ExactNumber threesevenfive_dupe = new ExactNumber(3, 7500000000000000L);
    ExactNumber ten = new ExactNumber(10, 0);
    ExactNumber thirteensevenfive = new ExactNumber(13, 7500000000000000L);
    ExactNumber sevenfifty = new ExactNumber(7, 5000000000000000L);

public void test_equals() {
        assertFalse(threesevenfive.equals(threesevenfive_andalittlebit));
        assertEquals(threesevenfive, threesevenfive_dupe);
    }

public void test_add() {
        assertEquals(threesevenfive.add(ten), thirteensevenfive);
        assertEquals(threesevenfive.add(threesevenfive), sevenfifty);

上面的 assertEquals 在 JUnit 测试中失败,但表示(例如)预期 = 13.75 和实际 = 13.75。

非常感谢任何关于我需要对我的代码做什么的提示或提示。并提前感谢您。

注意事项:

  • 根据我的导师的说法,我不应该使用 doubleValue 方法来实现我的 equals 方法。我知道我的代码中确实有它,但那是在教练给我的提示之前,我只是不确定如何更改它。

  • 我正在使用 eclipse for java 来编写代码。

【问题讨论】:

  • 如果您使用的是 Java 7,您可以在大数字中使用下划线以使其更具可读性。例如,100_000_000_000_000L

标签: java junit3


【解决方案1】:

您的equal 方法从未使用过。 assertEquals() 使用的 Java 方法称为 equalS(您必须将 override equals() 方法从 Object 派生出来)。 因此,断言将使用继承自 Object 的 equals,它将比较实际的 instances,而不是使用您的 equal 方法来比较对象值。而且由于它们是两个不同的实例,它们并不相等。

最后,这两个实例将用toString() 绘制,结果为expected = 13.75 and actual = 13.75.(因为你的 toString() 只返回值,忽略实例之间的差异)


您的导师回应: Java 中的 Long 是一个 64 位长的数字。 Java 中的 Double 是使用 IEEE754 标准实现的,它只为尾数留下 52 位。含义:长数字到双精度数的任何转换,其中长数字在位 53 到 63 上 设置位 - 将导致指数以某种方式移动,您会在 LSB 周围失去精度- 导致不精确的 Double 值。

因此,比较双精度值以确定相等性不足以满足您想要的“精确数字”设计。

例子:

Long bigLong = 1L<<51; //picked 51: 52 and 53 already causing rounding issues.
Long long1 = bigLong + 1L;
Long long2 = bigLong + 2L;
System.out.println(long1+" -> " + long1.doubleValue());
System.out.println(long2+" -> " + long2.doubleValue());

//false, enough precision to preserve bit "0" and "1".
System.out.println(long1.doubleValue()==long2.doubleValue()); 

输出:

2251799813685262 -> 2.251799813685262E15
2251799813685263 -> 2.251799813685263E15
false

设置第 54 位时:

Long bigLong = 1L<<54;
Long long1 = bigLong + 1L;
Long long2 = bigLong + 2L;
System.out.println(long1+" -> " + long1.doubleValue());
System.out.println(long2+" -> " + long2.doubleValue());
System.out.println(long1.doubleValue()==long2.doubleValue());

输出:

18014398509481985 -> 1.8014398509481984E16
18014398509481986 -> 1.8014398509481984E16
true

注意指数蜂从 15 增加到 16,这将切断两个 long 之间“1”的差异。

要解决这个问题,您可以将 left1left2 以及 right1right2 进行比较,而无需将其转换为双倍。

【讨论】:

  • 您可能还提到,如果您添加 @Override 注释,编译器可能会警告您您实际上并未覆盖超类的方法。
【解决方案2】:

您的 equal 方法应该理想地测试您的类中的每个必要值。在这种情况下,它应该检查两个对象之间的左右值是否相同。如果它们相同,则可以认为对象相等。

在您的情况下,您可能应该在您的 equals 方法中放置一个调试点,以查看该函数返回 false 的原因。

尝试使用 Eclipse 的内置功能为您创建 equals 和 hashcode 方法。您可以通过转到 Source->Generate hashCode() 和 equals() 来创建它。这些方法将与您创建的方法大不相同。

另外,在您的 AssertEquals 方法中,确保传入的两个值的类型相同。在您的情况下,您正在使用 ExactNumber 对象检查 Double 。他们肯定不会一样。你需要

  1. 更改您的 Add 方法以返回 ExactNumber 对象
  2. 在您的 ExactNumber 类中有一个名为 getDouble() 的方法,并将其用作第二个参数。

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-27
    • 2019-03-19
    • 1970-01-01
    • 2019-12-20
    • 2013-01-30
    • 2020-12-05
    相关资源
    最近更新 更多