Java简单复数类

b09cbbtk  于 2023-01-07  发布在  Java
关注(0)|答案(1)|浏览(172)
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的部分,我不明白它是如何检查和比较公差的(我不知道公差在这里是什么意思:请解释我这也)和返回值在不同的条件下。这是结束部分的代码,而不是全部。请帮助我理解它。

c6ubokkw

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)。
这意味着会出现错误,数字越大,错误可能越大。这意味着等式会变得复杂。简单的例子:

double x = 0.0;
for (int i = 0; i < 10; i++) x += 0.1;
double y = 1.0;
System.out.println(x == y); // This prints false!!!
System.out.println(x - y);

差值(最后一行)打印出-1.1102230246251565E-16--所以这是一个非常微小的差值(E-16表示10^-16,所以,差值是-0.0000000000000000000000000000000011102230246251565)。
但是.. 10 * 0.11.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情况:

double x = 0.0;
for (int i = 0; i < 10; i++) x += 0.1;
double y = 1.0;
System.out.println(x == y); // This prints false!!!
double EPSILON = 1E-14;
System.out.println(Math.abs(x-y) <= EPSILON * Math.max(Math.abs(x),
Math.abs(y)));

最后一行打印true

相关问题