Я не знаю, как кодировать число с плавающей запятой в целочисленном формате.
Для этого есть функция: _1 _ strong>, который возвращает u32
. Также есть функция для другого направления: f32::from_bits
, который принимает u32
в качестве аргумента. Эти функции предпочтительнее, чем mem::transmute
, поскольку последняя unsafe
сложна в использовании.
Итак, вот реализация InvSqrt
:
fn inv_sqrt(x: f32) -> f32 {
let i = x.to_bits();
let i = 0x5f3759df - (i >> 1);
let y = f32::from_bits(i);
y * (1.5 - 0.5 * x * y * y)
}
(площадка)
Эта функция компилируется в следующую сборку на x86-64:
.LCPI0_0:
.long 3204448256 ; f32 -0.5
.LCPI0_1:
.long 1069547520 ; f32 1.5
example::inv_sqrt:
movd eax, xmm0
shr eax ; i << 1
mov ecx, 1597463007 ; 0x5f3759df
sub ecx, eax ; 0x5f3759df - ...
movd xmm1, ecx
mulss xmm0, dword ptr [rip + .LCPI0_0] ; x *= 0.5
mulss xmm0, xmm1 ; x *= y
mulss xmm0, xmm1 ; x *= y
addss xmm0, dword ptr [rip + .LCPI0_1] ; x += 1.5
mulss xmm0, xmm1 ; x *= y
ret
Я не нашел ни одной эталонной сборки (если есть, скажите, пожалуйста!), Но мне она кажется неплохой. Я просто не уверен, почему число с плавающей запятой было перемещено в eax
только для того, чтобы выполнить сдвиг и целочисленное вычитание. Может быть, регистры SSE не поддерживают эти операции?
clang 9.0 с -O3
компилирует код C в в основном ту же сборку. Так что это хороший знак.
Стоит отметить, что если вы действительно хотите использовать это на практике: пожалуйста, не делайте этого. Как указал benrg в комментарии, современные процессоры x86 имеют специальную инструкцию для этой функции, которая работает быстрее и точнее, чем этот хакерский хак. К сожалению, 1.0 / x.sqrt()
, похоже, не оптимизируется под эту инструкцию. Так что, если вам действительно нужна скорость, используйте встроенные функции _mm_rsqrt_ps
< / a>, вероятно, лучший вариант. Однако это опять же требует unsafe
кода. Я не буду вдаваться в подробности в этом ответе, так как это действительно понадобится меньшинству программистов.
person
Lukas Kalbertodt
schedule
28.11.2019
union
. - person trentcl   schedule 28.11.2019union
работает.memcpy
определенно работает, хотя и многословно. - person Matthieu M.   schedule 28.11.2019rsqrtss
иrsqrtps
, представленные в Pentium III в 1999 году, работают быстрее и точнее, чем этот код. ARM NEON имеетvrsqrte
, что похоже. И какие бы вычисления Quake III ни использовал для этого, вероятно, в наши дни все равно будет выполняться на GPU. - person benrg   schedule 30.11.2019