; Jade Yu Cheng
; ICS 312
; Assignment 7 Exercise 2
; April 24, 2009
; driver_ex2.c defines a main function. It takes two command-line arguments,
; both of them are floating point numbers. The program defines a function, f,
; which takes as argument a float and returns a float. In the program as it is
; written this function is the f(x) = x2 + 10/x function. The program calls a
; function called compute_derivative. This function takes three arguments. The
; first argument is a "function pointer", that is the address of a function.
; The second argument is a float, which is the point at which the function's
; derivative should be computed (x). The third argument is a float, which is
; the level of precision at which the derivative should be computed (epsilon).
; You can see in the program that the function passed to compute_derivative is
; function f, that the value of x comes from the first command-line argument,
; and that the value of epsilon comes from the second command-line argument.
%include "asm_io.inc"
%define f dword [ebp + 8] ; 1st argument the function pointer
%define x dword [ebp + 12] ; 2nd argument the value to compute
%define e dword [ebp + 16] ; 3rd argument user specified percision
%define fresult dword [ebp - 4] ; 1st local var stores f(x) value
%define h dword [ebp - 8] ; 2nd local var stores h
%define param dword [ebp - 12] ; 3rd local var stores x + h
%define two dword [ebp - 16] ; 4th local var stores integer 2
%define diff dword [ebp - 20] ; 5th local var stores (f(x+h)-f(x))/h
%define tmp dword [ebp - 24] ; 6th local var a temp space for diff
segment .text
global compute_derivative
compute_derivative:
push ebp ; setup
mov ebp, esp ; setup
sub esp, 24 ; setup spare space for 6 local vars
push x ; push x as f's param
call f ; call f
add esp, 4 ; clean up stack after function call
fstp fresult ; store f(x) value into fresult
mov two, 2 ; store 2 in a four byte quatity
mov h, 2 ; initialize h, it will be divided by 2
mov diff, 0 ; initialize diff
fild h ; convert h into a float quantity
fstp h
compute_loop:
fld h ; st0 = h_old
fidiv two ; st0 = h_old/2
fst h ; h_new = h_old/2
fadd x ; st0 = h_new + x
fstp param ; fp stack is empty at this point
push param ; call f with h_new + x
call f
add esp, 4 ; clean up stack after function call
fsub fresult ; st0 = f(h_new + x) - f(x)
fdiv h ; st0 = (f(h_new + x) - f(x))/h
fabs ; |st0 = (f(h_new + x) - f(x))/h|
fst tmp ; store the diff_new in tmp for now
fsub diff ; st0 = diff_old - diff_new
fabs ; st0 = |diff_old - diff_new|
fcomp e ; compare st0 with epsilon
fstsw ax
sahf
jna compute_loop_end ; jmp to terminate if st0 < epsilon
fld tmp ; otherwise diff_new = tmp
fstp diff
jmp compute_loop
compute_loop_end:
fld tmp ; put diff_new as the return value
add esp, 24
mov esp, ebp ; clean up
pop ebp ; clean up
ret ; clean up