Определено, что произойдет, если вы сдвинете поплавок? - PullRequest
1 голос
/ 05 апреля 2020

Я следую Это видеоурок по реализации raycaster. Он содержит этот код:

if(ra > PI) { ry = (((int)py>>6)<<6)-0.0001; rx=(py-ry)*aTan+px; yo=-64; xo=-yo*aTan; }//looking up

Я надеюсь, что я расшифровал это правильно. В частности, мой вопрос о приведении py (он объявлен как float) к целому числу, смещении его назад и вперед, вычитании чего-либо, а затем присвоении его ry (также float) этой строке код вводится в 7:24, где он также объясняет, что он хочет

округлить позицию y до ближайшего 64-го значения

(я не уверен, если это означает, что ближайшее кратное 64 или ближайшее (1/64), но я знаю, что 6 в источнике происходит от числа 64, равного 2⁶)

С одной стороны, я думаю, что это будет допустимо, чтобы компилятор загружал (скажем) 32-разрядное число с плавающей запятой в регистр машины, а затем сдвигал это значение на шесть пробелов, а затем сдвигал его обратно на шесть пробелов (эти две операции могут мешать мантиссе, или показатель степени, или, может быть, что-то еще, или , эти две операции могут быть удалены с помощью шага оптимизации глазка.)

Также я думаю, что для компилятора будет правильным, чтобы демоны вылетали из Ваш нос, когда выполняется это утверждение.

Итак, мой вопрос: (((int)py>>6)<<6) определено в C, когда py равно float?

Ответы [ 2 ]

1 голос
/ 06 апреля 2020

равно (((int)py>>6)<<6) определено в C, когда py равно float?

Это, безусловно, неопределенное поведение (UB) для многих float. Приведение к int является UB для float со значением целого числа вне диапазона [INT_MIN ... INT_MAX].

Таким образом, код является UB для примерно 38% всех типичных float - большие значения, NaN с и бесконечности.


Для типичных float приведение к int128_t определено почти для всех float.


Чтобы достичь цели ОП, код может использовать нижеприведенное, которое, как я считаю, хорошо определено для всех float.

Если что-то есть, используйте нижеприведенное, чтобы оценить правильность своего созданный код .

// round the y position to the nearest 64th value
float round_to_64th(float x) {
  if (isfinite(x)) {
    float ipart;
    // The modf functions break the argument value into integral and fractional parts
    float frac = modff(x, &ipart);
    x = ipart + roundf(frac*64)/64;
  }
  return x;
}

"Я не уверен, означает ли это ближайшее кратное 64 или ближайшее (1/64)"

Вкл обзор, код OP пытается укоротить до ближайшего кратного 64 или 2⁶.

Это все еще UB для многих float.

1 голос
/ 05 апреля 2020

Этот код не сдвигает float, потому что операторы битового сдвига не определены для типов с плавающей запятой. Если вы попробуете это, вы получите ошибку компилятора.

Обратите внимание, что код (int)py >> 6, float приведен к int перед операцией сдвига. Целочисленное значение - это то, что смещается.

Если ваш вопрос «что произойдет, если вы сместите число с плавающей запятой?», Ответ - он не скомпилируется. Пример в компиляторе Explorer .

...