Магическая константа 0x5f3759df (немного пятничное)

Многие из присутствующих знают волшебный трюк: ХЗ почему, но вот такая программа с довольно приличной точностью вычисляет обратную величину квадратного корня из x.

image

float FastInvSqrt(float x) {
	float xhalf = 0.5f * x;
	int i = *(int*)&x;  // представим биты float в виде целого числа
	i = 0x5f3759df - (i >> 1);  // какого черта здесь происходит ?
	x = *(float*)&i;
	x = x*(1.5f-(xhalf*x*x));
	return x;
}

Чуть поменьше, но тоже немало народу знают, что если страшную константу 0x5f3759df заменить на не менее страшную 0x1fbd1df5, то та же самая функция, каким-то волшебным образом начнёт вычислять просто корень из x (не обратную величину).

Если кому-то, когда-то, хотелось понять, что же чёрт побери здесь происходит, то теперь у вас появилась такая возможность. Вот, читайте - полное разоблачение волшебных констант.

3 лайка

Чой-та вас в пятницу на некротемы потянуло? ))

А, что, все это уже знают?

Ну, тогда, как писал сэр Исаак Ньютон: «Если же окажется известным всё, то более буду наказан я – писавший, нежели Вы – читающий».

1 лайк

На счет всех - не знаю. Но, полагаю, кому это нужно/интересно - точно должны знать. :slight_smile:

А я тем не менее запустил компиляцию вот этого:

Спойлер
float FastInvSqrt(float x) {
  float xhalf = 0.5f * x;
  int i = *(int*)&x;  // представим биты float в виде целого числа
  i = 0x5f3759df - (i >> 1);  // какого черта здесь происходит ?
  x = *(float*)&i;
  x = x*(1.5f-(xhalf*x*x));
  return x;
}

void setup() {
  
  Serial.begin(9600);
  for (uint8_t i = 1; i < 25; i++) {
    Serial.println(FastInvSqrt(i));
  }
}

void loop() {  }

и получил вот такое:

Спойлер
C:\Users\u\AppData\Local\Temp\arduino_modified_sketch_223041\sketch_jun02a.ino: In function 'float FastInvSqrt(float)':
C:\Users\u\AppData\Local\Temp\arduino_modified_sketch_223041\sketch_jun02a.ino:3:19: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
   int i = *(int*)&x;  // представим биты float в виде целого числа
                   
C:\Users\u\AppData\Local\Temp\arduino_modified_sketch_223041\sketch_jun02a.ino:5:17: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
   x = *(float*)&i;
                 
C:\Users\u\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.6\cores\arduino\new.cpp: In function 'void* operator new(std::size_t, std::nothrow_t)':
C:\Users\u\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.6\cores\arduino\new.cpp:59:60: warning: unused parameter 'tag' [-Wunused-parameter]
 void * operator new(std::size_t size, const std::nothrow_t tag) noexcept {
                                                            
C:\Users\u\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.6\cores\arduino\new.cpp: In function 'void* operator new [](std::size_t, const std::nothrow_t&)':
C:\Users\u\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.6\cores\arduino\new.cpp:68:63: warning: unused parameter 'tag' [-Wunused-parameter]
 void * operator new[](std::size_t size, const std::nothrow_t& tag) noexcept {
                                                               
C:\Users\u\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.6\cores\arduino\new.cpp: In function 'void operator delete(void*, const std::nothrow_t&)':
C:\Users\u\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.6\cores\arduino\new.cpp:103:55: warning: unused parameter 'tag' [-Wunused-parameter]
 void operator delete(void* ptr, const std::nothrow_t& tag) noexcept {
                                                       
C:\Users\u\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.6\cores\arduino\new.cpp: In function 'void operator delete [](void*, const std::nothrow_t&)':
C:\Users\u\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.6\cores\arduino\new.cpp:106:57: warning: unused parameter 'tag' [-Wunused-parameter]
 void operator delete[](void* ptr, const std::nothrow_t& tag) noexcept {

Чой-та так?

это код для архитектуры с 32битными инт
Попробуйте его компильнуть для ЕСП32, например

Это для 32 бит-ных int’ов.

Чтобы работало на 8-битном AVR, в третьей строке int на long замените.

Ну для кого как. Хабр читаю, но не попадалось. Для меня витапост. Прикольно.

1 лайк