Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

Disccusion: YAC, Yet Another Calculator; RPN

Mikhail Pasternak
Registered User
Join date: 1 Oct 2005
Posts: 54
01-19-2007 12:50
CODE
// YAC, Yet Another Calculator
// by Mikhail Pasternak
// Jan 18, 2007
//
// An RPN Calculator, with vector and rotation operations
//
// Enter operands and operators by chat (0); the stack is displayed with floating text above the calculator; other communications are sent to owner by llOwnerSay().
// The columns of the display, left to right, are referred to as X, Y, Z, S
// The X column is composed of 4 floating point numbers, from bottom to top, to as x, y, z, s
// Almost all scalar operations are on x, y, z, s. Vector and quanterion operations on on X, Y, Z, S
// Note that all operands and operators must be separated by or comma.
// Look at the else-if lists of execute_basic_command(), execute_misc_command(), execute_trig_command(), execute_vector_command() to see what operators are available
// To list x, y, z, s in Chat, use the operator "say" (good for cut and paste0
//
// If there is enough interest, I will write an instruction manual

integer TIME_SECONDS = 600 ; // Time that script turns off from non-use
vector color_vector = <1.0, 1.0, 1.0> ; // Color of floating text
float color_alpha = 1.0 ; // Opacity of floating text

integer handle = 0 ;

float E_constant = 2.718281 ;
float trig_arg_mult ;
float trig_result_mult ;
integer Xflag ;

list stack_list ; // List 16 floating point numbers (stack does not grow ar shrink)

float copy(integer index) // Copy stack element
{
return( llList2Float(stack_list, index) ) ;
}

push(float value) // Push float onto stack
{
stack_list = [value] + stack_list ;
stack_list = llDeleteSubList(stack_list, 4, 4) ;
}

put(integer index, float value) // Replace current float at index, with value
{
stack_list = llListReplaceList(stack_list, [value], index, index) ;
}

stk_adj_2(float value) // Delete top 2 floats, put value on top of stack, duplicate
// entry s to exit s
{
stack_list = llDeleteSubList(stack_list, 0, 1) ;
stack_list = [value ] + llListInsertList(stack_list, [ llList2Float(stack_list, 1) ], 1) ;
}

drop() // Delete top float, duplicate entry s to exit s
{
stack_list = llDeleteSubList(stack_list, 0, 0) ;
stack_list = llListInsertList(stack_list, [ llList2Float(stack_list, 2) ], 2) ;
}

degrees() // Set trig functions to accept and report in degrees
{
trig_arg_mult = DEG_TO_RAD ;
trig_result_mult = RAD_TO_DEG ;
}

radians() // Set trig functions to accept and report in radions
{
trig_arg_mult = 1.0 ;
trig_result_mult = 1.0 ;
}

// OPERATORS - start

