public String toString() {
final String IMAGINARY_UNIT = "i";
if (equalsApprox(im , 0)) {
return String.valueOf(re);
}
String sign = "-";
if (im > 0) {
sign = "+";
}
if(equalsApprox(re, 0)) {
return "MyComplex" + sign + IMAGINARY_UNIT + Math.abs(im);
}
return "MyComplex" + re + " " + sign + IMAGINARY_UNIT + Math.abs(im);
}
public boolean equalsApprox(MyComplex z) {
return equalsApprox(re, z.re) && equalsApprox(im, z.im);
}
private static boolean equalsApprox(double x , double y) {
final double EPSILON = 1E-14;
return Math.abs(x-y) <= EPSILON * Math.max(Math.abs(x), Math.abs(y));
}
我想清楚地解释equalsApprox的部分,我不明白它是如何检查和比较公差的(我不知道公差在这里是什么意思:请解释我这也)和返回值在不同的条件下。这是结束部分的代码,而不是全部。请帮助我理解它。
1条答案
按热度按时间c6ubokkw1#
要完全理解它,它会变得有点复杂!
电脑并不神奇存储的数字“大小”是有限制的。例如,
int
只能存储-2147483648到+2147483647之间的数字(试试看!)这些数字不是任意的,对于正数和负数都是2^31
(2的31次幂-2*2*2*2*...
),因为int使用32位,一位表示符号,31位表示数字。double
也有类似的限制,它使用64位,但仍然有限制,只能存储2^64个不同的数字。(为什么?数学-如果我给予你3个电灯开关,你能和我交流的唯一方式就是拨动它们,然后离开房间,你最多只能给我发8条不同的信息。那是因为2^3 = 8
。有64个灯开关就是2^64
。那是很多数字,但是在0和1之间存在无限数量的数,更不用说所有的无穷数了)。那么,既然double只能存储2^64个唯一的数字,那么double可以存储哪些数字呢?就好像有人在数字线上投了2^64个 dart --这些数字是double可以存储的。还有什么是double不能存储的呢?如果您尝试这样做,或者计算的结果是一个没有“dart”的值,它会自动四舍五入到最近的dart。
dart 不是随意扔的如果你想象一下数轴,0-2之间的 dart 和其他地方的 dart 一样多--越接近1.0, dart 就越密集。最终,在2^52以上,每个整数只有不到一个 dart (具有
x+1
可以等于x
的奇怪效果,对于足够大的x
,偶数!-结果被四舍五入到最接近的省道,其最终再次仅为x
)。这意味着会出现错误,数字越大,错误可能越大。这意味着等式会变得复杂。简单的例子:
差值(最后一行)打印出
-1.1102230246251565E-16
--所以这是一个非常微小的差值(E-16表示10^-16,所以,差值是-0.0000000000000000000000000000000011102230246251565)。但是.. 10 * 0.1是1.0,那么为什么打印出来是假的呢?因为 dart 的事情-四舍五入杀了你。计算机是用二进制计数的;而“十分之一”在十进制中工作良好(只有0.1),就像“三分之一”在十进制中不“工作”一样(它是0.333333333......你永远不可能得到完美的),十分之一在二进制中同样不是很完美,因此,是的,0.1在dart上不是很完美,每个中间值(0.1,0.2,0.3)也不是 dart ,所以要不断地复合10个微小的舍入误差。
解决方案是,当想要考虑两个double值是否“相等”时,不能只使用
==
,而是需要将其定义为“它们真的彼此接近吗?"因此,此代码检查差异(
Math.abs(x-y)
就是x-y
,去掉了符号:x和y之间的差值,并检查它是否真的很小。有多小?嗯,在basis中,EPSILON(1E-14
,这是一种科学记数法,意思是-0.00000000000001),除了,我们稍微缩放一下(乘以x和y中最大的值),因为当你远离0时,误差往往会更大,因为当你离它越来越远的时候 dart 会越来越少。将其应用于我们的
0.1*10 vs 1.0
情况:最后一行打印
true
。