X^Y (X,Y - double) , средствами FPU

Тема в разделе "WASM.BEGINNERS", создана пользователем Swat2k, 13 дек 2011.

  1. Swat2k

    Swat2k Дима

    Публикаций:
    0
    Регистрация:
    14 май 2007
    Сообщения:
    64
    Интересует есть ли у кого, оптимизированная версия процедуры FpuXexpY из fpulib (masm) по размеру ? Вообще задача состоит в том что бы сделать X^Y ( где X,Y - double ) средствами FPU.

    Думал считать по известной формуле : X^Y = 1+ F2XM1(FYL2X(Y,X)) , но что то оно не так, не пойму что упускаю.
     
  2. Swat2k

    Swat2k Дима

    Публикаций:
    0
    Регистрация:
    14 май 2007
    Сообщения:
    64
    Сильно тупанул, заработался видимо

    Прикладываю рабочий код (может кому то и пригодиться) , теперь интересует оптимизация.

    Код (Text):
    1.     ; Вычисляет формулу : (3/4) ^ ((x^2-x-1)/x) - 9/16
    2.     ; средствами FPU
    3.  
    4.  
    5.     format PE console
    6.     entry OEP
    7.      
    8.     include 'win32a.inc'
    9.      
    10.     ;======================================
    11.     section '.data' data readable writeable
    12.     ;======================================
    13.      
    14.     hello_msg db 'Press input, x = ',0
    15.     x_is_zero db 'Sorry, x not must be zero!',13,10,0
    16.     f_x_out   db 'f(x) = %lf',13,10,0
    17.  
    18.     h_c_out   dd  0h
    19.     h_c_in    dd  0h
    20.     tmp   dd  0h
    21.     floatX    dq  ?
    22.     _3    dq  3.0
    23.     _4    dq  4.0
    24.     _9    dq  9.0
    25.     _16   dq  16.0
    26.     f_x   dq  ?
    27.  
    28.     intput_buffer db 255 dup (0)
    29.     output_buffer db 255 dup (0)
    30.  
    31.     ;=======================================
    32.     section '.code' code readable executable
    33.     ;=======================================
    34.  
    35.     OEP:
    36.     finit                               ; Включаем FPU
    37.     invoke GetStdHandle,STD_OUTPUT_HANDLE               ; Получаем хендл вывода консоли
    38.     mov [h_c_out],eax                       ; и сохраняем его в переменной
    39.     invoke GetStdHandle,STD_INPUT_HANDLE                ; Так же поступаем и с хендлом
    40.     mov [h_c_in],eax                        ; ввода консоли.
    41.     invoke lstrlen,hello_msg                    ; Определяем длинну строки hello_msg
    42.     invoke WriteConsole,[h_c_out],hello_msg,eax, tmp,NULL       ; Выводим её
    43.     invoke ReadConsole,[h_c_in],intput_buffer,255,tmp,NULL      ; Ждём окончания ввода
    44.     ;invoke MessageBox,0,intput_buffer,intput_buffer,0
    45.  
    46.     cinvoke atof, intput_buffer                 ; atof ф-я из msvcrt.dll ( Ansi String to Float )
    47.  
    48.  
    49.  
    50.     pushad                              ; Сохраняем все регистры и флаги CPU
    51.  
    52.     ; Теперь в ST(0) находиться X
    53.     ftst                ; теперь проверим X на ноль
    54.     fstsw ax            ; сохраняем слово состояния регистра swr в регистр ax
    55.     fwait
    56.     sahf                ; записываем содержимое AH в младший байт регистра EFLAGS
    57.     je is_zero          ; теперь можем провести сравнение ja : ST0 > 0
    58.                     ;                                 jb : ST0 < 0
    59.                     ;                                 je : ST0 == 0
    60.  
    61.  
    62.  
    63.     fld ST0             ; Теперь в ST(0) и ST(1) содержиться наш X
    64.     fmul ST0,ST1            ; Теперь в ST(0) = x^2
    65.     fsub ST0,ST1            ; Теперь в ST(0) = x^2 - x
    66.     fld1                ; Теперь в ST(0) = 1   , ST(1) =  x^2 - x
    67.     fsub ST1,ST0            ; ST(1) = x^2 - x - 1
    68.     fxch ST2
    69.     fdiv ST1,ST0            ; ST(1) = ( x^2 - x - 1 ) / x
    70.     fxch ST1            ; ST(0) = ( x^2 - x - 1 ) / x
    71.     fld qword[_3]
    72.     fld qword[_4]
    73.     fdiv ST1,ST0        ; ST(1) = 3/4
    74.     fxch ST2
    75.     fxch ST1
    76.     fyl2x
    77.     f2xm1
    78.     fld1
    79.     fadd  ST1,ST0         ; ST(1) =  (3/4) ^ ( ( x^2 - x - 1 ) / x )
    80.     fld qword[_9]
    81.     fld qword[_16]
    82.     fdiv ST1,ST0        ; ST(1) = 9/16
    83.     fxch ST3
    84.     fsub ST0,ST1
    85.     fstp qword[f_x]                      ; сохраняем переменную и очищаем ST(0)
    86.  
    87.  
    88.  
    89.     popad               ; Восстанавливаем все регистры и флаги CPU
    90.  
    91.     push dword [f_x+4]
    92.     push dword [f_x]
    93.     push f_x_out
    94.     call [printf]
    95.     add esp,4*3         ; Выводим наш результат f_x
    96.  
    97.     invoke ReadConsole,[h_c_in],intput_buffer,1,tmp,NULL  ; ждём нажатия клавишы и завершаемся
    98.     jmp @exit
    99.  
    100.     is_zero:
    101.             invoke lstrlen,x_is_zero
    102.             invoke WriteConsole,[h_c_out],x_is_zero,eax, tmp,NULL
    103.  
    104.     @exit:
    105.     stdcall [ExitProcess],0
    106.  
    107.  
    108.     ; Таблица импорта ф-ий
    109.     section '.idata' import data readable writeable
    110.  
    111.     library kernel32,'kernel32.dll',\
    112.     user32, 'user32.dll',\
    113.     msvcrt, 'msvcrt.dll'
    114.  
    115.       import  msvcrt,\
    116.       atof,'atof',\
    117.       printf,'printf'
    118.  
    119.  
    120.     include '\api\kernel32.inc'
    121.     include '\api\user32.inc'
     
  3. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Видимо, да, т.к. вычислять константы 3/4 и 9/16, вместо того чтобы сразу задать 0.75 и 0.5625 - это "супер-оптимизация"