integer execute_basic_command(string command)
{
integer found = TRUE ;

command = llToLower(llGetSubString(command, 0, 2)) ; // Truncate strings to 3 chars
// max; set to lower case

if(command == "+")
{
stk_adj_2(copy(0) + copy(1)) ;
}
else if(command == "-")
{
stk_adj_2(copy(1) - copy(0)) ;
}
else if(command == "*")
{
stk_adj_2(copy(0) * copy(1)) ;
}
else if(command == "/")
{
stk_adj_2(copy(1) / copy(0)) ;
}
else if(command == "^")
{
stk_adj_2( llPow(copy(1), copy(0)) ) ;
}
else if(command == "/%") // Integer results of y/, y mod x placed in x, y (resp)
{
integer temp0 = (integer)llFabs(copy(0)) ;
integer temp1 = (integer)llFabs(copy(1)) ;
put(0, temp1 / temp0 ) ;
put(1, temp1 % temp0 ) ;
}
else if(command == "d") // duplicate x; entry s is lost
{
stack_list = llDeleteSubList(llListInsertList(stack_list, [ copy(0) ], 0), 4, 4) ;
}
else if(command == "dd") // duplicate X; entry S is lost
{
stack_list = llDeleteSubList(llListInsertList(stack_list, llList2List(stack_list, 0, 3), 0), 16, 19) ;
}
else if(command == "r") // Rotate X stack; x->y, y->z, z->s, s->x
{
stack_list = llDeleteSubList(llListInsertList(stack_list, [ copy(0) ], 4), 0, 0) ;
}
else if(command == "rr") // Rotate columns; X->Y, Y->Z, Z->S, S->X
{
stack_list = llDeleteSubList(llListInsertList(stack_list, llList2List(stack_list, 0, 3), 16), 0, 3) ;
}
else if(command == "s") // Swap x and y
{
float temp = copy(0) ;
put(0, copy(1) ) ;
put(1, temp ) ;
}
else if(command == "ss") // Swap X and Y
{
stack_list = llDeleteSubList(llListInsertList(stack_list, llList2List(stack_list, 0, 3), 8), 0, 3) ;
}
else if(command == "@0") // Push Y.x; copy first element of Y and then push on stack
{
push(copy(4)) ;
}
else if(command == "@1")
{
push(copy(5)) ;
}
else if(command == "@2")
{
push(copy(6)) ;
}
else if(command == "@3")
{
push(copy(7)) ;
}
else if(command == "!0") // Put x into first element place of Y (x is consumed)
{
put(4, copy(0)) ;
drop() ;
}
else if(command == "!1")
{
put(5, copy(0)) ;
drop() ;
}
else if(command == "!2")
{
put(6, copy(0)) ;
drop() ;
}
else if(command == "!3")
{
put(7, copy(0)) ;
drop() ;
}
else
{
found = FALSE ;
}

return(found) ;
}

float memory_0 ;
float memory_1 ;
float memory_2 ;
float memory_3 ;

integer execute_misc_command(string command)
{
integer found = TRUE ;

command = llToLower(llGetSubString(command, 0, 2)) ;

if(command == "abs") // Absolute value
{
put(0, llFabs(copy(0)) ) ;
}
if(command == "e")
{
push(E_constant ) ;
}
else if(command == "fra") // Fractional part of number
{
float temp = copy(0) ;
put(0, temp - (integer)temp) ;
}
else if(command == "int") // Integer part of number
{
put(0, (integer)copy(0) ) ;
}
else if(command == "ln")
{
put(0, llLog(copy(0)) ) ;
}
else if(command == "log")
{
put(0, llLog10(copy(0)) ) ;
}
else if(command == "neg")
{
put(0, -copy(0)) ;
}
else if(command == "rou") // Round off fraction
{
put(0, llRound(copy(0)) ) ;
}
else if(command == "ran") // Random number between 0 and operand
{
put(0, llFrand(copy(0)) ) ;
}
else if(command == "rc0") // Push contents of memory_0 onto the stack
{
push(memory_0) ;
}
else if(command == "rc1")
{
push(memory_1) ;
}
else if(command == "rc2")
{
push(memory_2) ;
}
else if(command == "rc3")
{
push(memory_3) ;
}
else if(command == "say") // Say the 4 elements of X to owner (use in cut & paste)
{
Xflag = TRUE ;
}
else if(command == "sqr") // Square root
{
put(0, llSqrt(copy(0)) ) ;
}
else if(command == "st0") // Store x in memory_0
{
memory_0 = copy(0) ;
}
else if(command == "st1")
{
memory_1 = copy(0) ;
}
else if(command == "st2")
{
memory_2 = copy(0) ;
}
else if(command == "st3")
{
memory_3 = copy(0) ;
}
else
{
found = FALSE ;
}

return(found) ;
}

