-
-
Save BGMcoder/2d6e1ef7a88adc5c5c661498a369714b to your computer and use it in GitHub Desktop.
my calculator script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
ResetNormalFormats(){ | |
global | |
if(usedecimalplaces){ | |
normalfloatformat := "0." . decimalplaces | |
}else{ | |
normalfloatformat := "0." . maxdecimalplaces | |
} | |
;W := W="" ? "0.6g" : "0." . W | |
;SetFormat Integer, %FormI% | |
SetFormat Integer, D ;decimal format | |
SetFormat FLOAT, %normalfloatformat% | |
} | |
;------adapted from monster 1.2------------(needs AHK 1.0.48+)-------------------------------------------------------------------------------------------------------------------- | |
;http://www.autohotkey.com/board/topic/15675-monster-evaluate-math-expressions-in-strings/ | |
; Containing HEX, Signed Binary ('11 = -1, '011 = 3), scientific numbers (1.2e+5) | |
; Assignments :=, preceding an expression. E.g: a:=1; b:=2; a+b | |
;Predefined variables are only accepted if listed in the keywords variables in gui.ahk | |
; Logic operators: !, ||, &&; ternary operator: (_?_:_); | |
; Relations: =,<>; <,>,<=,>= | |
; Binary operators: ~; |, ^, &, <<, >> | |
; Arithmetic operators: +, -; *, /, \ (or % = mod); ** (or @ = power) | |
; Output FORMAT: $x,$h: Hex; $b{W}: W-bit binary; | |
; ${k}: k-digit fixpoint, ${k}e,${k}g: k-digit scientific (Default $6g) | |
;I fixed this to return "" instead of 0 for incomplete expressions | |
;tobin() crashes the script | |
;$b is the inline flag for decimal -to- binary with answer as binary | |
;$h is the inline flag for decimal -to- hexadecimal with the answer as hex | |
;if x is discovered in the string, it is interepreted as hex with answer as dec | |
;preprocessed means that we have iterated over a certain part of the equation and already converted it to a solution | |
;this is necessary to fetch global variables into the Eval function | |
FetchGlobal(whatvar){ | |
thisval := % %whatvar% | |
return thisval | |
} | |
SetGlobal(whatvar, whatvalue){ | |
global | |
%whatvar% := whatvalue | |
} | |
;there is a limit to the math. | |
;ahk cannot process a number higher than 2**64-1, which is: 9223372036854775800.000000 on a 64bit system | |
;but on a 32bit system it is 2**32-1, which is: 4294967295.000000 | |
;if you reach that value, it just stops computing | |
Eval(x, byref whatcommand="") { ; non-recursive PRE/POST PROCESSING: I/O forms, numbers, ops, ";" | |
Local FORM, i, W, y, y1, y2, y3, y4 | |
Local preform, prex, pre, pre1, pre2 | |
FormI := A_FormatInteger, FormF := A_FormatFloat ;save the current number formats | |
;usedecimalplaces := fetchglobal("usedecimalplaces") | |
;usedivisionsign := fetchglobal("usedivisionsign") | |
SetFormat Integer, D ; decimal intermediate results! | |
;---------------Process Special Calculor Math Functions First (Maestrith)-------------------- | |
;this colourizes the letter combinations --> see gui.ahk | |
RegExReplace(x,"\(",,Count),replace:=[] | |
Loop,%count%{ | |
pos:=InStr(x,"(",0,0,A_Index)-1 | |
if((match:=hequation.2353(pos))>pos){ | |
text:=hequation.textrange(pos+1,match) | |
function:=hequation.textrange(hequation.2266(pos-1),hequation.2267(pos-1)) | |
if(keywordsSpecial2~="\b" function "\b"){ | |
new:=%function%(StrSplit(text,",")*) | |
replace.push({find:function "(" text ")",replace:new}) | |
;ToolTip,This was triggered %A_TickCount% | |
} | |
} | |
} | |
total:="" | |
for a,b in replace{ | |
;alert(b.find,b.replace) | |
total.=b.find " , " b.replace | |
x:=RegExReplace(x,"\Q" b.find "\E",b.replace) | |
} | |
;-------------------------------------------------------------------------------------------------------------------------------------- | |
;replace any fancy characters with their computable alternatives | |
;if(usedivisionsign){ | |
; x := RegExReplace(x,"÷","/") | |
;} | |
;-------------------------------------------------------------------------------------------------------------------------------------- | |
;Let's do some conversion modes before we begin calculating | |
RegExMatch(x, "\$(c|u|a|n|rfs|rf)(.*)", pre) | |
;x = input | |
;pre = regexmatch array | |
;pre1 = flag (that is, c or u) | |
;pre2 = value after flag | |
;prex = return value (we don't want to mess up x, just in case) | |
whatcommand := "" | |
preform := pre1 | |
StringReplace prex, x, %pre% ; remove $.. flag | |
if(preform){ | |
whatcommand := "$" . preform ;make sure to return the command so we can colour it with Enhance() | |
;CHARACTER TO ASCII CODE | |
;produce codepoints from characters | |
;type a character and get the ascii code | |
if(preform = "c"){ | |
loop,parse,pre2,,%a_space% | |
prex .= ord(a_loopfield) . " " | |
} | |
;CHARACTER TO UNICODE CODEPOINT | |
;type a character and get the unicode code point | |
;produce a character from this unicode code by inserting 0x before the code point supplied by the user | |
;we have to do tricks though to get the unicode code point | |
if(preform = "n"){ | |
loop,parse,pre2,,%a_space% | |
{ | |
thisnum := Format("{1:#x}", ord(a_loopfield)) | |
prex .= math_padnumber(thisnum,"00000","0") . " " | |
} | |
} | |
;UNICODE CODE TO CHARACTER | |
;produce a unicode character from its code | |
if(preform = "u"){ | |
loop,parse,pre2,%a_space% | |
{ | |
thiscode := a_loopfield | |
if(left(thiscode,2) != "0x") | |
thiscode := "0x" . thiscode | |
prex .= chr(thiscode) . " " | |
;provide some explanations for spaces which won't show in the solution | |
;https://www.cs.tut.fi/~jkorpela/chars/spaces.html | |
if(thiscode = "0x0020") | |
prex := "ascii space" | |
else if(thiscode = "0x2002") | |
prex := "en space" | |
else if(thiscode = "0x2003") | |
prex := "em space" | |
else if(thiscode = "0x2009") | |
prex := "thin space" | |
else if(thiscode = "0x00a0") | |
prex := "no-break space" | |
} | |
} | |
;ASCII CODE TO CHARACTER | |
;produce an ascii character from its code | |
if(preform = "a"){ | |
loop,parse,pre2,%a_space% | |
{ | |
if(a_loopfield = "32") | |
prex .= "[space]" | |
else | |
prex .= chr(a_loopfield) . " " | |
} | |
} | |
;ROUND FRACTION | |
;this is more of a convertor than a math function | |
if(preform = "rfs"){ | |
stringsplit, xrf, pre2,`,,%a_space% | |
prex := roundfraction(xrf1,xrf2,false) ;don't simplify | |
} | |
if(preform = "rf"){ | |
stringsplit, xrf, pre2,`,,%a_space% | |
prex := roundfraction(xrf1,xrf2,true) ;simplify | |
} | |
return prex | |
} | |
;-------------------------------------------------------------------------------------------------------------------------------------- | |
;Process math flags | |
RegExMatch(x, "\$(b|h)(\d*[eEgG]?)", y) | |
FORM := y1, W := y2 ; HeX, Bin, .{digits} output format | |
SetFormat FLOAT, 0.16 ; Full intermediate float precision | |
;SetFormat FLOAT, 0.16e ; Full intermediate float precision | |
StringReplace x, x, %y% ; remove $.. flag | |
if(FORM) | |
whatcommand := "$" . FORM | |
; convert hex numbers to decimal by checking for numbers with 0x in front of them | |
Loop | |
If RegExMatch(x, "i)(.*)(0x[a-f\d]*)(.*)", y) | |
x := y1 . y2+0 . y3 | |
Else Break | |
; convert binary numbers to decimal | |
Loop | |
If RegExMatch(x, "(.*)''([01]*)(.*)", y) | |
x := y1 . FromBin(y2) . y3 | |
Else Break | |
; convert unsigned binary numbers to decimal | |
Loop | |
If RegExMatch(x, "(.*)'([01]*)(.*)", y) | |
x := y1 . baseConvert(y2, "base2", "base10") . y3 | |
Else Break | |
; consider all numbers in equation are in hex and we will convert them to decimals | |
; if(FORM = "x"){ | |
; Loop | |
; If RegExMatch(x, "i)(.*)(.*[a-f].*)(.*)", y) | |
; x := y1 . baseConvert(y2, "base16", "base10") . y3 | |
; Else Break | |
; } | |
; add missing '.' before E (1e3 -> 1.e3) | |
x := RegExReplace(x,"(^|[^.\d])(\d+)(e|E)","$1$2.$3") | |
; literal scientific numbers between ‘ and ’ chars | |
x := RegExReplace(x,"(\d*\.\d*|\d)([eE][+-]?\d+)","‘$1$2’") | |
StringReplace x, x,`%, \, All ;; % -> \ (= MOD) | |
StringReplace x, x, **,@, All ; ** -> @ for easier process for exponents | |
StringReplace x, x, +, ±, All ; ± is addition | |
x := RegExReplace(x,"(‘[^’]*)±","$1+") ; ...not inside literal numbers | |
StringReplace x, x, -, ¬, All ; ¬ is subtraction | |
x := RegExReplace(x,"(‘[^’]*)¬","$1-") ; ...not inside literal numbers | |
; work on pre-processed sub expressions beginning with semicolon ; | |
Loop Parse, x, `; | |
y := Eval1(A_LoopField) | |
;y will be the result of the whole evaluation so far | |
;<<><><><><><>><><><>> | |
;after this point, we are operating on the solution | |
; return result of last sub-expression (numeric) | |
; convert output to binary | |
If (FORM = "b"){ | |
y := W ? ToBinW(Round(y),W) : ToBin(Round(y)) | |
; convert output to hex | |
}else if(FORM = "h") { | |
y := baseConvert(y, "base10", "base16") | |
;cleanup floating point numbers with too many 0's | |
}else{ | |
ResetNormalFormats() | |
y := rtrim(y, 0) | |
} | |
Return y | |
} | |
Eval1(x) { ; recursive PREPROCESSING of :=, vars, (..) [decimal, no ";"] | |
Local i, y, y1, y2, y3 | |
;This was originally in Monster calc, and allowed for some sort of user-defined function definition. There is a corresponding part at the end of Eval@(x) | |
; save function definition: f(x) := expr | |
; If RegExMatch(x, "(\S*?)\((.*?)\)\s*:=\s*(.*)", y) { | |
; f%y1%__X := y2, f%y1%__F := y3 | |
; Return | |
; } | |
;SPECIAL VARIABLES | |
; execute leftmost ":=" operator of a := b := ... | |
;here we exchange the values of special vars like pi, e, gallon, inch, etc. these vars start with "x" | |
;the colours for these words are set in strings in gui.ahk | |
If RegExMatch(x, "(\S*?)\s*:=\s*(.*)", y) { | |
y := "x" . y1 ; user vars internally start with x to avoid name conflicts | |
if(y = "xe"){ ;don't allow e to become a user variable | |
;I WISH THIS ALERT COULD BE MADE MODAL *AND* ONTOP - I can only get one or the other. | |
alert("Sorry, Friend, you can't use e for a variable`rThat letter is reserved for the Euler's Number",error,apptitle . " Error") | |
return error | |
}else{ | |
Return %y% := Eval1(y2) | |
} | |
} | |
; at this point there are no variables to the left of last ":=" | |
x := RegExReplace(x,"([\)’.\w]\s+|[\)’])([a-z_A-Z]+)","$1«$2»") ; op -> «op» | |
x := RegExReplace(x,"\s+") ; remove spaces, tabs, newlines | |
x := RegExReplace(x,"([a-z_A-Z]\w*)\(","'$1'(") ; func( -> 'func'( to avoid atan|tan conflicts | |
x := RegExReplace(x,"([a-z_A-Z]\w*)([^\w'»’]|$)","%x$1%$2") ; VAR -> %xVAR% | |
x := RegExReplace(x,"(‘[^’]*)%x[eE]%","$1e") ; in numbers %xe% -> e | |
x := RegExReplace(x,"‘|’") ; no more need for number markers | |
Transform x, Deref, %x% ; dereference all right-hand-side %var%-s | |
; find last innermost (..) | |
Loop { | |
If( RegExMatch(x, "(.*)\(([^\(\)]*)\)(.*)", y) ){ | |
;y1= whatever is before ( | |
;y2=whatever is between () | |
;y3=whatever is after () | |
;y4= | |
;evaltest(y1,y2,y3,y4,"() loop") | |
;test for operators to the left and right of the parenthesis, that is, in y1 and y3; if there are none, process it as multiplication by supplying * | |
if(regexmatch(y1,".*(\d$)",thisop) ){ | |
y1 := y1 . "*" | |
} | |
if(regexmatch(y3,"(^\d).*",thisop) ){ | |
y3 := "*" . y3 | |
} | |
x := y1 . Eval@(y2) . y3 ; replace (x) with value of x | |
}Else{ | |
Break | |
} | |
} | |
Return Eval@(x) | |
} | |
Eval@(x) { ; EVALUATE PRE-PROCESSED EXPRESSIONS [decimal, NO space, vars, (..), ";", ":="] | |
Local i, y, y1, y2, y3, y4 | |
; no more operators left | |
If x is number | |
Return x | |
; execute rightmost ?,: operator | |
RegExMatch(x, "(.*)(\?|:)(.*)", y) | |
IfEqual y2,?, Return Eval@(y1) ? Eval@(y3) : "" | |
IfEqual y2,:, Return ((y := Eval@(y1)) = "" ? Eval@(y3) : y) | |
; execute rightmost || operator | |
StringGetPos i, x, ||, R | |
IfGreaterOrEqual i,0, Return Eval@(SubStr(x,1,i)) || Eval@(SubStr(x,3+i)) | |
; execute rightmost && operator | |
StringGetPos i, x, &&, R | |
IfGreaterOrEqual i,0, Return Eval@(SubStr(x,1,i)) && Eval@(SubStr(x,3+i)) | |
; execute rightmost =, <> operator | |
RegExMatch(x, "(.*)(?<![\<\>])(\<\>|=)(.*)", y) | |
IfEqual y2,=, Return Eval@(y1) = Eval@(y3) | |
IfEqual y2,<>, Return Eval@(y1) <> Eval@(y3) | |
; execute rightmost <,>,<=,>= operator | |
RegExMatch(x, "(.*)(?<![\<\>])(\<=?|\>=?)(?![\<\>])(.*)", y) | |
IfEqual y2,<, Return Eval@(y1) < Eval@(y3) | |
IfEqual y2,>, Return Eval@(y1) > Eval@(y3) | |
IfEqual y2,<=, Return Eval@(y1) <= Eval@(y3) | |
IfEqual y2,>=, Return Eval@(y1) >= Eval@(y3) | |
; execute rightmost user operator (low precedence) | |
RegExMatch(x, "i)(.*)«(.*?)»(.*)", y) | |
;evaltest(y1,y2,y3,y4,"low precedence`r" . %y2%) | |
;evaltest(y1,y2,y3,y4,"func=" . %y2%) | |
If(IsFunc(y2) ){ | |
;y1=everthing before () | |
;y2=between () | |
;y3=solved equation after() | |
;y4= | |
Return %y2%(Eval@(y1),Eval@(y3)) ; predefined relational ops | |
} | |
StringGetPos i, x, |, R ; execute rightmost | operator | |
IfGreaterOrEqual i,0, Return Eval@(SubStr(x,1,i)) | Eval@(SubStr(x,2+i)) | |
StringGetPos i, x, ^, R ; execute rightmost ^ operator | |
IfGreaterOrEqual i,0, Return Eval@(SubStr(x,1,i)) ^ Eval@(SubStr(x,2+i)) | |
StringGetPos i, x, &, R ; execute rightmost & operator | |
IfGreaterOrEqual i,0, Return Eval@(SubStr(x,1,i)) & Eval@(SubStr(x,2+i)) | |
; execute rightmost <<, >> operator | |
RegExMatch(x, "(.*)(\<\<|\>\>)(.*)", y) | |
IfEqual y2,<<, Return Eval@(y1) << Eval@(y3) | |
IfEqual y2,>>, Return Eval@(y1) >> Eval@(y3) | |
; execute rightmost +- (not unary) operator | |
RegExMatch(x, "(.*[^!\~±¬\@\*/\\])(±|¬)(.*)", y) ; lower precedence ops already handled | |
IfEqual y2,±, Return Eval@(y1) + Eval@(y3) | |
IfEqual y2,¬, Return Eval@(y1) - Eval@(y3) | |
; execute rightmost */% operator | |
RegExMatch(x, "(.*)(\*|/|\\)(.*)", y) | |
IfEqual y2,*, Return Eval@(y1) * Eval@(y3) | |
IfEqual y2,/, Return Eval@(y1) / Eval@(y3) | |
IfEqual y2,\, Return Mod(Eval@(y1),Eval@(y3)) | |
; execute rightmost power | |
StringGetPos i, x, @, R | |
IfGreaterOrEqual i,0, Return Eval@(SubStr(x,1,i)) ** Eval@(SubStr(x,2+i)) | |
; execute rightmost function, unary operator | |
If(!RegExMatch(x,"(.*)(!|±|¬|~|'(.*)')(.*)", y) ){ ; no more function (y1 <> "" only at multiple unaries: --+-) | |
Return x | |
} | |
IfEqual y2,!,Return Eval@(y1 . !y4) ; unary ! | |
IfEqual y2,±,Return Eval@(y1 . y4) ; unary + | |
IfEqual y2,¬,Return Eval@(y1 . -y4) ; unary - (they behave like functions) | |
IfEqual y2,~,Return Eval@(y1 . ~y4) ; unary ~ | |
;From here on we are detecting functions in the query | |
;don't return anything if the parenthesis isn't closed | |
;Wait till AFTER the close parenthesis is given whence the upper code removes the parenthesis | |
if(instr(y4,"(") && !instr(y4,")")2) | |
return | |
;evaltest(y1,y2,y3,y4,x) | |
;intercept ahk functions typed into the query box | |
if(y3 = "cos"){ | |
y3 := "math_cos" | |
}else if(y3 = "sin"){ | |
y3 := "math_sin" | |
}else if(y3 = "tan"){ | |
y3 := "math_tan" | |
}else if(y3 = "acos"){ | |
y3 := "math_acos" | |
}else if(y3 = "asin"){ | |
y3 := "math_asin" | |
}else if(y3 = "atan"){ | |
y3 := "math_atan" | |
}else if(y3 = "deg"){ | |
y3 := "math_deg" | |
}else if(y3 = "rad"){ | |
y3 := "math_rad" | |
}else if(y3 = "log"){ | |
;if you feed Log() a 1 it will return a blank string, which makes Calculor think it should return ". . ." | |
;so override this and return the correct answer | |
if(y4 = 1){ | |
Return Eval@(y1 . "0" ) | |
} | |
} | |
; built-in and predefined functions(y4) | |
If(IsFunc(y3) ){ | |
;Don't run any functions in the query box unless they are in the main list (see the list of keywords in gui.ahk) | |
if(!instr(AllQueryFunctions, y3)) | |
return | |
;evaltest(y1,y2,y3,y4,x) | |
;Determine if the parameters in y4 are multiple and separate them | |
;yparam := strsplit(y4,",",a_space) <--why didn't this work?? I don't know | |
stringsplit, yparam, y4,`, | |
;keep the function from being called until the second parameter is ready | |
if(yparam0 > 1){ ;check for more than one parameter; yparam0 is the number of parameters | |
if(yparam1 != "" && yparam2 != "") ;prevent the function from running against blanks, but allow 0 - otherwise gcd will crash | |
return Eval@(y1 . %y3%(yparam1,yparam2) ) | |
else | |
return | |
;else there are no commas so there is only one parameter | |
}else{ | |
;evaltest(y1,y2,y3,y4,x) | |
Return Eval@(y1 . %y3%(y4) ) | |
} | |
} | |
;I'm not sure if we need this last part... when you figure out what it does, re-enable it | |
;By disabling it, it allows us to not calculate when a user has a function call typo | |
;There is a corresponding part at the beginning of Eval1(x) | |
;evaltest(y1,y2,y3,y4,x) | |
return | |
; LAST: user defined functions | |
;Return Eval@(y1 . Eval1(RegExReplace(f%y3%__F, f%y3%__X, y4))) | |
} | |
evaltest(y1,y2,y3,y4,whattitle="EvalTest"){ | |
;y1= | |
;y2='functionName' | |
;y3=functionName | |
;y4=function parameters calculated separately within parenthesis | |
thisstring := whattitle . "`r`ry1=" . y1 . "`ry2=" . y2 . "`ry3=" . y3 . "`ry4=" . y4, "info" | |
ToolTip, %thisstring%, %x%+10, %y%+50 | |
} | |
tooly(what){ | |
ToolTip, %what%, %x%+50, %y%+50 | |
} | |
;-------------------------------------------------------------------------------------------------------------------------------------- | |
;Special Functions that can be called - see the list of globals in gui.ahk | |
;if the functions are not in these lists then they cannot be run from Calculor | |
;we do this so that Calculor won't get confused to run other ahk functions folks might type in the box | |
;keywordsMath, keywordsCommands, keywordsSpecial1, keywordsSpecial2, keywordsPredefined | |
ToBin(n){ ; Binary representation of n. 1st bit is SIGN: -8 -> 1000, -1 -> 1, 0 -> 0, 8 -> 01000 | |
Return n=0||n=-1 ? -n : ToBin(n>>1) . n&1 | |
} | |
ToBinW(n,W=8){ ; LS W-bits of Binary representation of n | |
Loop %W% ; Recursive (slower): Return W=1 ? n&1 : ToBinW(n>>1,W-1) . n&1 | |
b := n&1 . b, n >>= 1 | |
Return b | |
} | |
FromBin(bits){ ; Number converted from the binary "bits" string, 1st bit is SIGN | |
n = 0 | |
Loop Parse, bits | |
n += n + A_LoopField | |
Return n - (SubStr(bits,1,1)<<StrLen(bits)) | |
} | |
; Sgn(x){ | |
; Return (x>0)-(x<0) | |
; } | |
min(a,b){ | |
Return a<b ? a : b | |
} | |
max(a,b){ | |
Return a<b ? b : a | |
} | |
gcd(a,b){ ; Greatest Common Divisor (we include both functions here for the user's sake | |
Return math_gcd(a,b) | |
} | |
gcf(a,b){ ; Greatest Common Factor | |
Return math_gcd(a,b) | |
} | |
choose(n,k){ ; Binomial coefficient | |
return math_choose(n,k) | |
} | |
fib(n){ ; n-th Fibonacci number (n < 0 OK, iterative to avoid globals) | |
return math_fib(n) | |
} | |
fac(n){ ; n! | |
;Return n<2 ? 1 : n*fac(n-1) | |
return math_fac(n) | |
} | |
rf(a,b){ | |
;alert("hitting rf") | |
Return roundfraction(a,b) | |
} | |
rad(n){ | |
return math_rad(n) | |
} | |
deg(n){ | |
return math_deg(n) | |
} | |
;-------------------------------------------------------------------------------------------------------------------------------------- | |
roundfraction(whatval, roundto, simplify=false){ | |
;original fraction | |
stringsplit, fracval, whatval,`,%a_space% | |
thisfrac := new fraction | |
thisfrac.fast(true) ;do not simplify | |
thisfrac.set(fracval1,fracval2) | |
;convert original fraction to number and round it off to the nearest roundto | |
thisval := thisfrac.tonumber() | |
if(!simplify){ | |
roundedval := Round(thisval*roundto,4)/roundto | |
}else{ | |
roundedval := Round(thisval*roundto,4)/roundto | |
} | |
;new, rounded fraction | |
roundedfrac := new fraction | |
roundedfrac.fast(true) | |
roundedfrac.set(roundedval) | |
rounded := roundedfrac.tostring() | |
;if the user wants the closest value, give it | |
if(!simplify){ | |
return rounded | |
} | |
;to unsimplify it in case the user just wants the value closest to the roundto number | |
stringsplit, rvals, rounded,`/ | |
div := roundto / rvals2 | |
top := round(rvals1 * div,0) | |
bottom := roundto | |
newfrac := new fraction | |
newfrac.fast(true) | |
newfrac.set(top ,bottom) | |
;return unsimplified fraction | |
return newfrac.tostring() | |
} | |
;round to fraction - requires the fraction.ahk library | |
roundfractionx(whatval, roundto, simplify=true){ | |
;convert whatval into a decimal | |
thisval := new fraction(whatval).tonumber() | |
;round it and divide | |
rounded := Round(thisval*roundto,0)/roundto | |
;return it to fraction form | |
retval := new fraction(rounded) | |
return retval.tostring() ; whatval " : " . roundto . " = " . rounded . " = " . retval.tostring() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment