Ответ 1
Изменить: сначала я подумал, что на это можно ответить, используя требование "результаты должны быть полумонотонными" из javadoc, но на самом деле это невозможно применить, поэтому я повторно написал ответ.
Почти все, что я могу сказать, уже покрыто dimo414 answer. Я просто хочу добавить: при использовании Math.atan2
на той же платформе или даже при использовании StrictMath.atan2
формальной гарантии (из документации) нет atan2(y, x) == atan2(y * k, x * k)
. Конечно, реализация StrictMath
фактически использует y / x
, поэтому, когда y / x
является точно таким же значением double
, результаты будут равны (здесь я разумно подразумеваю, что функция детерминирована), но помните об этом.
Ответ на эту часть параметров int
: int
содержит 32 бита (фактически, более 31 бит плюс один бит для знака) и может быть представлен типом double
без потери точности, поэтому никаких новых проблем есть.
И разница, которую вы описали в вопросе (для значений, не переполняющих long
), вызвана потерей точности при преобразовании значений long
в double
, она не имеет ничего общего с Math.atan2
и это происходит до того, как функция будет даже вызвана. double
type может удерживать только 53 бит мантиссы, но в вашем случае a * k
требуется 54 бит, поэтому округляется до ближайшего число a double
может представлять (b * k
в порядке, хотя для этого требуется всего 52 бита):
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
И чтобы обратиться к примеру из comment:
Имеем 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