· Начало · Отвђтить · Статистика · Поиск · FAQ · Правила · Установки · Язык · Выход · WASM.RU · Noir.Ru ·

 WASM Phorum —› WASM.A&O —› Простенькая задачка-головоломка на оптимизацию

Посл.отвђт Сообщен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:10

sum:;(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