Вы сравниваете теплое с мягким — очевидно, что тривиальная программа при прочих равных медленнее/менее точна чем программа с итеративным вычислением тригонометрии. Так что непонятно, на что списывать разницу в результатах — на ассемблер или на алгоритм. Нужно реализовать итеративную тригонометрию на C# и сравнить ассемблер с ней.
Ну и странно, что fsincos вызывается n раз — можно посчитать функции только для phi, а дальше все по формулам.
Ну, я тоже когда-то соревновался с memcpy (правда, с msvc-шным на x86), и тоже не мог его обогнать, даже с SIMD. Но оказалось, что это не потому, что SIMD медленный, а потому, что в msvc реализация лучше…
Возможно criterion использует не слишком точный таймер, да и вообще, мерять 0.5ms даже с QPC — не слишком перспективное занятие. Нужно увеличить количество итераций.
См. комментарий.
Тестов, сравнений опять нет, аргументация высокой производительности вида «использовал SIMD» — несостоятельна. И опять ничего не понятно.
Компилятор — это машина, у него всегда хорошее настроение. Их совершенствовали годами, и они справляются со своими задачами очень хорошо. У кого может быть плохое настроение — так это у программиста. Иногда даже у Вас.
Я отлично понимаю, что эти функции — это по факту ассемблерные инструкции. Они поэтому и называются «интринсиками», а не функциями. Но нет, этот код не написан на ассемблере, ведь во время его написания я не думал об аллокации регистров, соблюдении соглашений вызова и прочей рутине. Это работа, требующая лишь внимание для выполнения автоматических действий по четкому алгоритму — почему бы не поручить ее компилятору.
Если Вы затрудняетесь в подобных рассуждениях, то Вы или не понимаете понятие языков высокого уровня, или не понимаете дизайн SSE/AVX интринсиков в C++. В любом случае рекомендую вместо выпытывания объяснений прочитать какую-нибудь основательную статью на заданные темы. Спойлер: при умножении вектора на матрицу чтение/запись в память, как и FPU, не нужны вообще.
Известная Вам картина мира противоречит реальной картине мира, в которой стандартная функция логарифма в MSVC реализуется програмно с помощью SSE/AVX инструкций. Но в Microsoft очевидно тестировали производительность своего решения при разработке, так что в Вашей картине мира они может быть не самым лучшим.
Нет, не можете. Речь идет о C/C++, программист оперирует переменными, а регистрами оперирует компилятор.
Программисты спокойно вычисляют логарифмы без устаревших наборов инструкций.
Вы-то можете не сомневаться в своих решениях, но тому, кто мог бы использовать данное решение в критически важном месте, нужны аргументы получше. Так что таким как Вы статья может и понравиться, но те, к числу которых Вы пытаетесь себя причислить, определенно пройдут стороной.
Ну и странно, что fsincos вызывается n раз — можно посчитать функции только для phi, а дальше все по формулам.
Возможно criterion использует не слишком точный таймер, да и вообще, мерять 0.5ms даже с QPC — не слишком перспективное занятие. Нужно увеличить количество итераций.
Тестов, сравнений опять нет, аргументация высокой производительности вида «использовал SIMD» — несостоятельна. И опять ничего не понятно.
--- minkernel\crts\ucrt\src\appcrt\tran\amd64\log.asm ---sub rsp,58h
movdqa xmmword ptr [rsp+20h],xmm6
cmp dword ptr [__use_fma3_lib (07FF6A0259C2Ch)],0
jne Llog_sse2+2A9h (07FF6A0247C10h)
movdqa xmm3,xmm0
movapd xmm4,xmm0
psrlq xmm3,34h
movq rax,xmm0
psubq xmm3,xmmword ptr [__mask_1023 (07FF6A02533A0h)]
mov rcx,rax
btr rcx,3Fh
cmp rcx,qword ptr [__real_inf (07FF6A0253350h)]
jae Llog_sse2+279h (07FF6A0247BE0h)
movdqa xmm2,xmm0
cvtdq2pd xmm6,xmm3
pand xmm2,xmmword ptr [__real_mant (07FF6A0253390h)]
subsd xmm4,mmword ptr [__real_one (07FF6A02533F0h)]
comisd xmm6,mmword ptr [__mask_1023_f (07FF6A02534A0h)]
je Llog_sse2+1F9h (07FF6A0247B60h)
andpd xmm4,xmmword ptr [__real_notsign (07FF6A02534D0h)]
mov r9,rax
and rax,qword ptr [__mask_mant_all8 (07FF6A02533C0h)]
and r9,qword ptr [__mask_mant9 (07FF6A02533D0h)]
shl r9,1
add rax,r9
movq xmm1,rax
comisd xmm4,mmword ptr [__real_threshold (07FF6A02534C0h)]
jb Llog_sse2+169h (07FF6A0247AD0h)
shr rax,2Ch
por xmm2,xmmword ptr [__real_half (07FF6A0253420h)]
por xmm1,xmmword ptr [__real_half (07FF6A0253420h)]
lea r9,[__log_F_inv_qword (07FF6A0251EE0h)]
xorpd xmm5,xmm5
comisd xmm0,xmm5
jbe Llog_sse2+239h (07FF6A0247BA0h)
subsd xmm1,xmm2
mulsd xmm1,mmword ptr [r9+rax*8]
movapd xmm2,xmm1
movapd xmm0,xmm1
lea r9,[__log_256_lead (07FF6A0253960h)]
movsd xmm3,mmword ptr [__real_1_over_6 (07FF6A0253490h)]
movsd xmm1,mmword ptr [__real_1_over_3 (07FF6A0253460h)]
mulsd xmm3,xmm2
mulsd xmm1,xmm2
mulsd xmm0,xmm2
movapd xmm4,xmm0
addsd xmm3,mmword ptr [__real_1_over_5 (07FF6A0253480h)]
addsd xmm1,mmword ptr [__real_1_over_2 (07FF6A0253450h)]
mulsd xmm4,xmm0
mulsd xmm3,xmm2
mulsd xmm1,xmm0
addsd xmm3,mmword ptr [__real_1_over_4 (07FF6A0253470h)]
addsd xmm1,xmm2
mulsd xmm3,xmm4
addsd xmm1,xmm3
movsd xmm5,mmword ptr [__real_log2_tail (07FF6A0253530h)]
mulsd xmm5,xmm6
subsd xmm5,xmm1
movsd xmm0,mmword ptr [r9+rax*8]
lea rdx,[__log_256_tail (07FF6A0254170h)]
movsd xmm2,mmword ptr [rdx+rax*8]
addsd xmm2,xmm5
movsd xmm4,mmword ptr [__real_log2_lead (07FF6A0253520h)]
mulsd xmm4,xmm6
addsd xmm0,xmm4
addsd xmm0,xmm2
movdqa xmm6,xmmword ptr [rsp+20h]
add rsp,58h
ret
nop word ptr [rax+rax]
movsd xmm2,mmword ptr [__real_two (07FF6A02533E0h)]
subsd xmm0,mmword ptr [__real_one (07FF6A02533F0h)]
addsd xmm2,xmm0
movsd xmm1,xmm0
divsd xmm1,xmm2
movsd xmm4,mmword ptr [__real_ca2 (07FF6A02534F0h)]
movsd xmm5,mmword ptr [__real_ca4 (07FF6A0253510h)]
movsd xmm6,xmm0
mulsd xmm6,xmm1
addsd xmm1,xmm1
movsd xmm2,xmm1
mulsd xmm2,xmm1
mulsd xmm4,xmm2
mulsd xmm5,xmm2
addsd xmm4,mmword ptr [__real_ca1 (07FF6A02534E0h)]
addsd xmm5,mmword ptr [__real_ca3 (07FF6A0253500h)]
mulsd xmm2,xmm1
mulsd xmm4,xmm2
mulsd xmm2,xmm2
mulsd xmm2,xmm1
mulsd xmm5,xmm2
addsd xmm4,xmm5
subsd xmm4,xmm6
addsd xmm0,xmm4
movdqa xmm6,xmmword ptr [rsp+20h]
add rsp,58h
ret
nop word ptr [rax+rax]
por xmm2,xmmword ptr [__real_one (07FF6A02533F0h)]
subsd xmm2,mmword ptr [__real_one (07FF6A02533F0h)]
movsd xmm5,xmm2
pand xmm2,xmmword ptr [__real_mant (07FF6A0253390h)]
movq rax,xmm2
psrlq xmm5,34h
psubd xmm5,xmmword ptr [__mask_2045 (07FF6A02534B0h)]
cvtdq2pd xmm6,xmm5
jmp Llog_sse2+55h (07FF6A02479BCh)
nop word ptr [rax+rax]
jne Llog_sse2+259h (07FF6A0247BC0h)
movsd xmm1,mmword ptr [__real_ninf (07FF6A0253340h)]
mov r8d,dword ptr [__flag_x_zero (07FF6A0253540h)]
call _log_special (07FF6A02467D0h)
jmp Llog_sse2+299h (07FF6A0247C00h)
nop dword ptr [rax+rax]
movsd xmm1,mmword ptr [__real_neg_qnan (07FF6A0253360h)]
mov r8d,dword ptr [__flag_x_neg (07FF6A0253544h)]
call _log_special (07FF6A02467D0h)
jmp Llog_sse2+299h (07FF6A0247C00h)
nop word ptr [rax+rax]
cmp rax,qword ptr [__real_inf (07FF6A0253350h)]
je Llog_sse2+299h (07FF6A0247C00h)
cmp rax,qword ptr [__real_ninf (07FF6A0253340h)]
je Llog_sse2+259h (07FF6A0247BC0h)
or rax,qword ptr [__real_qnanbit (07FF6A0253370h)]
movq xmm0,rax
xchg ax,ax
movdqa xmm6,xmmword ptr [rsp+20h]
add rsp,58h
ret
nop dword ptr [rax+rax]
xor rax,rax
vpsrlq xmm3,xmm0,34h
vmovq rax,xmm0
vpsubq xmm3,xmm3,xmmword ptr [__mask_1023 (07FF6A02533A0h)]
vcvtdq2pd xmm6,xmm3
vpand xmm5,xmm0,xmmword ptr [__real_inf (07FF6A0253350h)]
vcomisd xmm5,mmword ptr [__real_inf (07FF6A0253350h)]
je Llog_sse2+4D9h (07FF6A0247E40h)
vpxor xmm5,xmm5,xmm5
vcomisd xmm0,xmm5
jbe Llog_sse2+489h (07FF6A0247DF0h)
vpand xmm2,xmm0,xmmword ptr [__real_mant (07FF6A0253390h)]
vsubsd xmm4,xmm0,mmword ptr [__real_one (07FF6A02533F0h)]
vcomisd xmm6,mmword ptr [__mask_1023_f (07FF6A02534A0h)]
je Llog_sse2+457h (07FF6A0247DBEh)
vpand xmm1,xmm0,xmmword ptr [__mask_mant_all8 (07FF6A02533C0h)]
vpand xmm3,xmm0,xmmword ptr [__mask_mant9 (07FF6A02533D0h)]
vpsllq xmm3,xmm3,1
vpaddq xmm1,xmm3,xmm1
vmovq rax,xmm1
vpand xmm4,xmm4,xmmword ptr [__real_notsign (07FF6A02534D0h)]
vcomisd xmm4,mmword ptr [__real_threshold (07FF6A02534C0h)]
jb Llog_sse2+3E9h (07FF6A0247D50h)
shr rax,2Ch
vpor xmm2,xmm2,xmmword ptr [__real_half (07FF6A0253420h)]
vpor xmm1,xmm1,xmmword ptr [__real_half (07FF6A0253420h)]
lea r9,[__log_F_inv_qword (07FF6A0251EE0h)]
vsubsd xmm1,xmm1,xmm2
vmulsd xmm1,xmm1,mmword ptr [r9+rax*8]
lea r9,[__log_256_lead (07FF6A0253960h)]
vmulsd xmm0,xmm1,xmm1
vmovsd xmm3,qword ptr [__real_1_over_6 (07FF6A0253490h)]
vmovsd xmm5,qword ptr [__real_1_over_3 (07FF6A0253460h)]
vfmadd213sd xmm3,xmm1,mmword ptr [__real_1_over_5 (07FF6A0253480h)]
vfmadd213sd xmm5,xmm1,mmword ptr [__real_1_over_2 (07FF6A0253450h)]
vmovsd xmm4,xmm0,xmm0
vfmadd213sd xmm3,xmm1,mmword ptr [__real_1_over_4 (07FF6A0253470h)]
vmulsd xmm4,xmm0,xmm0
vfmadd231sd xmm1,xmm5,xmm0
vfmadd231sd xmm1,xmm3,xmm4
vmovsd xmm5,qword ptr [__real_log2_tail (07FF6A0253530h)]
vfmsub213sd xmm5,xmm6,xmm1
vmovsd xmm0,qword ptr [r9+rax*8]
lea rdx,[__log_256_tail (07FF6A0254170h)]
vmovsd xmm1,qword ptr [rdx+rax*8]
vaddsd xmm1,xmm1,xmm5
vfmadd231sd xmm0,xmm6,mmword ptr [__real_log2_lead (07FF6A0253520h)]
vaddsd xmm0,xmm0,xmm1
vmovdqa xmm6,xmmword ptr [rsp+20h]
add rsp,58h
ret
nop word ptr [rax+rax]
vmovsd xmm3,qword ptr [__real_two (07FF6A02533E0h)]
vsubsd xmm0,xmm0,mmword ptr [__real_one (07FF6A02533F0h)]
vaddsd xmm3,xmm3,xmm0
vdivsd xmm1,xmm0,xmm3
vmovsd xmm4,qword ptr [__real_ca2 (07FF6A02534F0h)]
vmovsd xmm5,qword ptr [__real_ca4 (07FF6A0253510h)]
vmulsd xmm3,xmm0,xmm1
vaddsd xmm1,xmm1,xmm1
vmulsd xmm2,xmm1,xmm1
vfmadd213sd xmm4,xmm2,mmword ptr [__real_ca1 (07FF6A02534E0h)]
vfmadd213sd xmm5,xmm2,mmword ptr [__real_ca3 (07FF6A0253500h)]
vmulsd xmm2,xmm2,xmm1
vmulsd xmm4,xmm4,xmm2
vmulsd xmm2,xmm2,xmm2
vmulsd xmm2,xmm2,xmm1
vfmadd231sd xmm4,xmm5,xmm2
vsubsd xmm4,xmm4,xmm3
vaddsd xmm0,xmm0,xmm4
vmovdqa xmm6,xmmword ptr [rsp+20h]
add rsp,58h
ret
vpor xmm2,xmm2,xmmword ptr [__real_one (07FF6A02533F0h)]
vsubsd xmm2,xmm2,mmword ptr [__real_one (07FF6A02533F0h)]
vpsrlq xmm5,xmm2,34h
vpand xmm2,xmm2,xmmword ptr [__real_mant (07FF6A0253390h)]
vmovapd xmm0,xmm2
vpsubd xmm5,xmm5,xmmword ptr [__mask_2045 (07FF6A02534B0h)]
vcvtdq2pd xmm6,xmm5
jmp Llog_sse2+304h (07FF6A0247C6Bh)
jne Llog_sse2+4B9h (07FF6A0247E20h)
vmovsd xmm1,qword ptr [__real_ninf (07FF6A0253340h)]
mov r8d,dword ptr [__flag_x_zero (07FF6A0253540h)]
call _log_special (07FF6A02467D0h)
vmovdqa xmm6,xmmword ptr [rsp+20h]
add rsp,58h
ret
nop word ptr [rax+rax]
vmovsd xmm1,qword ptr [__real_neg_qnan (07FF6A0253360h)]
mov r8d,dword ptr [__flag_x_neg (07FF6A0253544h)]
call _log_special (07FF6A02467D0h)
vmovdqa xmm6,xmmword ptr [rsp+20h]
add rsp,58h
ret
nop
cmp rax,qword ptr [__real_inf (07FF6A0253350h)]
je Llog_sse2+509h (07FF6A0247E70h)
cmp rax,qword ptr [__real_ninf (07FF6A0253340h)]
je Llog_sse2+4B9h (07FF6A0247E20h)
or rax,qword ptr [__real_qnanbit (07FF6A0253370h)]
vmovq xmm1,rax
mov r8d,dword ptr [__flag_x_nan (07FF6A0253548h)]
call _log_special (07FF6A02467D0h)
nop word ptr [rax+rax]
vmovdqa xmm6,xmmword ptr [rsp+20h]
add rsp,58h
ret
Программисты спокойно вычисляют логарифмы без устаревших наборов инструкций.
Их можно использовать вручную. Там вообще есть все кроме FPU стека)