Here is a major update v.1.4: array handling and statistics. (Function plots are basically supported via arrays, as in Excel: generate the points of the function graph and pass it to an external graphing application.) There are more than 200 lines of new code, so some bugs could have remained.
To Do:
- Dynamic functions: the work is basically done in the function array(), but some more debugging is needed.
- Include AHK graphing (maybe jonny’s
Mathematical Function Grapher)
- Extra level of evaluation inside [..], which allows x[i+2] like indexing
Arrays are implemented as in AHK: separate variables for the entries, the 0th entry being the length. Also, the array variable contains its name, so after creation there is no need to use quotation marks around array names. The new functions:
- copy("X",Y) duplicates array Y
- clear(X) removes array header
- seq("X",i0,i1[,d=1]) set up linear sequence X = {i0,i0+d..,i1}, return "X"
- array("X","i",i0,i1,d, "expr") general array with dynamic expression evaluation: X = {expr(i:=i0),expr(i:=i0+d)..,expr(i:=i1)}
- more("X",entry0,..) add up to 30 new entries to the end of array X, return "X"
- part("Y",X,i0,i1[,d=1]) Y <- {X[i0],X[i0+d]..,X[i1]}, return "Y" ( Y <> X )
- join("Z",X,Y) Z <- joined arrays {X,Y}, return "Z" (not equal to X or Y)
- add("Z",Y,X), sub(), mult(), div(): elementwise operators on arrays
- mean(X), std(X), moment(k,X) statistics functions
- sum(X), prod(X), sumpow(k,X), dot(X,Y) vector to scalar functions
- the functions min(X) and max(X) handle arrays when one array argument is passed
Also,
- added 2 new constants rad and deg to convert to degree: radians*deg, or to radian: degrees*rad
Here the most powerful function is array(). Its last argument is an expression, which is repeatedly evaluated with the changing variable (the second argument), going over a linear sequence. Basically, a function is tabulated: evaluated at many arguments, and the results are stored in an array.
Examples:
more("X",1,-2,3); min(X)
more(X,5,6,-7); std(X)
array("Y","i", 0,9,1, "i*i"); Y_5+Y_4
dot(X,Y)
--- --- ---
Another significant update: Version 1.5.
- Help is shown/hidden in a scrollable edit control (Alt-H)
- “;” is kept (not treated as command separator) inside quoted strings
- Internal global variables are renamed to start with “__”, to avoid conflicts with user variables (which are always global)
Three new functions are added for iterative computations:
- for(Var,i0,i1,d,expr) : evaluate {expr(i0),expr(i0+d)..,expr(i1)}; -> last result
x:=0; for("i",1,10,1,"x+=i*i") -> the sum of the 1st 10 squares
- while(cond,expr) : evaluate expr while cond is true; -> last result
n:=1; x:=1; while("n++<10","x+=1/n") -> the sum of the 1st 10 reciprocals
- until(expr,cond) : evaluate expr until cond gets true (at least once); -> last result
n:=1;x:=1;until("x*=++n","n=10") -> 10!
- Dynamic expression evaluation: eval(expr):
f:="1/x+1/y+1/z"
x:=1;y:=2;z:=0.5; eval(f)
- Poor man’s dynamic functions: call(FName, Param1,Param2...)
f:="1/f1+1/f2+1/f3"
call("f",1,2,3)
~Assign the function body (as a string) to a variable, like “f”.
~The function parameters are numbered, prefixed with the name of the variable “f”: f1, f2,...
This way the chance of variable naming conflict is smaller, but still there. In the Popup Calculator every variable is global, so if you have used f2 earlier, it will be overwritten by the call("f",1,2,3).
--- --- ---
Update: Version 1.6.
- simplified __eval()
- new tray menu item: edit/hide history
- support for binary input with the MS bit as sign: b("0101") -> 5, b("1000") -> -8. (A variable can still be named “b”).
- [expr]: evaluate expr -> v, return “_v”; ~ computed index.
e.g. X[1]:=2 is the same as X_1:=2
e.g. i:=2; 3-X[i-1] is the same as i:=2; __temp:=i-1; 3-X_%__temp%, or 3-X[1]. Here __temp is not global, there is no conflict with multiple brackets in one expression.
B[1][2] is the same as B_1_2, so we can mix one-, and two dimensional arrays: B[1][2] is different from B[12].
Using [.] allows replacing the ugly x_%i% with x[i], where i is an arbitrary expression. x[i] can be on the left hand side of an assignment, too. The elements of an automatic array X are accessed as X_0=X[0]: length, X_1=X[1], X_2=X[2]... which reduces the possibility of conflicts with explicitly defined variables x1, x2...:
more("X",3,2,1),X[3]
gives 1, the value stored in X_3.
--- --- ---
The next major update v.1.7 (with function graphing built in) is here. It is still a single ahk file, start it from any directory, where you can write the history file to. Now all the requested features are implemented, we can fix bugs and think about the ease of use and similar fine tunings.
Changes/New features:
- edit history now updates drop-down expressions list
- results are separated by ¦, cosmetic help changes
- single tray-click activates calculator window
- pmean() works now on vectors (1-dim arrays), too
-
GRAPHING FUNCTIONS
- graph(x0,x1,y0,y1,width=400,height=300,BGcolor=white) : create/change graph window to plot in
---- (margin=10) deleted when closed[x] or GuiEscape
---- graph is copied with Alt-PrtScrn to the clipboard
---- graph() destroys
- Xtick(Array=10,LineColor=gray,LineWidth=1,Label=true) : add | lines to graph at X positions
---- (Labels are not yet implemented)
---- can be called multiple times, BEFORE plot
---- Array=integer : equidistant ticks, Array="" : 10 stripes
---- Array=float : single line
- Ytick(Array=10,LineColor=gray,LineWidth=1,Label=true) : add - lines at y positions...
- plot(Y,color=blue,LineWidth=2) add plot of straight lines with X = {1..len(Y)}
---- if no graph: create default one with y0 = min(Y), y1 = max(Y)
---- plot() erase function graphs
- plotXY(X,Y...): add XY plot to last graph
---- if no graph, create default one with graph(min(X),max(X),min(Y),max(Y))
Example:
array("X","i",1,100,1,"sin(i/pi)"); plot(X)
array("Y","i",1,100,1,"atan((i-50)/25)/pi_2"); plot(Y,0xFF)
--- --- ---
Version 1.8:
- array operations now accept one scalar argument, like add(X,X,-1) subtracts 1 from each elements of X, div(X,1,X) replaces the elements of X with their reciprocals.
- fixed missing memory allocation for __Z
--- --- ---
Version 1.9:
There are two major new additions: list(.), opening up a new window where an array (vector) can be entered, edited or sorted for view (see min/max); and the apply-to function @(..), which applies another function or AHK operator on one or two arrays. Local variable names are now prefixed with double underscores when necessary to minimize the chance of a conflict with global variables defined in the calculator. The size of the windows are computed using the selected font and DPI settings. There are more than a thousand changes, so be careful, some new bugs could have been introduced!
Here are some not numeric applications:
- fast conversion between char and its ANSI code: asc('a')->97, chr(0x44)->D
- quick test of RegEx Match/Replace (not all works):
--- RegExReplace("C:\Windows\system32", "Windows", "WinNT")
- get file attributes: FileExist("C:\Windows\system32\systeminfo.exe") -> A
Changes/New features:
- list(array) Edit/Sort ListView of elements. To build array: {Enter}-Value-{Enter}
--- rightclick menu: More (Enter, Alt-M: add new), Less (Alt-L: del last)
- separate, streamlined help window with added list of AHK functions
- if user entered expr is already in history: don't add (ignoring spaces)
- size of calc window is calculated to 65+1 chars for current font, DPI
- results are shown with tab chars
- new function msg(x): MsgBox % x
- @(..): apply-to function/operator for vectors (replaced add, sub, mul, div).
--- @("Z",X,"+",Y), @("Z",Z,"^",-1), @("Z",Z,"Round",3), @("Z",X,"sin"), @("Z",Z,"<=",0.25)
- shorthand: `var == "var", where var is terminated by "," or ")", "]", eol, space
--- careful with expressions: `sin(x) becomes "sin(x"), `round(x,2) --> "round(x",2)
- "[expr]" is now left unprocessed in quoted strings (delayed evaluation is needed for loops, arrays)
- locals, params are now prefixed with "__" to reduce conflicts with globals.
--- --- ---
Version 2 is uploaded. The changes:
- remember window positions → calc.ini
- configurable hotkeys ← calc.ini
- bugfix in prod()
- list: redraw LV after all rows added (to ensure proper display)
- periodically redraw graph window
- graph cursor is changed to crosshair + coordinates in ToolTip
- LCM(a,b) added: Least Common Multiple as a * (b // GCD(a,b))
- solve('x',x0,,x1,'expr'[,tol]) added: find 'x' where 'expr' = 0
- fmax('x',x0,x1,x2,'expr'[,tol])) added : find 'x' where 'expr' = max (at flat curve lower precision)
- rand(x,y) added: random number in [x,y]; rand(x) new seed=x.
--- rand(1,6) {Enter}…{Enter} = dice
- sort('y',x[.opt]) added: y ← sorted array x.
--- opt = 0: random, 1: no duplicates, 2: reverse, 3: reverse unique
- primes('p',n) added: {primes <= n} → array 'p' using the sieve Eratosthenes
--- list(primes(`x,999999)) shows all primes less than a million
--- m <= primes <= n: list(array(`x,`i,1,299,1,'isprime(2**32+i)'))
- IsPrime(p) added: machine code prime test (IsPrimeA is pure AHK, slow)
--- isprime(2**31+11), isprime(2**31-1)
--- list(array(`x,`i,1,999,1,'isprime(2**62+i)')) find all 32 primes in (2**62,2**62+1000) (Dell Inspiron 9300: 15 minutes)
--- isprime(9223372036854775783) → 1 (34 sec), it is the largest prime, 2**63-25, AHK can show
- pDivs('d',n) added: {prime divisors of n} → d (pDivsA is pure AHK, slow)
--- list(pdivs(`x,9973*9967)), list(pdivs(`x,(2**31+45)*(2**31+11))) – (Dell Inspiron 9300: 23 sec)
The file grew too large to be directly copied here. Download it from
here. No installation is required, just copy it somewhere and run.