package Farith; main::Register(package_name()); ############################################################### # File: Farith.cmd # # This program will allow for floating point # operations in Adept. # # Note: This function will not work if the parameters past in are # not strings. Since Adept does not provide for floating # point numbers, these numbers must be treated as if they were # strings. This package must be used for ALL floating point # operations. # # Items considered when writing this program: # 1. a+b = a+b if a > 0 and b > 0 # 2. a+b = a-b if a > 0 and b < 0 # 3. a+b = b-a if a < 0 and b > 0 # 4. a+b = -(a+b) if a < 0 and b < 0 # # 5. a-b = a-b if a > 0 and b > 0 # 6. a-b = a+b if a > 0 and b < 0 # 7. a-b = -(a+b) if a < 0 and b > 0 # 8. a-b = b-a if a < 0 and b < 0 # ############################################################### # Begin forward declarations function fop() {} function fadd() {} function fmult() {} function fdiv() {} function fsub() {} function fround() {} function fcomp() {} function fmax(a,b) { return (fcomp(a,b)>1?b:a) } function fmin(a,b) { return (fcomp(a,b)>1?a:b) } function is_float(a) { return match(a, '^[+-]?[0-9]*[.]?[0-9]+$') } # End forward declarations ################################################################ # This function will take an opeation as a parameter and perform # that operation. # Input: a, b (float numbers) # op (an operation: + - * /) # place (place to round to in this format ".01" or ".00001" etc.) ################################################################ function fop(a,op,b,place='.0001') { local result; # determine which operation to perform and execute it. switch (op) { case '+': result = fadd(a,b); break; case '-': result = fsub(a,b); break; case '*': result = fmult(a,b); break; case '/': result = fdiv(a,b); break; } result = fround(result,place); return result; } ################################################################ # This function will add two floating point numbers a and b. # 1) x[1] and y[1] are on the left side of the decimal point. # 2) x[2] and y[2] are on the right side of the decimal point. # 3) x[1],x[2],y[1],y[2] MUST be 9 digits or less for the return value # to be reliable. ################################################################ function fadd(a,b) { local x[],y[],s[]; local total; local len; # difference in size of numbers after decimal point local i; # counter # need to make sure there is a leading 0 if no left hand side if (substr(a,1,1) == '.') { a="0".a; } if (substr(b,1,1) == '.') { b="0".b; } # determine what we will really do as per considerations above if (a > 0 && b < 0) { # make b positive b=substr(b,2,length(b)); total = fsub(a,b); return total; } if (a < 0 && b > 0) { # make a positive a=substr(a,2,length(a)); total = fsub(b,a); return total; } if (a < 0 && b < 0) { # make both numbers positive a=substr(a,2,length(a)); b=substr(b,2,length(b)); total = "-".fadd(a,b); return total; } # both number are positive so add normally split(a,x,'.'); split(b,y,'.'); len=length(x[2])-length(y[2]); # make sure x[2] and y[2] are appropriate sizes to be added correctly # we pad with 0's to ensure this condition if (len > 0) { for (i=0;ilen;i--) { x[2] .= "0"; } } s[1] = x[1]+y[1]; s[2] = x[2]+y[2]; # we now check for a carry value if (length(s[2]) > length(x[2])) { # add carry value to s[1] s[1] += substr(s[2],1,1); # remove carry value from s[2] s[2] = substr(s[2],2,length(s[2])); } # truncate s[2] to get rid of trailing 0's while not the last number # after the decimal while (substr(s[2],length(s[2]),1)=='0' && length(s[2]) != 1) { s[2]=substr(s[2],1,length(s[2])-1); } total = s[1].".".s[2]; return total; } ########################################################## # This function will provide functionality to subtract # a floating point number from another floating point # number. # Input: a, b # Output: a-b ########################################################## function fsub(a,b) { local s[],x[],y[]; local total; # result to be returned local i; # counter # need to make sure there is a leading 0 if no left hand side if (substr(a,1,1) == '.') { a="0".a; } if (substr(b,1,1) == '.') { b="0".b; } # determine what we will really do as per considerations above if (a > 0 && b < 0) { # make b positive b=substr(b,2,length(b)); total = fadd(a,b); return total; } if (a < 0 && b > 0) { # make a positive a=substr(a,2,length(a)); total = "-".fadd(a,b); return total; } if (a < 0 && b < 0) { # make both numbers positive a=substr(a,2,length(a)); b=substr(b,2,length(b)); total = fsub(b,a); return total; } # both number are positive so compare then subtract # if b > a then compute -(b-a) if (fcomp(a,b) == 2) { # we reassign a and b because they don't get passed correctly to # fsub. I have no idea why this is the case. local c=a; local d=b; total = "-".fsub(d,c); return total; } # split a and b into components split(a,x,"."); split(b,y,"."); local len=length(x[2])-length(y[2]); # make sure x[2] and y[2] are appropriate sizes to be subtracted correctly # we pad with 0's to ensure this condition if (len > 0) { for (i=0;ilen;i--) { x[2] .= "0"; } } # depending on relationship of a and b we have to do different things # compare the two decimal components and subtract if (x[2] >= y[2]) # subtract normally { s[2] = x[2]-y[2]; } else # we need to borrow from x[1] { x[1]--; x[2] = "1".x[2]; s[2] = x[2] - y[2]; } # once we have s[2] we need to make sure that leading zeros weren't truncated i=0; while (i<(length(x[2]) - length(s[2]))) { s[2]=0.s[2]; i++; } i=0; while (i<(length(y[2]) - length(s[2]))) { s[2]=0.s[2]; i++; } # truncate s[2] to get rid of trailing 0's while not the last number # after the decimal. while (substr(s[2],length(s[2]),1)=='0' && length(s[2]) != 1) { s[2]=substr(s[2],1,length(s[2])-1); } # now subtract left side of decimal s[1] = x[1] - y[1]; # put together into total total = s[1].".".s[2]; return total; } ########################################################## # This function will multiply two floating point numbers # Input: a,b # Output: a*b # # Note: this function is limited in the sense that the length # of the output cannot be greater than 10 digits. This # is an adept feature. Adept cannot handle numbers # with more than 10 digits. So if the output were to have # more than 10 digits the result would be inaccurate. ########################################################## function fmult(a,b) { local x[],y[],l,r; # host variables local product; # it is what it says it is local i; # counter variable # split a and b into components split(a,x,"."); split(b,y,"."); local places = length(x[2]) + length(y[2]); # where the decimal will go # re-form numbers with no decimal point a=x[1].x[2]; b=y[1].y[2]; # multiply product=a*b; # re-insert decimal point r = substr(product,1,(length(product)-places)); l = substr(product,(length(product)-places+1),length(product)); # reconstruct product product = r.".".l; return product; } ########################################################## # This function will divide two floating point numbers # Input: a, b # Output: a/b # # Note: This algorithm is rather inefficient, however, # it will serve our purposes for Adept. ########################################################## function fdiv(a,b) { local x[],y[]; # host variables local i; # counter local numer, div; # numerator divisor local temp; # variable to hold string numer local result="", count; # current result, counter local places = 10; # first we shift each number over so that the divisor # has no decimal points in it split(b,y,"."); split(a,x,"."); local len = length(y[2]); # number of decimal places in divisor div = y[1].y[2]; # numer is temporary and will change, this is the number we subtract # from to divide temp = x[1].substr(x[2],1,len); if (len >= length(x[2])) { for (i=length(x[2]);i= 0) { numer -= div; count++; } if (numer == 0) { return count; } # begin putting result together result .= count."."; # loop through number of places of percision for (i=0;i= 0) { numer -= div; count++; } # add to result result .= count; if (numer == 0) { return result; } } return result; } ########################################################## # This function will round a floating point number to the # specified place. # Input: a (float number), place (i.e. .0001 or .1 etc) # Output: rounded number # # Note: this function does not provide for rounding to # whole numbers. ########################################################## function fround(a,place) { local x[]; # parts of a local rounded; # rounded number local len, i; # length, and counter # remove decimal point from place place = substr(place,2,length(place)); # split a into parts split(a,x,"."); # make sure the percision is less than the value of a if (length(place) >= length(x[2])) { return a; } # round decimal part of a x[2]=substr(x[2],1,(length(place)+1)); # need this length to ensure enough leading 0's later len = length(place); x[2]+=5; # rounding part x[2] = substr(x[2],1,length(x[2])-1); i=0; while (i < (len-length(x[2]))) { x[2] = '0'.x[2]; i++; } rounded = x[1].".".x[2]; return rounded; } ########################################################## # This function will compare two floating point numbers # Input: a,b (numbers to compare) # Output: 0 if a == b # 1 if a > b # 2 if a < b ########################################################## function fcomp(a,b) { local x[],y[]; # to contain split variables # split numbers at decimal point split(a,x,"."); split(b,y,"."); local len=length(x[2])-length(y[2]); # make sure x[2] and y[2] are appropriate sizes to be added correctly # we pad with 0's to ensure this condition if (len > 0) { for (i=0;ilen;i--) { x[2] .= "0"; } } # check left side of decimal if (x[1] > y[1]) { return 1; } if (y[1] > x[1]) { return 2; } else # check right side of decimal { if (x[2] > y[2]) { return 1; } if (x[2] < y[2]) { return 2; } } # we fell through so a equals b return 0; }