Вы можете довольно смело предположить форматирование IEEE 754, детали которого могут стать довольно скучными (особенно, когда вы попадаете в субнормалы). Однако в общих случаях это должно работать:
const int DOUBLE_EXP_SHIFT = 52;
const unsigned long long DOUBLE_MANT_MASK = (1ull << DOUBLE_EXP_SHIFT) - 1ull;
const unsigned long long DOUBLE_EXP_MASK = ((1ull << 63) - 1) & ~DOUBLE_MANT_MASK;
void unsafe_shl(double* d, int shift) {
unsigned long long* i = (unsigned long long*)d;
if ((*i & DOUBLE_EXP_MASK) && ((*i & DOUBLE_EXP_MASK) != DOUBLE_EXP_MASK)) {
*i += (unsigned long long)shift << DOUBLE_EXP_SHIFT;
} else if (*i) {
*d *= (1 << shift);
}
}
РЕДАКТИРОВАТЬ: После некоторой синхронизации этот метод немного медленнее, чем метод double на моем компиляторе и машине, даже обрезанный до минимально исполняемого кода:
double ds[0x1000];
for (int i = 0; i != 0x1000; i++)
ds[i] = 1.2;
clock_t t = clock();
for (int j = 0; j != 1000000; j++)
for (int i = 0; i != 0x1000; i++)
#if DOUBLE_SHIFT
ds[i] *= 1 << 4;
#else
((unsigned int*)&ds[i])[1] += 4 << 20;
#endif
clock_t e = clock();
printf("%g\n", (float)(e - t) / CLOCKS_PER_SEC);
В DOUBLE_SHIFT завершается через 1,6 секунды, с внутренней петлей
movupd xmm0,xmmword ptr [ecx]
lea ecx,[ecx+10h]
mulpd xmm0,xmm1
movupd xmmword ptr [ecx-10h],xmm0
В сравнении с 2,4 секундами в противном случае с внутренним циклом:
add dword ptr [ecx],400000h
lea ecx, [ecx+8]
Действительно неожиданно!
РЕДАКТИРОВАТЬ 2: Тайна раскрыта! Одним из изменений для VC11 является то, что теперь он всегда векторизует циклы с плавающей запятой, эффективно форсируя / arch: SSE2, хотя VC10 даже с / arch: SSE2 все еще хуже с 3,0 секундами с внутренним циклом:
movsd xmm1,mmword ptr [esp+eax*8+38h]
mulsd xmm1,xmm0
movsd mmword ptr [esp+eax*8+38h],xmm1
inc eax
VC10 без / arch: SSE2 (даже с / arch: SSE) составляет 5,3 секунды ... с 1/100 итерациями !! , внутренний цикл:
fld qword ptr [esp+eax*8+38h]
inc eax
fmul st,st(1)
fstp qword ptr [esp+eax*8+30h]
Я знал, что стек x87 FP ужасен, но в 500 раз хуже, это просто смешно. Вы, вероятно, не увидите такого рода ускорений, например, матричных операций в SSE или int-хаков, поскольку это наихудший случай загрузки в стек FP, выполнения одной операции и сохранения из нее, но это хороший пример того, почему x87 это не способ пойти на что-либо перф. связаны между собой.