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

 WASM Phorum —› WASM.A&O —› Микроупражнение: числа Фибоначчи

. 1 . 2 . >>

Посл.отвђт Сообщенiе


Дата: Июн 14, 2004 22:58:12

Числа Фибоначчи - это последовательность целых чисел, определяемая следующим образом:

F0=0
F1=1
Fn+2=Fn+1+Fn, n - целое неотрицательное число.

Задан адрес, обозначим его ADDR, по которому нужно поместить таблицу чисел Фибоначчи от F0 до F47, размер чисел - dword. То есть по адресу ADDR поместить значение F0=0, по адресу ADDR+4 - значение F1=1, и т. д.

Оптимизировать код по размеру. Предлагая вариант, указывать размер в байтах...

Справка ("откуда взялось число 47"): F47 - максимальное число Фибоначчи, влезающее в беззнаковый dword (но не помещающееся в знаковый).


Дата: Июн 15, 2004 00:24:53

        mov edi,table   ;5

        xor eax,eax     ;2
        lea ecx,[eax+1] ;3
    .fib:
        stosd           ;1
        xchg eax,ecx    ;1
        add eax,ecx     ;2
        jnc .fib        ;2

Итого 11 байт без команды загрузки адреса таблицы


Дата: Июн 15, 2004 00:29:37 · Поправил: volodya

Я, с вашего позволения, начну как новичок в этих делах. Самый очевидный (и не совсем правильный, кстати) метод выглядит так:
	unsigned n1 = 0;
	unsigned n2 = 1;
	unsigned n3 = 0;

	do{
		n3 = n1 + n2;
		n1 = n2;
		n2 = n3;
		printf("%u\n", n3);
	}while(n3 < INT_MAX);



Что сводится к следующему ассемблерному коду:
xor	 ebx, ebx
mov	 edi, 1
@again:
lea	 esi, DWORD PTR [edi+ebx]
mov	 ebx, edi
mov	 edi, esi
cmp	 esi, -2147483648	; 80000000H
jb	 @again


Итого: 15 байт из которых хренова туча именно на cmp.
Т.е. нужно заменить cmp/jb на что-нибудь менее ужасное, что детектило бы overflow. Так можно отыграть где-то три байта или что-то около.

Сейчас будет второй вариант.


Дата: Июн 15, 2004 00:29:57

Black_mirror

Ты меня опередил, я хотел начать :((((


Дата: Июн 15, 2004 00:32:21

Вариант с массивом, в котором убирается проверка на overflow в принципе, выглядит так:
    int i;
    int fib[47];

    fib[0] = 1;
    fib[1] = 1;

    for (i = 2; i < 47; i++)
    {
        fib[i] = fib[i-1] + fib[i-2];
    }


Однако индексы сводят отказ от проверки на ноль :( Или даже на минус. Щаз поглядим как оно будет с поинтерами работать :)


Дата: Июн 15, 2004 01:22:38 · Поправил: volodya

Оптимизированный вариант на С без индексов выглядит так:
    int fib[47];
	
    fib[46] = '$';
    fib[0] = 1;
    fib[1] = 1;

    int *fib_p = &fib[2];
    while(*fib_p != '$')
    {
        *fib_p = *(fib_p-2) +  *(fib_p-1);
	fib_p++;
    }


Само тело цикла сводится к:
@cool:
mov	 edx, DWORD PTR [eax-8]   ;3
add	 edx, DWORD PTR [eax-4]   ;3
mov	 DWORD PTR [eax], edx     ;2
mov	 edx, DWORD PTR [eax+4]   ;3
add	 eax, 4                   ;3
cmp	 edx, ecx                 ;2
jne	 @cool                    ;3


Дата: Июн 15, 2004 02:24:39

xadd используйте.


Дата: Июн 15, 2004 03:52:51

Сократил вариант Black_mirror на байт.
Не пойму только, как XADD может уменьшить размер, она же 3 байта?
    	mov	edi, ADDR	; 5	
    	xor	eax, eax	; 2	
    	cdq			; 1	
    	inc	edx		; 1	
    @@:	stosd			; 1	
    	xadd	eax, edx	; 3	
    	jnb	@b		; 2	


Дата: Июн 15, 2004 14:00:36

volodya
>fib[0] = 1;
нужно fib[0] = 0; :)


Дата: Июн 15, 2004 15:56:03 · Поправил: vaskovich

    mov   edi,addr

    sub   eax,eax     ; 2
    stc               ; 1
@@: stosd             ; 1
    adc   eax,[edi-8] ; 3
    jnc   @b          ; 2


Если предположить, что по addr-4 лежит ноль, то 9 байт.. иначе 10. Я седня туплю хуже обычного, извините если что :(


Дата: Июн 15, 2004 17:01:42

Не пойму только, как XADD может уменьшить размер, она же 3 байта?
:)
Ну вот ты сам мне ответь убедившись, что xadd эвкиваленто будет по функцианальности и размеру паре команд add и xchg ты сам то что предпочтёшь написать в программе?
vaskovich - не сработает.


Дата: Июн 15, 2004 17:46:06

The Svin
Ээ.. почему? У меня все работало, т.е. получилась последовательность 0,1,1,2,3,5,8,13,... Или ты имеешь ввиду что такое мое допущение тут никому нафиг не нужно?
В целом разъясни фразу.


Дата: Июн 15, 2004 18:22:21

ozzman

Неа. И так работает :)
Да, и еще.
while(n3 < INT_MAX + 1)


надо заменить на:
while(!(n3 & INT_MAX + 1))


отыграем три байта.


Дата: Июн 15, 2004 18:48:17

Нельзя предполагать, что кто-то вам что-то положит в память, загрузит базовый адрес в регистр, или установит подходящее значение флага направления...


Дата: Июн 15, 2004 20:04:35

vaskovich
ваш код выдает правильные числа до F31 включительно.

. 1 . 2 . >>


Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.044