编辑:起初我认为这可以使用javadoc的“结果必须是半单调的”要求来回答,但它实际上无法应用,所以我重写了答案。
我所能说的几乎所有内容都已经包含在dimo414的答案中。我只想补充一点:在同一平台上使用时,甚至在使用时,都没有正式的保证(从文档中) .当然,的实现实际上使用了 ,所以当值完全相同时,结果将是相等的(这里我合理地暗示函数是确定性的),但请记住这一点。Math.atan2
StrictMath.atan2
atan2(y, x) == atan2(y * k, x * k)
StrictMath
y / x
y / x
double
回答关于参数的部分:保持32位(实际上,更像是31位加一位符号),并且可以用类型表示而不会损失任何精度,因此没有新的问题。int
int
double
您在问题中描述的差异(对于非溢出值)是由将值转换为 时精度损失引起的,它与自身无关,甚至在调用函数之前就发生了。 type 只能包含 53 位尾数,但在您的情况下需要 54 位,因此它被舍入为最接近的数字 a 可以表示(不过没关系,它只需要 52 位):long
long
double
Math.atan2
double
a * k
double
b * k
long a = 959786689;
long b = 363236985;
long k = 9675271;
System.out.println(a * k);
System.out.println((double) (a * k));
System.out.println((long) (double) (a * k));
System.out.println((long) (double) (a * k) == a * k);
System.out.println(b * k);
System.out.println((double) (b * k));
System.out.println((long) (double) (b * k));
System.out.println((long) (double) (b * k) == b * k);
输出:
9286196318267719
9.28619631826772E15
9286196318267720
false
3514416267097935
3.514416267097935E15
3514416267097935
true
并解决注释中的示例:
我们有。在这种情况下,任何 、 、 都不能表示为不损失精度。我将用它来演示它,因为它可以显示的真实(未舍入)值:double a = 1.02551177480084, b = 1.12312341356234, k = 5;
a
b
a * k
b * k
double
BigDecimal
double
double a = 1.02551177480084;
System.out.println("a is " + new BigDecimal(a));
System.out.println("a * 5 is " + new BigDecimal(a * 5));
System.out.println("a * 5 should be " + new BigDecimal(a).multiply(new BigDecimal("5")));
输出
a is 1.0255117748008399924941613789997063577175140380859375
a * 5 is 5.12755887400420018451541182002983987331390380859375 // precision loss here
a * 5 should be 5.1275588740041999624708068949985317885875701904296875
并且可以清楚地看到差异(也可以用代替)b
a
有一个更简单的测试(因为本质上是使用):atan2()
a/b
double a = 1.02551177480084, b = 1.12312341356234, k = 5;
System.out.println(a / b == (a * k) / (b * k));
输出
false