по известному алгоритму из Quake и затем делить единицу на эту величину
эта идея мне приходила в голову, там даже проще чем Вы пишите, инверсию корня делать ненужно, лучше его умножить на аргумент, это заметно добавляет точности. Я это всё опробовал, вот рабочий код:
Код:
double fast_sqrt(double x)
{ 
  double y=0;
  asm ("movq %1, %%rax; shr  $1, %%rax; movq $6910469321099104000, %%rbx; "
       "subq %%rax, %%rbx; movq %%rbx, %0;"
       :"=r"(y)
       :"r"(x)
       :"%rax","%rbx"
       );
       y=y*(3-(x*y*y));
       y=y*(12-(x*y*y));
       y=y*(768-(x*y*y));
       
  return y*x/8192;
}
даёт точность почти double, если убрать последнюю итерацию - получается почти float, если оставить только одну, то получается 3 верных знака. Но но скорости это хозяйство отстаёт от sqrt. Если ограничиться точностью float и вставить тело функции прямо в код, то работает в 1.5 раза быстрее, что тоже несущественно.
-- 04.05.2024, 18:50 --можно сделать LUT и считать результат линейной интерполяцией
я не знаю что это такое, но делал вот такую штуку, если Вы об этом:
Код:
   const uint64_t root[64]=
   { 0,69827414112268,138604612414727,206377602297819,
       273189127023833,339078981026126,404084287098361,
       468239740956932,531577827751080,594129014356004,
       655921920679557,716983472715828,777339039667879,
       837012557120638,896026637960214,954402672497414,
       1012160919052590,1069320586089555,1125899906842624,
       1181916207258746,1237385967972342,1292324880941192,
       1346747901294976,1400669294881971,1454102681942250,
       1507061077286234,1559556927314419,1611602144176602,
       1663208137336207,1714385842776648,1765145750061507,
       1815497927438199,1865452045155277,1964202921218288,
       2061468567839650,2157314049294893,2251799813685248,
       2344982138838073,2436913524311641,2527643037258634,
       2617216618617683,2705677355056896,2793065721238116,
       2879419796267360,2964775457615668,3049166555311868,
       3132625068806179,3215181248566246,3296863744183466,
       3377699720527872,3457714963286720,3536933975049166,
       3615380062951923,3693075418774505,3770041192264134,
       3846297558376920,3921863779041097,3996758259978076,
       4070998603056240,4144601654599387,4217583550025434,
       4289959755150440,4361745104457490,4432953836598623 };
  
   asm ("movq %1, %%rax;"
        "movq %%rax, %%rbx;"
        "xorq %%rcx, %%rcx; incq %%rcx; rcr  $2, %%rcx;"  // знаковый бит
        "andq %%rcx, %%rbx; subq %%rbx, %%rax;"
        "shr  $2, %%rcx; decq %%rcx; movq %%rcx, %%rdx; incq %%rcx;"
        "shr  $9, %%rcx; addq %%rcx, %%rax;"
        "decq %%rcx; notq %%rcx; andq %%rcx, %%rdx; shr $1, %%rax;"
        "addq %%rdx, %%rax; addq %%rbx, %%rax;"
        "movq %%rax, %%rbx; andq %%rcx, %%rbx;"            // порядок
        "notq %%rcx; andq %%rcx, %%rax;"
        "shr  $38, %%rax; xor %%al, %%al; shr  $5, %%rax;" // 8-битный адрес мантиссы        
        "movq %2, %%rcx; add %%rax, %%rcx; xorq (%%rcx), %%rbx;" // из массива  
        "movq %%rbx, %0;"
                
         :"=r"(br)                        
         :"r"(ar), "r"(root)            
         :"%rax", "%rbx", "%rcx", "%rdx"   
        );
       tmp=ar/br; br+=tmp; br/=2;
смысл такой - несколько старших бит смещённой мантиссы double используются в качестве адреса массива, содержащего готовые значения корня. Но мне кажется затея так себе, доступ к памяти в данном случае слишком дорогой, это сводит всё на нет.