Как реализовать "быстрый обратный квадратный корень" в Java?
Я слышал о "быстром обратном квадратном корне", обсуждался здесь, и я хотел поместить его в свою программу на Java (только для исследовательских целей, поэтому игнорировать что-либо о том, что собственные библиотеки быстрее).
Я смотрел на код, а код C напрямую преобразовывал float
в int
с некоторой магией указателя на C. Если вы попытаетесь сделать это на Java с приведениями, это не сработает: java усекает float (как и следовало ожидать), и вы не можете получить указатель на примитив (как вы можете на C).
Итак, как вы это делаете?
Ответы
Ответ 1
Не забудьте проверить свой код перед использованием.
Если вам это не понадобится, или это медленнее на архитектуре процессора, которую вы используете, тогда вам лучше идти без этого тупого кода в вашем проекте.
В библиотеках Java есть способ получить от числа с плавающей точкой до необработанных битов.
Как видно из Javadoc для java.lang.Float
(http://docs.oracle.com/javase/6/docs/api/java/lang/Float.html), мы имеем функцию floatToIntBits
, а также intBitsToFloat
.
Это означает, что мы можем написать "быстрый обратный квадратный корень" в Java следующим образом:
public static float invSqrt(float x) {
float xhalf = 0.5f * x;
int i = Float.floatToIntBits(x);
i = 0x5f3759df - (i >> 1);
x = Float.intBitsToFloat(i);
x *= (1.5f - xhalf * x * x);
return x;
}
Вот версия для парных:
public static double invSqrt(double x) {
double xhalf = 0.5d * x;
long i = Double.doubleToLongBits(x);
i = 0x5fe6ec85e7de30daL - (i >> 1);
x = Double.longBitsToDouble(i);
x *= (1.5d - xhalf * x * x);
return x;
}
Источник: http://www.actionscript.org/forums/showthread.php3?t=142537
Ответ 2
Для ответа на Riking даже двойной может вернуть материал, например 0.9983227945440889, для квадратного корня из одного.
Чтобы повысить точность, вы можете использовать эту версию, которую я сделал:
public static double Q_rsqrt(double number){
double x = number;
double xhalf = 0.5d*x;
long i = Double.doubleToLongBits(x);
i = 0x5fe6ec85e7de30daL - (i>>1);
x = Double.longBitsToDouble(i);
for(int it = 0; it < 4; it++){
x = x*(1.5d - xhalf*x*x);
}
x *= number;
return x;
}
Вы можете отредактировать, как долго задолго до того, как цикл for завершится, но вы хотите, но 4 раза, похоже, довели его до максимальной точности для двойника. Если вам нужна совершенная точность (или длинные строки десятичных знаков, где они не должны вас беспокоить), используйте эту версию.