|
|
| Посл.отвђт | Сообщенiе |
|
|
Дата: Окт 14, 2004 13:41:48 В одном форуме прочитал такую задачку. Дано N. Необходимо посчитать sum(N/i), где i от 1 до N. Деление целочисленное. Например для 10: 10/1 = 10 10/2 = 5 10/3 = 3 10/4 = 2 10/5 = 2 10/6 = 1 10/7 = 1 10/8 = 1 10/9 = 1 10/10 = 1 Итого: 10+5+3+2+2+1+1+1+1+1 = 27 Требуется написать максимально быструю программу. Максимальное значение N - 10^12. |
|
|
Дата: Окт 14, 2004 13:52:39 Как написать с применением 16 разрядных регистров или 32х,или же и то и то? |
|
|
Дата: Окт 14, 2004 14:19:51 · Поправил: tasman Daniil Ну во превых можно сократить вычисления в два раза: все результаты полученные целочисленным делением на числа >= (N%2)+1 всегда будут 1 |
|
|
Дата: Окт 14, 2004 15:56:27 А я блин поизвращался: Buffer db MAX dup(0) mov eax,N mov bl,I mov esi,offset buffer mov edi,esi round: div bl mov word ptr[esi],eax ; частное test edx,edx ; есть ли остаток jne short next jmps exit_round next: mov eax,edx add esi,4 jmp round exit_round: sub esi,4 add edx,word ptr[esi] test edi,esi jne exit_round |
|
|
Дата: Окт 15, 2004 07:57:10sum:;(esp +4 - i64)
fldcw [.cwnear]
fild qword [esp+4] ;N
fld st0
fsqrt ;N sqrt(N)
fldcw [.cwdown]
frndint
sub esp,8
fist dword [esp] ;int(sqrt(N))
fmul st0,st0
fchs ;N sum=-int(sqrt(N))^2
.l0:
fild dword [esp] ;N sum i
fdivr st0,st2 ;N sum N/i
frndint
fadd st1,st0 ;N sum+N/i N/i
faddp st1,st0 ;N sum+2N/i
dec dword [esp]
jnz .l0
fstp st1
fistp qword [esp]
pop eax
pop edx
ret 8
.cwnear dw 33Fh
.cwdown dw 73Fh |
|
|
Дата: Окт 19, 2004 10:24:02 · Поправил: leo В принципе, вариант Black_mirror неплохо решает задачу алгоритмически, но конечно не "максимально быстро" в смысле вычислений. Можно попытаться пооптимизировать вычисления для больших N. Если брать N хотя бы 1000 и более, то увидим что при уменьшении i от исходного значения int(sqrt(N)) значения k=int(N/i) меняются медленно и вполне предсказуемо: сначала на 1, потом начинается "вкрапление" 2, потом устойчивая разница на 2 и т.д. Поэтому идея заключается в том, чтобы при больших начальных i заменить длительную операцию деления (на пеньках, что div, что fdiv+frndint - не менее 60 тактов) на целочисленные операции add\sub\cmp для получения очередного k. Наиболее просто задачка решается для разности соседних k < 3, а это около 30% от общего числа итераций, т.к. N/(i-1)-N/i > 2 при i < sqrt(N/2) ~ 0.7*sqrt(N). Пусть на входе имеем i = int(sqrt(N)) k = i r = N-i*i - остаток от деления N/iТогда на следующем шаге для i=i-1 будем иметь r=r+k ;остаток при том же k, т.к.r=N-(i-1)*k =(N-i*k)+k inc k ;прогнозируемое значение k r=r-i ;остаток при k=k+1 cmp r,i ;проверяем не нужно ли еще увеличить k jl @@sum inc k r=r-i ;если развивать идею, то здесь в принципе можно вставить еще проверку на r >= i ;и либо еще увеличивать k, либо найти его делением исходного r на i @@sum: sum=sum+k dec iЦикл выполняется до некоторого порогового i, затем переход на прямое вычисление по Black_mirror. При ограниченном i только вычисление sum требует 64битных чисел, остальные операции с r32. |
|
|
Дата: Окт 20, 2004 17:57:15 Подсказка: частичные суммы гармонического ряда некоторым образом связаны с логарифмами... ;) |
|
|
Дата: Ноя 16, 2004 08:12:08 · Поправил: getoff sum=N*exp(1) |
|
Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.107 |