在我进入细节之前,是的,这是一个家庭作业。不,我不想要答案,只是提示和/或建议,尝试这个或那个。
问题由此产生:
下面是我的代码:创建一个类ExactNumber,它使用两个名为left的长属性右边(表示数字在左边的部分和小数点右边)。例如,3.75用new ExactNumber(3,7500000000000000l)表示。注意上面的L它告诉Java大数是一个长。这就意味着To: 3 + 750000000000000/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测试中失败,但表示(例如)expected = 13.75 and actual = 13.75。
任何提示或提示,我需要做我的代码是非常感谢。提前谢谢你。
指出:
根据我的导师,我不应该使用doubleValue方法来实现我的equals方法。我知道我的代码中确实有它,但那是在教练给我的提示之前,我只是不确定如何更改它。
我正在使用eclipse for java编写此代码。
您的equal
方法从未使用过。assertEquals()
使用的Java方法称为equalS
(您必须使用从Object
派生的equals()
方法override
)。因此,断言将使用从Object继承的equals
,它将比较实际的instances
,而不是使用您的equal
方法来比较对象值。因为它们是两个不同的实例,所以它们不相等。
最后,用toString()
绘制两个实例,得到expected = 13.75 and actual = 13.75.
(因为您的toString()只返回值,忽略实例之间的差异)
你的导师回应:Java中的Long是64位长的数字。Java中的Double是通过IEEE754标准实现的,它只给尾数留下52位。含义:任何长数到双精度数的转换,如果长数在53位到63位上有设置位,将导致指数以某种方式移位,从而在lsb周围失去精度-导致不精确的双精度值。
因此,比较双精度值以确定相等性对于您期望的"精确数字"设计是不够的。
的例子:
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,这将切断两个长数之间的"1"之差。
要解决这个问题,可以将left1与left2进行比较,将right1与right2进行比较,而无需将其转换为双精度类型。
理想情况下,equal方法应该测试类中的每个必要值。在这种情况下,它应该检查两个对象之间的左值和右值是否相同。如果它们是相同的,那么你可以认为这两个对象是相等的。
在你的例子中,你可能应该在你的equals方法中放置一个调试点,看看为什么函数返回false。
尝试使用Eclipse的内置功能为您创建equals和hashcode方法。您可以通过Source->Generate hashCode()和equals()来创建它。这些方法将与您创建的方法非常不同。
另一件事,在你的AssertEquals方法中,确保传入的两个值是相同类型的。在您的例子中,您正在使用ExactNumber对象检查Double。它们肯定不会是一样的。您需要
- 改变你的Add方法返回一个ExactNumber对象
- 在你的ExactNumber类中有一个叫做getDouble()的方法,并使用它作为第二个参数。