Нужна помощь в переводе кода с C на Java - PullRequest
1 голос
/ 11 мая 2010

С этой статьи. Вот код:

float InvSqrt(float x){ // line 0
   float xhalf = 0.5f * x;
   int i = *(int*)&x; // store floating-point bits in integer
   i = 0x5f3759d5 - (i >> 1); // initial guess for Newton's method
   x = *(float*)&i; // convert new bits into float
   x = x*(1.5f - xhalf*x*x); // One round of Newton's method
   return x;
}

... Я даже не могу сказать, это C или C ++. [хорошо, очевидно, это C, спасибо] Может кто-нибудь перевести это на Java для меня, пожалуйста? Меня сбивают с толку только 2 и 4 строки.

Ответы [ 5 ]

10 голосов
/ 11 мая 2010

Вы хотите использовать эти методы:

И могут быть проблемы с strictfp и т. Д.

Это примерно так: (ВНИМАНИЕ: это не проверено!)

float InvSqrt(float x){ // line 0
   float xhalf = 0.5f * x;
   int i = Float.floatToIntBits(x); // store floating-point bits in integer
   i = 0x5f3759d5 - (i >> 1); // initial guess for Newton's method
   x = Float.intBitsToFloat(i); // convert new bits into float
   x = x*(1.5f - xhalf*x*x); // One round of Newton's method
   return x;
}
7 голосов
/ 11 мая 2010

Эти строки используются для преобразования между float и int в виде битовых комбинаций. В Java есть статические методы в java.lang.Float для этого - все остальное идентично.

static float InvSqrt(float x) { // line 0
    float xhalf = 0.5f * x;
    int i = Float.floatToIntBits(x); // store floating-point bits in integer
    i = 0x5f3759d5 - (i >> 1); // initial guess for Newton's method
    x = Float.intBitsToFloat(i); // convert new bits into float
    x = x * (1.5f - xhalf * x * x); // One round of Newton's method
    return x;
}
2 голосов
/ 11 мая 2010

Код, который вы цитируете, - C, хотя комментарии в стиле C ++.

То, что делает код, включает знание того, как хранятся значения с плавающей запятой на уровне битов. «Магическое число» 0x5f3759d5 связано с определенным значением.

Доступ к битам значения с плавающей запятой x осуществляется при инициализации i, поскольку адрес x разыменовывается. Итак, i загружается с первыми 32 битами значения с плавающей запятой. На следующей строке записывается x с содержанием i, обновляющим значение рабочего приближения.

Я читал, что этот код стал популярным, когда Джон Кармак выпустил его с открытым движком Quake от Id. Целью кода является быстрый расчет 1 / Sqrt (x), который используется в вычислениях освещения графических движков.

Я бы не смог перевести этот код непосредственно в Java, потому что он использует «типизацию», как описано выше - когда он обращается к плавающей запятой в памяти, как если бы это был int. Java предотвращает подобные действия, но, как отмечали другие, объект Float предоставляет методы вокруг него.

Цель использования этой странной реализации в C была в том, чтобы она была очень быстрой. В то время, когда он был написан, я думаю, что этот метод значительно улучшился. Интересно, стоит ли разница сегодня, когда операции с плавающей запятой стали быстрее.

Использование методов Java для преобразования чисел с плавающей точкой в ​​целочисленные биты и обратно может быть медленнее, чем просто вычисление обратного квадратного корня напрямую с использованием математической функции Java для квадратного корня.

1 голос
/ 12 мая 2010

Хорошо, я собираюсь на конечности, потому что я знаю C, но я не знаю Java.

Буквальное переписывание этого C-кода на Java требует больших усилий. Даже в C код не переносим. Среди прочего он опирается на: Размер чисел с плавающей запятой. Размер целых чисел. Внутреннее представление чисел с плавающей точкой. Выравнивание байтов как чисел с плавающей точкой, так и целых чисел. Сдвиг вправо (т.е. я >> 1) осуществляется с использованием логического сдвига вправо в отличие от арифметического сдвига вправо (который будет сдвиг в 1 на целые числа с битом высокого порядка 1 и, таким образом, больше не равняются делению на 2).

Я понимаю, что Java компилируется в байт-код, а не напрямую в Машинный код. Разработчики интерпретаторов байтового кода настраиваются с помощью предположения, основанные на спецификации для байтового кода и понимания что выводит компилятор из разумного источника ввода код.

Подобные хаки не попадают под зонтик "разумного источника ввода".

Нет оснований ожидать, что переводчик выполнит быстрее с вашим взломом C, на самом деле есть хороший шанс это будет медленнее.

Мой совет: игнорировать код С.

Ищите выигрыш в эффективности, ориентированный на Java.

Концепция взлома C:

Приблизительно 1 / квадрат (х), используя знания о том, что внутренний представление чисел с плавающей точкой уже имеет экспонента, вычеркнутая из числа, экспонента (x) / 2 быстрее вычислить, чем root (x), если у вас уже есть показатель степени (x).

Затем взломщик выполняет одну итерацию метода Ньютона. уменьшить погрешность в приближении. Я предполагаю одна итерация уменьшила ошибку до приемлемого уровня.

Возможно, концепция требует исследования на Java, но детали будут зависеть от глубоких знаний как реализован JAVA, а не как C.

0 голосов
/ 11 мая 2010

Линии, о которых вы заботитесь, довольно простые. Строка 2 принимает байты с плавающей запятой x, которые находятся в некотором представлении с плавающей запятой, например, IEEE754, и сохраняет их в целых числах в точности так, как они есть. Это приведет к совершенно другому числу, так как целые числа и числа с плавающей точкой представлены по-разному в байтовой форме. Строка 4 делает обратное и снова передает байты в этом int в число с плавающей точкой

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...