integer execute_trig_command(string command)
{
integer found = TRUE ;

command = llToLower(llGetSubString(command, 0, 2)) ;

if(command == "aco") // Arc-cosine
{
put(0, llAcos(copy(0)) * trig_result_mult ) ;
}
else if(command == "asi")
{
put(0, llAsin(copy(0)) * trig_result_mult ) ;
}
else if(command == "ata")
{
put(0, llAtan2(copy(0), 1.0) * trig_result_mult ) ;
}
else if(command == "cos")
{
put(0, llCos(copy(0) * trig_arg_mult) ) ;
}
else if(command == "deg") // Accept/report degress for trig functions
{
degrees() ;
}
else if(command == "pi")
{
push(PI) ;
}
else if(command == "rad") // Accept/report radians for trig functions
{
radians() ;
}
else if(command == "sin")
{
put(0, llSin(copy(0) * trig_arg_mult) ) ;
}
else if(command == "tan")
{
put(0, llTan(copy(0) * trig_arg_mult) ) ;
}
else
{
found = FALSE ;
}

return(found) ;
}

vector CCopy3(integer index) // Copy first 3 elements of a Column into a vector (3-typle)
{
index *= 4 ;
return( < copy(index), copy(index+1), copy(index+2) > ) ;
}

rotation CCopy4(integer index) // Copy 4 elements of a Column into a quanterion (4-tuple)
{
index *= 4 ;
return( < copy(index), copy(index+1), copy(index+2), copy(index+3) > ) ;
}

SStk_adj_2_3(vector value) // Delete X & Y, push vector on stack as a column, duplicate
// entry S to exit S
{
float temp = copy(3) ; // X.s is saved and inserted into exit X.s

stack_list = llDeleteSubList(stack_list, 0, 7) ;
stack_list = [ value.x, value.y, value.z, temp ] + llListInsertList(stack_list, llList2List(stack_list, 4, 7), 4) ;
}

SStk_adj_2_4(rotation value) // Delete X & Y, push vector on stack as a column, // duplicate S to exit S
{
stack_list = llDeleteSubList(stack_list, 0, 7) ;
stack_list = [ value.x, value.y, value.z, value.s] + llListInsertList(stack_list, llList2List(stack_list, 4, 7), 4) ;
}

integer execute_vector_command(string command)
{
integer found = TRUE ;

command = llToLower(llGetSubString(command, 0, 2)) ;

if(command == "++") // Add components of X and Y (quanterion)
{
SStk_adj_2_4(CCopy4(1) + CCopy4(0)) ;
}
else if(command == "--") // Subtract components of X from components of Y (quanterion)
{
SStk_adj_2_4(CCopy4(1) - CCopy4(0)) ;
}
else if(command == "**") // Multiply components of Y vector by scalar x
{
SStk_adj_2_3(CCopy3(1) * copy(0)) ;
}
else if(command == "dot" || command == ".") // Dot product of X and Y (vectors)
{
SStk_adj_2_3( < CCopy3(1) * CCopy3(0), 0.0, 0.0 > ) ;
}
else if(command == "cro" || command == "x") // Cross product of X and Y (vectors)
{
SStk_adj_2_3(CCopy3(1) % CCopy3(0)) ;
}
else if(command == "//") // Divide the components of vector Y by the scalar x
{
SStk_adj_2_3(CCopy3(1) / copy(0)) ;
}
else if(command == "*ro") // Ratate Y (vector) by X (quaternion)
{
SStk_adj_2_3(CCopy3(1) * CCopy4(0)) ;
}
else if(command == "*rr") // Multiply Y (quaternion) by X (quaternion)
{
SStk_adj_2_4(CCopy4(1) * CCopy4(0)) ;
}
else if(command == "/ro") // Ratate Y (vector) by inverse of X (quaternion)
{
SStk_adj_2_3(CCopy3(1) / CCopy4(0)) ;
}
else if(command == "/rr") // Multiply Y (quaternion) by inverse of X (quaternion)
{
SStk_adj_2_4(CCopy4(1) / CCopy4(0)) ;
}
else if(command == "rrc") // Push memory_0 thru memory_3 as 4-tuple on the stack
// memory_0 goes in x of X
{
stack_list = [ memory_0, memory_1, memory_2, memory_3 ] + llDeleteSubList(stack_list, 12, 15) ;
}
else if(command == "sst") // Copy x, y, z, s to memory_0 thru memory_3
{
memory_0 = copy(0) ;
memory_1 = copy(1) ;
memory_2 = copy(2) ;
memory_3 = copy(3) ;
}
else if(command == "sss") // Swap X with memory_0 thru memory_3
{
float temp ;

temp = memory_0 ;
memory_0 = copy(0) ;
put(0, temp) ;

temp = memory_1 ;
memory_1 = copy(1) ;
put(1, temp) ;

temp = memory_2 ;
memory_2 = copy(2) ;
put(2, temp) ;

temp = memory_3 ;
memory_3 = copy(3) ;
put(3, temp) ;
}
else if(command == ">") // Swap x and z, used for vector input
// e.g. 1 2 3 4 becomes 3 2 1 4
{
float temp = copy(0) ;
put(0, copy(2)) ;
put(2, temp) ;
}
else if(command == ">>") // Swap x and z, used for rotation input (quanterion)
// e.g. 1 2 3 4 becomes 4 3 2 1
{
float temp = copy(0) ;
put(0, copy(3)) ;
put(3, temp) ;

temp = copy(1) ;
put(1, copy(2)) ;
put(2, temp) ;
}
else
{
found = FALSE ;
}

return(found) ;
}

