Всегда было интересно, насколько классические вещи неоптимально работают?
Написал свой вариант sin/cos с использованием заранее посчитанной таблицы.
Измерял скорость вычисления sin (переменная) и sin (переменная+число).
Прибавка в скорости:
Microsoft C++Intel C++
Athlon+340%+180%+120%+100%
Core2 Duo+2270%+1890%+910%+845%
Если хранить и считать углы в формулах в целых числах - получится еще быстрее.
А что же с точностью?
При размере таблицы в 4kb максимальная погрешность 0.0061, при 16kb - 0.0015, при 64kb - 0.0003.
Microsoft 32-bit C/C++ Optimizing Compiler 13.10.3077 2002 года (/O2 /G7 /arch:SSE2)
Intel C++ Compiler Professional 11.1.48 2009 года (/O3 /arch:SSE2 /Zc:forScope)
AMD Athlon 64 3000+ 2Ghz
Microsoft C++ Intel C++
sinf (f) = 5291 msec | 1985 msec
sin32 (angle2int(f)) = 1199 msec | 899 msec
sinf (f+0.5) = 4007 msec | 2118 msec
sin32 (angle2int(f+0.5)) = 1429 msec | 1039 msec
Intel Core 2 Duo 3Ghz
Microsoft C++ Intel C++
sinf (f) = 3750 msec | 1029 msec
sin32 (angle2int(f)) = 158 msec | 102 msec
sinf (f+0.5) = 4140 msec | 1116 msec
sin32 (angle2int(f+0.5)) = 208 msec | 118 msec
enum
{
SINCOS_NUM_BITS = 12, // количество бит точности
SINCOS_TABLE_SIZE = 1 << SINCOS_NUM_BITS, // размер таблицы
SINCOS_TABLE_SHIFT = 16 - SINCOS_NUM_BITS, // сдвиг
SINCOS_TABLE_MASK = SINCOS_TABLE_SIZE - 1, // маска
SINCOS_PI = 32768, // пи
SINCOS_2PI = 2 * SINCOS_PI,
SINCOS_PI_DIV_2 = SINCOS_PI / 2,
};
const float ANGLE2INT = float (SINCOS_PI / M_PI);
const float INT2ANGLE = float (M_PI / SINCOS_PI);
__declspec (align(16)) float sin_table [SINCOS_TABLE_SIZE];
__forceinline int angle2int ( float angle )
{
return int ( angle * ANGLE2INT );
};
__forceinline float int2angle ( int val )
{
return val * INT2ANGLE;
};
__forceinline float sin32 ( int val )
{
return sin_table [ (val >> SINCOS_TABLE_SHIFT) & SINCOS_TABLE_MASK ];
};
__forceinline float cos32 ( int val )
{
return sin32 ( val + SINCOS_PI_DIV_2 );
};
// инициализация
for ( int i = 0; i < SINCOS_TABLE_SIZE; i++ )
{
const float angle = int2angle ( i << SINCOS_TABLE_SHIFT );
sin_table [i] = sinf (angle);
}
; f2 = sinf ( f1 + 0.5f );
; Intel C++
movss xmm0, [128+esp]
addss xmm0, [floatpacket.64]
call ___libm_sse2_sinf
; Microsoft C++
movss xmm0, f1 [ebp]
movss T56316 [ebp], xmm0
fld T56316 [ebp]
call __CIsin
fst tv335 [ebp]
fstp f2 [ebp]
; f2 = sin32 ( angle2int (f1 + 0.5f) );
; Intel C++
movss xmm0, [128+esp]
addss xmm0, xmm4
mulss xmm0, [ANGLE2INT]
cvttss2si edx, xmm0
shr edx, 4
and edx, 4095
mov ecx, [sin_table + edx*4]
mov [132+esp], ecx
; Microsoft C++
movss xmm0, f1 [ebp]
addss xmm0, real_f000000
movss T56376 [ebp], xmm0
movss xmm0, T56376 [ebp]
mulss xmm0, ANGLE2INT
cvttss2si eax, xmm0
sar eax, 4
and eax, 4095
movss xmm0, sin_table [eax*4]
movss f2 [ebp], xmm0
Полный исходникМожно скомпилить у себя и рассказать о результатах.
Порекомендовать: