Код (Pascal): function EuclidDist(const arr1, arr2: array of Double): Double; var i: Integer; begin Result := 0; if Length(arr1) = Length(arr2) then begin for i := 0 to Length(arr1) - 1 do begin Result := Result + Sqr(arr1 - arr2); end; Result := Sqrt(Result); end; end; //EuclidDist --- Delphi 7/win 32. Код (ASM): function EuclidDist(const V1, V2: TDouble): Double; assembler; asm // EAX = V1 data ptr (or nil) // EDX = V2 data ptr (or nil) test eax, eax jz @@Zero test edx, edx jz @@Zero mov ecx, [eax-4] // len1 test ecx, ecx jz @@Zero cmp ecx, [edx-4] // len2 jne @@Zero // ---- теперь можно сохранять callee-saved, т.к. точно работаем дальше push ebx push esi push edi mov esi, eax // p1 mov edi, edx // p2 // ebx = blocks of 8 doubles, edx = remainder (0..7) mov ebx, ecx shr ebx, 3 and ecx, 7 // остаток оставим в ECX xorps xmm0, xmm0 xorps xmm1, xmm1 xorps xmm2, xmm2 xorps xmm3, xmm3 // ---- optional aligned fast-path mov eax, esi or eax, edi test eax, 15 jnz @@Unaligned @@Aligned: test ebx, ebx jz @@Tail @@LoopA: movapd xmm4, [esi] movapd xmm5, [edi] subpd xmm4, xmm5 mulpd xmm4, xmm4 addpd xmm0, xmm4 movapd xmm4, [esi+16] movapd xmm5, [edi+16] subpd xmm4, xmm5 mulpd xmm4, xmm4 addpd xmm1, xmm4 movapd xmm4, [esi+32] movapd xmm5, [edi+32] subpd xmm4, xmm5 mulpd xmm4, xmm4 addpd xmm2, xmm4 movapd xmm4, [esi+48] movapd xmm5, [edi+48] subpd xmm4, xmm5 mulpd xmm4, xmm4 addpd xmm3, xmm4 add esi, 64 add edi, 64 dec ebx jnz @@LoopA jmp @@AfterMain @@Unaligned: test ebx, ebx jz @@Tail @@LoopU: movupd xmm4, [esi] movupd xmm5, [edi] subpd xmm4, xmm5 mulpd xmm4, xmm4 addpd xmm0, xmm4 movupd xmm4, [esi+16] movupd xmm5, [edi+16] subpd xmm4, xmm5 mulpd xmm4, xmm4 addpd xmm1, xmm4 movupd xmm4, [esi+32] movupd xmm5, [edi+32] subpd xmm4, xmm5 mulpd xmm4, xmm4 addpd xmm2, xmm4 movupd xmm4, [esi+48] movupd xmm5, [edi+48] subpd xmm4, xmm5 mulpd xmm4, xmm4 addpd xmm3, xmm4 add esi, 64 add edi, 64 dec ebx jnz @@LoopU @@AfterMain: addpd xmm0, xmm1 addpd xmm2, xmm3 addpd xmm0, xmm2 @@Tail: test ecx, ecx jz @@Finish @@TailLoop: movsd xmm4, [esi] movsd xmm5, [edi] subsd xmm4, xmm5 mulsd xmm4, xmm4 addsd xmm0, xmm4 add esi, 8 add edi, 8 dec ecx jnz @@TailLoop @@Finish: movhlps xmm1, xmm0 addsd xmm0, xmm1 sqrtsd xmm0, xmm0 // return Double via x87 ST(0) sub esp, 8 movsd qword ptr [esp], xmm0 fld qword ptr [esp] add esp, 8 pop edi pop esi pop ebx ret @@Zero: fldz ret end; ---
В скрипте наверно ошибка, должны быть индексы i в массивах, sqr это умножение. - deepseek Можно несколько потоков создать, уменьшить планировочные простои.
--- Код (Text): Правильный вариант: def euclidean_distance(x, y): return np.sqrt(np.sum((x - y) ** 2)) --- Типо такого? --- --- Сообщение объединено, 26 фев 2026 --- Дипсику про многопоточность не зашло
Это абмолютная чепуха, ботов нужно вначале обучить, только затем они годное генерят. Это все нужно проверять, prefetch тоже.
Формула евклидового расстояния абсолютно правильная, это вообще не трогаем. Да это понятно. Вручную надо писать, отлаживать в отладчике. Боты в такое вряд ли могут. --- Самое забористое. Код (ASM): function EuclidDist(const V1, V2: TVector): Double; assembler; asm // ---------------------------------------- // Максимально оптимизированная версия // Вход: EAX = V1, EDX = V2 // Выход: ST(0) = евклидово расстояние // ---------------------------------------- push esi push edi mov esi, eax // ESI = V1 mov edi, edx // EDI = V2 // ---------- Быстрая проверка на nil ---------- test esi, esi jz @ret_zero test edi, edi jz @ret_zero // ---------- Получение и сравнение длин ---------- mov eax, [esi-4] // EAX = Length(V1) cmp eax, [edi-4] // сравниваем с Length(V2) jne @ret_zero test eax, eax jz @ret_zero // ---------- Основной алгоритм ---------- mov ecx, eax // ECX = длина (счётчик для остатка) shr eax, 2 // EAX = количество четверок xorps xmm0, xmm0 // xmm0 = 0 // ---------- Цикл по 4 элемента ---------- test eax, eax jz @single push ebx // сохраняем EBX только если нужен цикл mov ebx, eax @quad_loop: movupd xmm1, [esi] movupd xmm2, [edi] movupd xmm3, [esi+16] movupd xmm4, [edi+16] subpd xmm1, xmm2 subpd xmm3, xmm4 mulpd xmm1, xmm1 mulpd xmm3, xmm3 addpd xmm0, xmm1 addpd xmm0, xmm3 add esi, 32 add edi, 32 dec ebx jnz @quad_loop pop ebx @single: // ---------- Обработка оставшихся элементов ---------- and ecx, 3 jz @combine @single_loop: movsd xmm1, [esi] movsd xmm2, [edi] subsd xmm1, xmm2 mulsd xmm1, xmm1 addsd xmm0, xmm1 add esi, 8 add edi, 8 dec ecx jnz @single_loop @combine: movhlps xmm1, xmm0 addsd xmm0, xmm1 sqrtsd xmm0, xmm0 sub esp, 8 movlpd [esp], xmm0 fld qword ptr [esp] add esp, 8 pop edi pop esi ret @ret_zero: fldz pop edi pop esi ret end; --- С проверками выравнивания: Код (ASM): function EuclidDist_SSE(const V1, V2: TVector): Double; assembler; asm // ---------------------------------------- // 1. ПРОЛОГ // ---------------------------------------- push ebx push esi push edi push ebp // ---------------------------------------- // 2. ПРОВЕРКА ДАННЫХ // ---------------------------------------- @validate: test eax, eax jz @error_exit test edx, edx jz @error_exit mov esi, [eax + TVector.FData] // получаем данные mov edi, [edx + TVector.FData] test esi, esi jz @error_exit test edi, edi jz @error_exit mov ebx, [eax + TVector.FLength] // длина cmp ebx, [edx + TVector.FLength] jne @error_exit test ebx, ebx jz @error_exit // ---------------------------------------- // 3. ВЫЧИСЛЕНИЯ (КРАСИВО И ЭФФЕКТИВНО) // ---------------------------------------- @compute: // Сохраняем длину mov ebp, ebx // EBP = общая длина // Инициализация аккумуляторов (4 независимых для конвейера) xorps xmm0, xmm0 xorps xmm1, xmm1 xorps xmm2, xmm2 xorps xmm3, xmm3 // Проверка выравнивания для выбора оптимального пути mov eax, esi or eax, edi and eax, 15 jnz @use_unaligned // невыровненные -> unaligned путь // ---------- ВЫРОВНЕННЫЙ ПУТЬ (ОПТИМАЛЬНЫЙ) ---------- mov ecx, ebp shr ecx, 2 // количество четверок jz @aligned_remainder @aligned_quad_loop: // Загружаем 4 элемента из V1 (выровненно!) movapd xmm4, [esi] // элементы 0-1 movapd xmm5, [esi+16] // элементы 2-3 // Загружаем 4 элемента из V2 (выровненно!) movapd xmm6, [edi] movapd xmm7, [edi+16] // Вычисления с минимальными зависимостями subpd xmm4, xmm6 subpd xmm5, xmm7 mulpd xmm4, xmm4 mulpd xmm5, xmm5 // Накопление в разные регистры (конвейер!) addpd xmm0, xmm4 addpd xmm1, xmm5 add esi, 32 add edi, 32 dec ecx jnz @aligned_quad_loop @aligned_remainder: // Суммируем аккумуляторы addpd xmm0, xmm1 addpd xmm2, xmm3 addpd xmm0, xmm2 // Обработка остатка (0-3 элемента) mov ecx, ebp and ecx, 3 jz @aligned_sum @aligned_rem_loop: movsd xmm4, [esi] movsd xmm5, [edi] subsd xmm4, xmm5 mulsd xmm4, xmm4 addsd xmm0, xmm4 add esi, 8 add edi, 8 dec ecx jnz @aligned_rem_loop @aligned_sum: jmp @combine_and_sqrt @use_unaligned: // ---------- НЕВЫРОВНЕННЫЙ ПУТЬ (универсальный) ---------- mov ecx, ebp shr ecx, 2 jz @unaligned_remainder @unaligned_quad_loop: // Невыровненная загрузка (медленнее, но работает везде) movupd xmm4, [esi] movupd xmm5, [esi+16] movupd xmm6, [edi] movupd xmm7, [edi+16] subpd xmm4, xmm6 subpd xmm5, xmm7 mulpd xmm4, xmm4 mulpd xmm5, xmm5 addpd xmm0, xmm4 addpd xmm1, xmm5 add esi, 32 add edi, 32 dec ecx jnz @unaligned_quad_loop @unaligned_remainder: addpd xmm0, xmm1 addpd xmm2, xmm3 addpd xmm0, xmm2 mov ecx, ebp and ecx, 3 jz @combine_and_sqrt @unaligned_rem_loop: movsd xmm4, [esi] movsd xmm5, [edi] subsd xmm4, xmm5 mulsd xmm4, xmm4 addsd xmm0, xmm4 add esi, 8 add edi, 8 dec ecx jnz @unaligned_rem_loop @combine_and_sqrt: // ---------- ФИНАЛЬНАЯ ОБРАБОТКА ---------- // Горизонтальное суммирование (красиво!) movhlps xmm1, xmm0 addsd xmm0, xmm1 // Квадратный корень sqrtsd xmm0, xmm0 // Перенос в FPU для возврата sub esp, 8 movlpd [esp], xmm0 fld qword ptr [esp] add esp, 8 jmp @success_exit // ---------------------------------------- // 4. УСПЕШНЫЙ ВЫХОД // ---------------------------------------- @success_exit: jmp @epilog // ---------------------------------------- // 5. ОШИБОЧНЫЙ ВЫХОД // ---------------------------------------- @error_exit: fldz // возвращаем 0 // ---------------------------------------- // 6. ЭПИЛОГ // ---------------------------------------- @epilog: pop ebp pop edi pop esi pop ebx ret end; --- Что-то типа такого, без avx, с xmm0-xmm7 с prefetch, без багов. Не обмазываясь выравниванием. --- Здесь боты вообще не нужны. На васме люди шахматные движки в уме пишут под разные инструкции и разные процессоры. Может кто-то из местной элиты ранее писал чтото подобное. --- --- Сообщение объединено, 26 фев 2026 --- Даже без prefetch. prefetch тоже не нужон. --- Сообщение объединено, 26 фев 2026 --- --- Сообщение объединено, 26 фев 2026 --- Код (ASM): function EuclidDist(...): Double; assembler; asm // ---------------------------------------- // 1. ПРОЛОГ - сохранение регистров // ---------------------------------------- // ---------------------------------------- // 2. ИНИЦИАЛИЗАЦИЯ // - получить длину массива // - установить указатели // - обнулить аккумуляторы // ---------------------------------------- // ---------------------------------------- // 3. ОСНОВНОЙ ЦИКЛ // - обрабатывать по 8 элементов за итерацию // - использовать предвыборку // - накапливать в 6 аккумуляторов // ---------------------------------------- // ---------------------------------------- // 4. ОБРАБОТКА ОСТАТКА // - 0-7 оставшихся элементов // - скалярная обработка // ---------------------------------------- // ---------------------------------------- // 5. СУММИРОВАНИЕ АККУМУЛЯТОРОВ // - сложить все частичные суммы // - вычислить x² + y² - 2xy // ---------------------------------------- // ---------------------------------------- // 6. КВАДРАТНЫЙ КОРЕНЬ // ---------------------------------------- // ---------------------------------------- // 7. ВОЗВРАТ РЕЗУЛЬТАТА // - перенести из XMM в FPU // ---------------------------------------- // ---------------------------------------- // 8. ЭПИЛОГ - восстановление регистров // ---------------------------------------- end; --- Сообщение объединено, 26 фев 2026 --- Формула вычислений Код (Text): sum = 0 for i = 0 to n-1 diff = a[i] - b[i] sum = sum + diff * diff result = sqrt(sum) --- Сообщение объединено, 26 фев 2026 --- Примерная структура: Код (ASM): function EuclidDist(const V1, V2: TVector): Double; assembler; asm // ---------------------------------------- // СТРУКТУРА ФУНКЦИИ // ---------------------------------------- // ======================================== // 1. ПРОЛОГ - сохранение регистров // ======================================== push ebx push esi push edi push ebp // ======================================== // 2. ПРОВЕРКА ДАННЫХ // ======================================== @check_data: // Проверка на nil test eax, eax jz @error_exit test edx, edx jz @error_exit // Получение длины mov ecx, [eax - 4] // длина V1 test ecx, ecx jz @error_exit // Проверка совпадения длин cmp ecx, [edx - 4] jne @error_exit // ======================================== // 3. ЗАГРУЗКА ДАННЫХ // ======================================== mov esi, eax // указатель на V1 mov edi, edx // указатель на V2 mov ebx, ecx // сохраняем длину в ebx mov ebp, ecx // также сохраняем в ebp (для остатка) // ======================================== // 4. ВЫЧИСЛЕНИЯ (ОСНОВНОЙ БЛОК) // ======================================== @compute: // Инициализация аккумуляторов xorps xmm0, xmm0 xorps xmm1, xmm1 xorps xmm2, xmm2 xorps xmm3, xmm3 // Обработка четверками (4 Double = 32 байта) mov eax, ebx shr eax, 2 // количество четверок jz @process_remainder xor edx, edx // смещение @loop_quad: // Загрузка 4 элементов из V1 movupd xmm4, [esi + edx] // элементы 0-1 movupd xmm5, [esi + edx + 16] // элементы 2-3 // Загрузка 4 элементов из V2 movupd xmm6, [edi + edx] // элементы 0-1 movupd xmm7, [edi + edx + 16] // элементы 2-3 // Вычисления для первой пары subpd xmm4, xmm6 mulpd xmm4, xmm4 addpd xmm0, xmm4 // Вычисления для второй пары subpd xmm5, xmm7 mulpd xmm5, xmm5 addpd xmm1, xmm5 // Переход к следующим 4 элементам add edx, 32 dec eax jnz @loop_quad // Суммирование аккумуляторов addpd xmm0, xmm1 addpd xmm2, xmm3 addpd xmm0, xmm2 @process_remainder: // Обработка остатка (0-3 элемента) mov eax, ebp and eax, 3 // остаток jz @combine_results mov ecx, eax mov edx, ebp sub edx, ecx // индекс начала остатка shl edx, 3 // пересчет в байты @rem_loop: movsd xmm4, [esi + edx] movsd xmm5, [edi + edx] subsd xmm4, xmm5 mulsd xmm4, xmm4 addsd xmm0, xmm4 add edx, 8 dec ecx jnz @rem_loop @combine_results: // Горизонтальное суммирование movhlps xmm1, xmm0 addsd xmm0, xmm1 // Квадратный корень sqrtsd xmm0, xmm0 // ======================================== // 5. ВЫХОД ПРИ НОРМАЛЬНОМ ЗАВЕРШЕНИИ // ======================================== @success_exit: // Перенос результата в FPU sub esp, 8 movlpd [esp], xmm0 fld qword [esp] add esp, 8 jmp @epilog // ======================================== // 6. ВЫХОД ПРИ ОШИБКЕ // ======================================== @error_exit: fldz // возвращаем 0.0 // ======================================== // 7. ЭПИЛОГ - восстановление регистров // ======================================== @epilog: pop ebp pop edi pop esi pop ebx ret end;
Код (ASM): function EuclidDist(const V1, V2: TVector): Double; assembler; asm // ----------------------------------------------------------------- // 1. Пролог – сохраняем регистры, которые обязаны сохранять // ----------------------------------------------------------------- push esi push edi // ----------------------------------------------------------------- // 2. Проверка корректности входных данных // ----------------------------------------------------------------- test eax, eax jz @ret_zero test edx, edx jz @ret_zero mov ecx, [eax - 4] // длина V1 test ecx, ecx jz @ret_zero cmp ecx, [edx - 4] // сравниваем с длиной V2 jne @ret_zero // ----------------------------------------------------------------- // 3. Получаем указатели на данные (длина уже в ECX) // ----------------------------------------------------------------- mov esi, eax // esi = указатель на V1[0] mov edi, edx // edi = указатель на V2[0] // ----------------------------------------------------------------- // 4. Инициализация аккумуляторов // ----------------------------------------------------------------- xorps xmm0, xmm0 xorps xmm1, xmm1 xorps xmm2, xmm2 xorps xmm3, xmm3 // ----------------------------------------------------------------- // 5. Основной цикл – обрабатываем по 8 элементов (4 пары Double) за итерацию // ----------------------------------------------------------------- mov eax, ecx shr eax, 3 // eax = количество полных восьмёрок (n div 8) jz @@HandleRemainder xor edx, edx // edx = смещение в байтах @@MainLoop: // Загружаем первые 4 элемента (2 пары) из V1 и V2 movupd xmm4, [esi + edx] // xmm4 = V1[i+1], V1[i] movupd xmm5, [edi + edx] // xmm5 = V2[i+1], V2[i] movupd xmm6, [esi + edx + 16] // xmm6 = V1[i+3], V1[i+2] movupd xmm7, [edi + edx + 16] // xmm7 = V2[i+3], V2[i+2] // Вычисляем для первой пары subpd xmm4, xmm5 mulpd xmm4, xmm4 addpd xmm0, xmm4 // Вычисляем для второй пары subpd xmm6, xmm7 mulpd xmm6, xmm6 addpd xmm1, xmm6 // Загружаем следующие 4 элемента (3-ю и 4-ю пары) movupd xmm4, [esi + edx + 32] // xmm4 = V1[i+5], V1[i+4] movupd xmm5, [edi + edx + 32] // xmm5 = V2[i+5], V2[i+4] movupd xmm6, [esi + edx + 48] // xmm6 = V1[i+7], V1[i+6] movupd xmm7, [edi + edx + 48] // xmm7 = V2[i+7], V2[i+6] subpd xmm4, xmm5 mulpd xmm4, xmm4 addpd xmm2, xmm4 subpd xmm6, xmm7 mulpd xmm6, xmm6 addpd xmm3, xmm6 // ---------- Предварительная выборка следующих данных ---------- prefetcht0 [esi + edx + 64] // загружаем в кэш следующие 64 байта из V1 prefetcht0 [edi + edx + 64] // загружаем в кэш следующие 64 байта из V2 // -------------------------------------------------------------- // Переходим к следующим 8 элементам (64 байта) add edx, 64 dec eax jnz @@MainLoop // ----------------------------------------------------------------- // 6. Суммируем аккумуляторы // ----------------------------------------------------------------- addpd xmm0, xmm1 addpd xmm2, xmm3 addpd xmm0, xmm2 // ----------------------------------------------------------------- // 7. Обработка остатка (0..7 элементов) // ----------------------------------------------------------------- @@HandleRemainder: mov eax, ecx and eax, 7 // остаток от деления на 8 jz @@Combine mov edx, ecx sub edx, eax // edx = индекс первого остаточного элемента shl edx, 3 // переводим в байты @@RemLoop: movsd xmm4, [esi + edx] movsd xmm5, [edi + edx] subsd xmm4, xmm5 mulsd xmm4, xmm4 addsd xmm0, xmm4 // добавляем к младшей половине xmm0 add edx, 8 dec eax jnz @@RemLoop // ----------------------------------------------------------------- // 8. Горизонтальное сложение (получаем одно число в xmm0) // ----------------------------------------------------------------- @@Combine: movhlps xmm1, xmm0 // xmm1 = старшая половина xmm0 addsd xmm0, xmm1 // xmm0[0] = сумма всех квадратов // ----------------------------------------------------------------- // 9. Квадратный корень // ----------------------------------------------------------------- sqrtsd xmm0, xmm0 // ----------------------------------------------------------------- // 10. Возврат результата в FPU // ----------------------------------------------------------------- sub esp, 8 movlpd [esp], xmm0 fld qword ptr [esp] add esp, 8 // ----------------------------------------------------------------- // 11. Эпилог – восстановление регистров // ----------------------------------------------------------------- pop edi pop esi ret @ret_zero: fldz pop edi pop esi ret end; //EuclidDist --- Сообщение объединено, 26 фев 2026 --- Вместо Код (ASM): test eax, eax // проверка V1 на nil jz @ret_zero test edx, edx // проверка V2 на nil jz @ret_zero mov ecx, [eax - 4] // длина V1 test ecx, ecx // проверка длины V1 jz @ret_zero cmp ecx, [edx - 4] // сравнение длин jne @ret_zero Код (ASM): mov ecx, [eax - 4] // сразу берем длину V1 test ecx, ecx // проверка длины V1 = 0? jz @@ZeroResult cmp ecx, [edx - 4] // сравнение длин jne @@ZeroResult --- Сообщение объединено, 26 фев 2026 --- Зря убрал ebx в самом начале. Код (ASM): function EuclidDist(const V1, V2: TVector): Double; assembler; asm // EAX = V1 ptr, EDX = V2 ptr push ebx push esi push edi // --- nil checks (âàæíî äëÿ íà䏿íîñòè) test eax, eax jz @@Zero test edx, edx jz @@Zero // --- lengths mov ecx, [eax-4] // len1 test ecx, ecx jz @@Zero cmp ecx, [edx-4] // len2 jne @@Zero mov esi, eax // p1 mov edi, edx // p2 // ebx = blocks of 8 doubles, eax = remainder mov ebx, ecx shr ebx, 3 // /8 mov eax, ecx and eax, 7 // %8 // accumulators xorps xmm0, xmm0 xorps xmm1, xmm1 xorps xmm2, xmm2 xorps xmm3, xmm3 test ebx, ebx jz @@Tail @@Loop: // 8 doubles (64 bytes) per iteration, 4 independent accumulators movupd xmm4, [esi] movupd xmm5, [edi] subpd xmm4, xmm5 mulpd xmm4, xmm4 addpd xmm0, xmm4 movupd xmm4, [esi+16] movupd xmm5, [edi+16] subpd xmm4, xmm5 mulpd xmm4, xmm4 addpd xmm1, xmm4 movupd xmm4, [esi+32] movupd xmm5, [edi+32] subpd xmm4, xmm5 mulpd xmm4, xmm4 addpd xmm2, xmm4 movupd xmm4, [esi+48] movupd xmm5, [edi+48] subpd xmm4, xmm5 mulpd xmm4, xmm4 addpd xmm3, xmm4 add esi, 64 add edi, 64 dec ebx jnz @@Loop // combine accumulators addpd xmm0, xmm1 addpd xmm2, xmm3 addpd xmm0, xmm2 @@Tail: test eax, eax jz @@Finish @@TailLoop: movsd xmm4, [esi] movsd xmm5, [edi] subsd xmm4, xmm5 mulsd xmm4, xmm4 addsd xmm0, xmm4 add esi, 8 add edi, 8 dec eax jnz @@TailLoop @@Finish: // ãîðèçîíòàëüíàÿ ñóììà äâóõ lane movhlps xmm1, xmm0 addsd xmm0, xmm1 sqrtsd xmm0, xmm0 // âåðíóòü Double â ST(0) (Delphi Win32) sub esp, 8 movlpd [esp], xmm0 fld qword ptr [esp] add esp, 8 pop edi pop esi pop ebx ret @@Zero: fldz pop edi pop esi pop ebx ret end; //EuclidDist --- Сообщение объединено, 26 фев 2026 --- Код (ASM): EuclidDist(const V1, V2: TVector): Double; assembler; asm // EAX = V1 data ptr (or nil) // EDX = V2 data ptr (or nil) test eax, eax jz @@Zero test edx, edx jz @@Zero mov ecx, [eax-4] // len1 test ecx, ecx jz @@Zero cmp ecx, [edx-4] // len2 jne @@Zero // ---- теперь можно сохранять callee-saved, т.к. точно работаем дальше push ebx push esi push edi mov esi, eax // p1 mov edi, edx // p2 // ebx = blocks of 8 doubles, edx = remainder (0..7) mov ebx, ecx shr ebx, 3 and ecx, 7 // остаток оставим в ECX xorps xmm0, xmm0 xorps xmm1, xmm1 xorps xmm2, xmm2 xorps xmm3, xmm3 // ---- optional aligned fast-path mov eax, esi or eax, edi test eax, 15 jnz @@Unaligned @@Aligned: test ebx, ebx jz @@Tail @@LoopA: movapd xmm4, [esi] movapd xmm5, [edi] subpd xmm4, xmm5 mulpd xmm4, xmm4 addpd xmm0, xmm4 movapd xmm4, [esi+16] movapd xmm5, [edi+16] subpd xmm4, xmm5 mulpd xmm4, xmm4 addpd xmm1, xmm4 movapd xmm4, [esi+32] movapd xmm5, [edi+32] subpd xmm4, xmm5 mulpd xmm4, xmm4 addpd xmm2, xmm4 movapd xmm4, [esi+48] movapd xmm5, [edi+48] subpd xmm4, xmm5 mulpd xmm4, xmm4 addpd xmm3, xmm4 add esi, 64 add edi, 64 dec ebx jnz @@LoopA jmp @@AfterMain @@Unaligned: test ebx, ebx jz @@Tail @@LoopU: movupd xmm4, [esi] movupd xmm5, [edi] subpd xmm4, xmm5 mulpd xmm4, xmm4 addpd xmm0, xmm4 movupd xmm4, [esi+16] movupd xmm5, [edi+16] subpd xmm4, xmm5 mulpd xmm4, xmm4 addpd xmm1, xmm4 movupd xmm4, [esi+32] movupd xmm5, [edi+32] subpd xmm4, xmm5 mulpd xmm4, xmm4 addpd xmm2, xmm4 movupd xmm4, [esi+48] movupd xmm5, [edi+48] subpd xmm4, xmm5 mulpd xmm4, xmm4 addpd xmm3, xmm4 add esi, 64 add edi, 64 dec ebx jnz @@LoopU @@AfterMain: addpd xmm0, xmm1 addpd xmm2, xmm3 addpd xmm0, xmm2 @@Tail: test ecx, ecx jz @@Finish @@TailLoop: movsd xmm4, [esi] movsd xmm5, [edi] subsd xmm4, xmm5 mulsd xmm4, xmm4 addsd xmm0, xmm4 add esi, 8 add edi, 8 dec ecx jnz @@TailLoop @@Finish: movhlps xmm1, xmm0 addsd xmm0, xmm1 sqrtsd xmm0, xmm0 // return Double via x87 ST(0) sub esp, 8 movsd qword ptr [esp], xmm0 fld qword ptr [esp] add esp, 8 pop edi pop esi pop ebx ret @@Zero: fldz ret end;
Есть такое: Код (Text): function FastInvSqrt(x: Double): Double; var i: Int64 absolute x; y: Double; begin y := x; i := $5FE6EB50C7B537A9 - (i shr 1); // магическая константа для Double Result := y * (1.5 - (x * 0.5 * y * y)); // одна итерация Ньютона end; Смысл такой - вообще не использовать блок математики, что бы шедулер его не сохранял(~fxsave). --- Сообщение объединено, 27 фев 2026 --- Посмотрел разницу, за 8s отношение числа итераций simd/fpu = 8. Тоесть sse быстрее почти на порядок. Это не много, если вычисления за короткий интервал времени.
6, но не суть. prefetch смысла вообще наверно нет проверять. Норм вариант - распараллелить вычисления в потоках.
Если несложно, можешь написать пример? Самый луший способ обмена мыслями это исходник. Программа тоже мысль. Говорят если она весит немного, килобайта 3(как test.exe) то безопасна. Брат. Я нуб. И мне лучше исходник. --- Сообщение объединено, 27 фев 2026 --- Современным процессорам это будет только мешать. Современным процессорам в моем нубском исполнении это будет как х*уй в спину.
Кстати. Когда искал инфу по улучшения, наткнулся на опесорсную либу для вычислений https://github.com/OpenMathLib/OpenBLAS