// OPERATORS - end

string pad(integer count, string padding) // Return a string consisting of count copies
// of padding
{
string result ;
integer i ;

if(count <= 0)
{
result = "" ;
}
else if(count == 1)
{
result = padding ;
}
else if(count == 2)
{
result = padding + padding ;
}
else if(count == 3)
{
result = padding + padding + padding ;
}
else
{
for(i=0, result="" ; i < count ; i++)
{
result += padding ;
}
}

return(result) ;
}

string make_exp_string(integer exp) // Produce display string of exponent
// [+|-] + {0} + <num>
{
string sign_string ;
if(exp >= 0)
{
sign_string = "+" ;
}
else
{
sign_string = "-" ;
}
exp = llAbs(exp) ;

string padding = "" ;
if(exp < 10)
{
padding = "0" ;
}

return("e" + sign_string + padding + (string)exp) ;
}

string display_float(float value) // Create a display string of floating point number
// (String should be 14-15 chars long, trail space)
// Manitissa is 7 decimal digits (about) of precision // Display as a decimal or scientific notation
{
integer exp ;
string sign_string ;
string num_string ;


if(llGetSubString((string)value, 0, 0) == "-") // Save sign as a string
{
sign_string = "-" ;
}
else
{
sign_string = " " ; // 2 spaces for plus
}
value = llFabs(value) ;

// (strings should be 12 characters in length
if(value == 0.0) // Handle 0.0 as a special case
{
num_string = "0.000000 " ;
}
else if(value >= 1e7) // Large number, scientific notation
{
exp = llFloor(llLog10(value)) ;
num_string = (string)(value * llPow(10, -exp)) + make_exp_string(exp) ;
}
else if(value >= 1.0) // 9,999,999 to 1.0 - regular decimal notation
{
num_string = llGetSubString((string)value, 0, 7) + " " ;
}
// else if(value >= .0001)
// {
//exp = -llFloor(llLog10(value)) ;
// num_string = (string)(value * 1e4) ;
// integer tindex = llSubStringIndex( num_string, ".") ;
//num_string = llDeleteSubString(num_string, tindex, tindex) ;
// num_string = llGetSubString(num_string, 0, 6) ;
// num_string = " 0." + pad(exp - 1, "0") + num_string + pad(4-exp, " ") ;
//}
else // value < .1 and value != 0.0
{
exp = llFloor(llLog10(value)) ;
num_string = (string)(value * llPow(10, -exp)) + make_exp_string(exp) ;
}

num_string = sign_string + num_string + " " ;

return(num_string) ;
}

display_stack()
{
integer i ;
string tstring ;

if(Xflag == TRUE) // say x, y, z, s to owner (see "say", in execute_misc_command())
{
llOwnerSay( display_float( copy(0)) + " "
+ display_float( copy(1)) + " "
+ display_float( copy(2)) + " "
+ display_float( copy(3)) ) ;
}
Xflag = FALSE ;

// Display the stack, rint 4 rows, each 4 wide
for(i=3, tstring="" ; i >= 0 ; i--)
{
tstring = tstring + "\n"
+ display_float(llList2Float(stack_list, i ))
+ display_float(llList2Float(stack_list, i+ 4))
+ display_float(llList2Float(stack_list, i+ 8))
+ display_float(llList2Float(stack_list, i+12)) ;
}

llSetText(tstring, color_vector, color_alpha) ;

llOwnerSay((string)llGetFreeMemory() + " bytes free Memory") ;
}

turn_display_off()
{
llSetText("", <0,0,0>, 0) ;
}

turn_on()
{
llListenRemove(handle) ;
llSetTimerEvent(TIME_SECONDS) ;
handle = llListen(0, "", llGetOwner(), "") ;
llOwnerSay("Calculator ON") ;
display_stack() ;
}

turn_off()
{
llListenRemove(handle) ;
llSetTimerEvent(0) ;
llOwnerSay("Calculator OFF") ;
turn_display_off() ;
}

initialize()
{
stack_list = [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0 ] ;
memory_3 = memory_2 = memory_1 = memory_0 = 0.0 ;
Xflag = FALSE ;
degrees() ;
llOwnerSay("Initializing") ;
turn_on() ;
}

default
{

on_rez(integer num_param)
{
initialize() ;
}

state_entry()
{
initialize() ;
}

touch_start(integer total_number)
{
if(llGetOwner() == llDetectedKey(0)) // only owner can turn calculator ON
{
turn_on() ;
}
}

listen(integer channel, string name, key id, string message)
{
if(channel == 0 && id == llGetOwner()) // Only listen for owner on CH 0
{
// Parse input line, demlited by spaces and commas
list strings = llParseString2List( message, [ " ", "," ], [] ) ;
integer length = llGetListLength(strings) ; // how many strings
integer i ;
for(i=0 ; i < length ; i++) // Process each string
{
string next_string = llList2String(strings, i) ;
// Truncate string to lower case, 3 chars max
if(llToLower(llGetSubString(next_string, 0, 2)) == "off")
{
turn_off() ; // Turn calculator off
return ;
}
// See if string is a command
if( execute_basic_command(next_string) == FALSE )
if( execute_misc_command(next_string) == FALSE )
if( execute_trig_command(next_string) == FALSE )
if( execute_vector_command(next_string) == FALSE )
{
push( (float)next_string ) ; // Else convert to float (0 on fail)
// and push on stack
//llOwnerSay("pushing") ;
}

// check the stack size must be 16
integer stack_size = llGetListLength(stack_list) ;
if(stack_size != 16)
{
llOwnerSay("Stack Error: size is " + (string)stack_size ) ;
stack_list = [ 0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0 ] ;
jump Listen_1 ; // Jump out of loop on stack erro
}
}
@Listen_1 ;
display_stack() ; // Now Display stack in floating text
llSetTimerEvent(TIME_SECONDS) ; // reset key timer
}
}

timer()
{
turn_off() ; // times up, no activity, turn off Calculator
}

}
Nada Epoch
The Librarian
Join date: 4 Nov 2002
Posts: 1,423
Original Thread
01-21-2007 16:51
/15/ec/161515/1.html#post1388657
_____________________
i've got nothing. ;)