 |
AutoHotkey Community Let's help each other out
|
| View previous topic :: View next topic |
| Author |
Message |
Chris Site Admin
Joined: 02 Mar 2004 Posts: 10716
|
Posted: Wed Sep 07, 2005 1:36 pm Post subject: |
|
|
| Laszlo wrote: | | numbers are practically fix point ([pi]/10000000000*10000000000 <> [pi]), and if you work with large or small numbers the precision of the intermediate results ruin the accuracy. | In case it's of interest, AutoHotkey stores intermediate expression results as 64-bit floating point numbers (or integers if there's no decimal portion). However, when the final result is stored in a variable (or for use by a command), the default precision is 6 decimal places. This can be increased via SetFormat. For example, the following retains a double's full 15 digits of precision:
SetFormat, Float, 0.15
MsgBox % 3.141592653589793/10000000000*10000000000
; It displays 3.141592653589793. |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4710 Location: Boulder, CO
|
Posted: Wed Sep 07, 2005 2:16 pm Post subject: |
|
|
Yes, the fix point conversion at store or at set command parameters makes the arithmetic practically fix point. If you don't know the range of the intermediate results (as at a complicated expressions), you may end up with inaccurate results. | Code: | SetFormat Float, 0.15
a := 3.141592653589793/1000000000000
MsgBox % a*1000000000000 | displays 3.142000000000000, only 3 decimals are accurate. Of course, you could set a very long float format at the beginning of the calculations and reset it to the desired length at the end, but you still have to have a reasonable estimate on the intermediate results. | Code: | SetFormat Float, 0.99
c = 100000000000000000000000000000000
a := 3.141592653589793/c
b := a*c
SetFormat Float, 0.15
b += 0
MsgBox %b% |
|
|
| Back to top |
|
 |
Decarlo110
Joined: 15 Dec 2004 Posts: 303 Location: United States
|
Posted: Tue Nov 08, 2005 9:47 pm Post subject: |
|
|
This set of scripts is, as Nemroth said, brilliant. Essential for computation until such time that dynamic expressions are built-in. The title is a bit odd though, since it isnt so simple to me.
| Laszlo on 2005.09.07 wrote: | | numbers are practically fix point ([pi]/10000000000*10000000000 <> [pi]), and if you work with large or small numbers the precision of the intermediate results ruin the accuracy. Maybe the best is to interface AHK to GMP, the GNU multi precision numerical library, compiled to a Windows DLL. |
I was wondering if you had seen Rubberduck's BigInteger-Calculation with AHK script, and if so, what you thought of it, and could it be adapted for or used as a basis for exponents and roots. _________________ 1) The Open Source Definition http://www.opensource.org/docs/definition_plain.php
2) Intuitive. Logical. Versatile. Adaptable. <<AutoHotkey>> |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4710 Location: Boulder, CO
|
Posted: Tue Nov 08, 2005 10:53 pm Post subject: |
|
|
Thanks for the compliments. Rubberduck's script is way too long for me to comprehend fully. It seems to work. Its main merit is educational: anyone interested in programming long arithmetic could find the necessary ideas there. I am sure it can be extended for handling other operators, too, but if you add expression parsing, functions, etc, it will go unmanageably large. We should use for that a structured, modular programming language.
I work often with long numbers, so for me speed is important. Therefore I wrote a script, which provides an interface from an editor or from MS Word to Pari/GP (an open source computer algebra system), which loads faster than the windows calculator and provides arbitrary precision at high speed. I thought there was no interest in the AHK forum for this kind of exotic stuff, but if there were, I could post the script. As you probably guessed, I try to keep the code size below 50 lines, otherwise most everybody would not bother to try to understand, and use it blindly just as a downloaded program.
Pari/GP is nice, but has some shortcomings. E.g. there is no hex I/O, or long random number generator. Therefore I compiled GMP, the Gnu Multi Precision arithmetic library to a Windows DLL, and wrote an AHK wrapper for most of its functions. It works, but the wrapper script is long. I haven't got the time to write (or modify/adapt/compile) an expression parser, so you have to write all operations as function calls, like gmp_add(x,1). One day I will finish it, but it might not be worth the effort. For longer calculations I run Mathematica. It takes minutes to start up, but then it is very nice. I can recommend it if you have three grands for SW. |
|
| Back to top |
|
 |
Futurepower(R)
Joined: 20 Jun 2005 Posts: 37
|
Posted: Thu Feb 16, 2006 2:29 am Post subject: GMP for Windows |
|
|
Laszlo, I wrote the comment below and then read the part of your comment about you making a GMP DLL for AutoHotkey. However, maybe it is of interest anyway:
Laszlo, this seems relevant to your comment about GMP:
GMP for Windows
http://www.cs.nyu.edu/exact/core/gmp/
But I don't see a precompiled DLL.
Another subject: In general, I find arithmetic in AutoHotkey mystifying.
I offered to help re-write this page:
http://www.autohotkey.com/docs/Variables.htm
which I think should provide more clear information about assignment operators.
I don't know when to use := and when to use =
I notice that == works to test equivalency. |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4710 Location: Boulder, CO
|
Posted: Thu Feb 16, 2006 4:16 am Post subject: |
|
|
In the mean time I found a better solution: calc. It is free, runs in Windows under GnuWin32. You can download the binaries from here. It has a nice expression parser, handles any number system (hex, octal, decimal...), fix or floating point operations with arbitrary precision, many transcendental functions, and it is lightning fast. If you do arithmetic with a million digits, GMP might be faster, otherwise, there is no noticeable difference.
If you want to use GMP in Windows the easiest is to install MinGW with the GNU C compiler and GNU make. The GMP make file under MinGW can create a dynamic library, which can be normally accessed from AHK using DllCalls. I did it the hard way: tweaked the Visual Studio setup, until it compiled GMP. It was a week work, and quite a stupid idea. |
|
| Back to top |
|
 |
PhiLho
Joined: 27 Dec 2005 Posts: 6836 Location: France (near Paris)
|
Posted: Thu Feb 16, 2006 2:00 pm Post subject: Re: GMP for Windows |
|
|
| Futurepower(R) wrote: | | I don't know when to use := and when to use = | For doing expressions, you must use := or derivatives (+=, etc.).
AFAIK, = works only for simple initializations (numeric constant or string) and string concatenation with variable substitution. That's all.
@Laszlo: I hope you don't mind if I plug in my simple utility: MPCalc. I made a simple wrapper around a little expression parser library I found. I made it, at the time, for AutoIt2, when most of its math power used EnvAdd and the like...
Its advantages: small (native Windows code), to the point (not everybody compute with thousand of decimal digits...), able to output to stdout (thus to a flat file), to a .ini file or to the clipboard.
Now, it is not as powerful as calc, but it still may be useful to some people. Which can actually use your script for such simple expressions...
It is mostly obsolete, I know  _________________
vPhiLho := RegExReplace("Philippe Lhoste", "^(\w{3})\w*\s+\b(\w{3})\w*$", "$1$2") |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4710 Location: Boulder, CO
|
Posted: Thu Feb 16, 2006 4:09 pm Post subject: |
|
|
| MPCalc looks like a nice little utility (it is hard to beat its size or speed), but the simplest solution (if you don't need infinite precision), is the Windows calculator (or the PowerToy calculator, etc.). It accepts input pasted from the Clipboard, understands brackets and operator precedence, logic operations, decimal, octal, hex and binary I/O, practically everything a normal user wants. It is fast and already installed in your PC. |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4710 Location: Boulder, CO
|
Posted: Sat Feb 24, 2007 7:57 pm Post subject: |
|
|
Since the scripts were posted, regular expressions were introduced to AHK. They allow great simplifications and removing some restrictions. The script below evaluates an arithmetic expression contained in a string, without any external programs. Therefore, it can be compiled and run in machines, where AHK is not installed. It can handle the usual arithmetic operations: + - * / mod (as % or \) and power (as **), predefined constants (pi and e) and some AHK functions (abs, floor, sqrt). Terms can be grouped with parentheses (..).
| Code: | ; AHK 1.0.46+
; evaluate arithmetic expressions containing
; unary +,- (-2*3; +3)
; +,-,*,/,\(or % = mod); **(or @ = power)
; (..); var (pi, e); abs(),sqrt(),floor()
MsgBox % Eval("-floor(abs(sqrt(1))) * (+pi -((3%5))) +pi+ 2-1-1 + e-abs(sqrt(floor(2)))**2-e") ; 1
Eval(x) { ; expression preprocessing
Static pi = 3.141592653589793, e = 2.718281828459045
StringReplace x, x,`%, \, All ; % -> \ for MOD
x := RegExReplace(x,"\s*") ; remove whitespace
x := RegExReplace(x,"([a-zA-Z]\w*)([^\w\(]|$)","%$1%$2") ; var -> %var%
Transform x, Deref, %x% ; dereference all %var%
StringReplace x, x, -, #, All ; # = subtraction
StringReplace x, x, (#, (0#, All ; (-x -> (0-x
If (Asc(x) = Asc("#"))
x = 0%x% ; leading -x -> 0-x
StringReplace x, x, (+, (, All ; (+x -> (x
If (Asc(x) = Asc("+"))
StringTrimLeft x, x, 1 ; leading +x -> x
StringReplace x, x, **, @, All ; ** -> @ for easier process
Loop { ; find innermost (..)
If !RegExMatch(x, "(.*)\(([^\(\)]*)\)(.*)", y)
Break
x := y1 . Eval@(y2) . y3 ; replace "(x)" with value of x
}
Return Eval@(x) ; no more (..)
}
Eval@(x) {
RegExMatch(x, "(.*)(\+|\#)(.*)", y) ; execute rightmost +- operator
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
If !RegExMatch(x,".*(abs|floor|sqrt)(.*)", y)
Return x ; no more function
IfEqual y1,abs, Return abs( Eval@(y2))
IfEqual y1,floor,Return floor(Eval@(y2))
IfEqual y1,sqrt, Return sqrt( Eval@(y2))
} | It is a major rewrite, so look out for bugs. More constants can be added after the Static directive, more AHK functions can be referenced (even user functions of one parameter), with editing the "If !RegExMatch(x,".*(abs|floor|sqrt|MyFun)..." command and adding new calls to the end of the script: "IfEqual y1,MyFun, Return MyFun( Eval@(y2))".
This is my 2500th post to the Forum. Have fun! |
|
| Back to top |
|
 |
Labouche10
Joined: 28 Nov 2007 Posts: 17 Location: Missouri, USA
|
Posted: Tue Apr 29, 2008 12:24 am Post subject: Much simpler solution |
|
|
I am blown away by the crazy logic that you guys have implemented in creating a dynamic evaluator. In the meantime I wrote a quick & dirty little program that seems to do the same thing but much easier and with alot less code. I need some help though filling in the last gap. This great little calculator is actually able to take advantage of all the mathematical wonderfulness in autohotkey including all the trig and powers etc etc. I added a little regexreplace function for pi also. This script writes a dynamic little script that uses the built in evaluation of autohotkey then writes the solution to another file which is read. Both temp files are then deleted. It is a shame that all the previous code was written. I'm sure it took a long time to write. The only problem I'm having at this point is getting the dynamically written script to execute on computers that do not have autohotkey installed. Hopefully one of you more experienced guys can help with that. Thanks in advance for the help!
Thanks
Labouche10
| Code: |
/*
Title: My Calculator
Compiled/Written 01.16.2008 by labouche10
This is just a basic calculator that I wrote that was inspired by my favorite calculator.
I wrote this for the people in my office to use.
I'm a noob so don't come down on me too hard! I hope someone can use this as much as I know I will.
*/
#NoEnv
SendMode Input
SetWorkingDir %A_ScriptDir%
CoordMode, tooltip, relative
groupadd, calculatorgroup, %A_Username%'s Calculator
; Add Menus
Menu, FileMenu, add, &Print Ctrl+P, printout
Menu, FileMenu, add, &Save Ctrl+S, save
Menu, FileMenu, add, Save &As Ctrl+Shift+S, saveas
Menu, FileMenu, add, E&xit Alt+F4, guiclose
Menu, MyMenuBar, Add, &File, :FileMenu
Menu, EditMenu, add, &Copy History Ctrl+C, copyhistorytoclipboard
Menu, EditMenu, add, Clear History Ctrl+Backspace, clearhistory
Menu, EditMenu, add, &Undo Clear Ctrl+Z, undoclearhistory
Menu, MyMenuBar, Add, &Edit, :EditMenu
Menu, OptionsMenu, add, &Set Decimal Places, rounding
Menu, OptionsMenu, add, &Stop Rounding, stoprounding
Menu, MyMenuBar, Add, &Options, :OptionsMenu
Menu, HelpMenu, Add, &Shortcuts F1, Helpmenushortcuts
Menu, HelpMenu, add, &About..., helpmenuabout
Menu, MyMenuBar, Add, &Help, :HelpMenu
; Gui functions
Gui, Menu, MyMenuBar
Gui, +Resize +MinSize
Gui, Color, 0x000000, 0x000000 ;0xD2E8F2
Gui, font, s10 bold cWhite, copperplate gothic :2D7597
Gui, add, text,, Description
Gui, font, s10 norm cWhite, copperplate gothic
Gui, add, edit, w175 R1 +veditdescription
Gui, font, s10 bold cWhite, copperplate gothic
Gui, add, text,, History
Gui, font, s10 norm cWhite, copperplate gothic
Gui, add, edit, w175 h200 +readonly +vedithistory
Gui, font, s10 bold cWhite, copperplate gothic
Gui, add, text,+vinput, Input
Gui, Font, s12 bold cWhite, copperplate gothic
Gui, add, edit, w175 R1 +veditcalculate
Gui, Font, s10 norm, copperplate gothic
Guicontrol, +0x40, edithistory
Guicontrol, focus, editcalculate
Gui, Show,, %A_Username%'s Calculator
;WinSet, ExStyle, ^0x80, %A_Username%'s Calculator
;WinSet, ExStyle, +0x80, %A_Username%'s Calculator
Return
; Context sensitive GUI hotkeys
#IfWinActive ahk_group calculatorgroup
; The following four functions use the most recent result as the first argument when pressing only +,-,*,/
NumpadAdd::
Gui, Submit, NoHide
ControlGetFocus, focusvar, ahk_group calculatorgroup
If focusvar = edit3
{
controlgettext, temptext, edit3
if temptext =
{
If answerall =
{
Sendraw, +
Return
}
Else
{
Sendraw, answer+
Return
}
}
Else
{
Sendraw, +
Return
}
}
Else
Sendraw, +
Return
+::
Gui, Submit, NoHide
ControlGetFocus, focusvar, ahk_group calculatorgroup
If focusvar = edit3
{
controlgettext, temptext, edit3
if temptext =
{
If answerall =
{
Sendraw, +
Return
}
Else
{
Sendraw, answer+
Return
}
}
Else
{
Sendraw, +
Return
}
}
Else
Sendraw, +
Return
~F1::
Gosub, helpmenushortcuts
Return
NumpadSub::
Gui, Submit, NoHide
ControlGetFocus, focusvar, ahk_group calculatorgroup
If focusvar = edit3
{
controlgettext, temptext, edit3
if temptext =
{
If answerall =
{
Sendraw, -
Return
}
Else
{
Sendraw, answer-
Return
}
}
Else
{
Sendraw, -
Return
}
}
Else
Sendraw, -
Return
-::
Gui, Submit, NoHide
ControlGetFocus, focusvar, ahk_group calculatorgroup
If focusvar = edit3
{
controlgettext, temptext, edit3
if temptext =
{
If answerall =
{
Sendraw, -
Return
}
Else
{
Sendraw, answer-
Return
}
}
Else
{
Sendraw, -
Return
}
}
Else
Sendraw, -
Return
NumpadMult::
Gui, Submit, NoHide
ControlGetFocus, focusvar, ahk_group calculatorgroup
If focusvar = edit3
{
controlgettext, temptext, edit3
if temptext =
{
If answerall =
{
Sendraw, *
Return
}
Else
{
Sendraw, answer*
Return
}
}
Else
{
Sendraw, *
Return
}
}
Else
Sendraw, *
Return
*::
Gui, Submit, NoHide
ControlGetFocus, focusvar, ahk_group calculatorgroup
If focusvar = edit3
{
controlgettext, temptext, edit3
if temptext =
{
If answerall =
{
Sendraw, *
Return
}
Else
{
Sendraw, answer*
Return
}
}
Else
{
Sendraw, *
Return
}
}
Else
Sendraw, *
Return
NumpadDiv::
Gui, Submit, NoHide
ControlGetFocus, focusvar, ahk_group calculatorgroup
If focusvar = edit3
{
controlgettext, temptext, edit3
if temptext =
{
If answerall =
{
Sendraw, /
Return
}
Else
{
Sendraw, answer/
Return
}
}
Else
{
Sendraw, /
Return
}
}
Else
Sendraw, /
Return
/::
Gui, Submit, NoHide
ControlGetFocus, focusvar, ahk_group calculatorgroup
If focusvar = edit3
{
controlgettext, temptext, edit3
if temptext =
{
If answerall =
{
Sendraw, /
Return
}
Else
{
Sendraw, answer/
Return
}
}
Else
{
Sendraw, /
Return
}
}
Else
Sendraw, /
Return
; This char doesn't belong in the edit box
=::
ControlGetFocus, focusvar, ahk_group calculatorgroup
If focusvar = edit3
{
TrayTip, Entry Error,Enter a numerical calculation,,3
SetTimer, Removetraytip, 5000
Return
}
Else
Sendraw, =
Return
; Proceed with the calculation
~NumPadEnter::
ControlGetFocus, focusvar, ahk_group calculatorgroup
If focusvar = edit3
Gosub, Calculate
Else
Sendinput, {Enter}
Return
~Enter::
ControlGetFocus, focusvar, ahk_group calculatorgroup
If focusvar = edit3
Gosub, Calculate
Else
Sendinput, {Enter}
Return
; Print results in a sort of 'adding machine' output.
^p::
printout:
Gui, Submit, NoHide
FormatTime, currentime
edit =
edit := "`nPrinted by: " . A_Username . "`n`nPrinted time: " . currentime . "`n`n`n`nDescription: " . editdescription . "`n`n`n`nCalculations:`n`n" . answerall
Print(edit)
Return
; Why would you want to save your results? I dunno if you want to then do it.
^s::
save:
If savefilename =
Fileselectfile, savefilename, 2, %A_Desktop%\calchistory.rtf, Save As, *.rtf
Gui, Submit, NoHide
FormatTime, currentime
edit =
edit := "`nPrinted by: " . A_Username . "`n`nPrinted time: " . currentime . "`n`n`n`nDescription: " . editdescription . "`n`n`n`nCalculations:`n`n" . answerall
fileappend, %edit%, %savefilename%
Return
^+s::
saveas:
Fileselectfile, savefilename, , %A_Desktop%\calchistory.rtf, Save As, *.rtf
savefilename := savefilename . ".rtf"
Gui, Submit, NoHide
FormatTime, currentime
edit =
edit := "`nPrinted by: " . A_Username . "`n`nPrinted time: " . currentime . "`n`n`n`nDescription: " . editdescription . "`n`n`n`nCalculations:`n`n" . answerall
fileappend, %edit%, %savefilename%
Return
; Just a helpful idea (hopefully)
^c::
copyhistorytoclipboard:
clipboard := answerall
Return
; Clear the history box
^Backspace::
clearhistory:
controlgettext, temptext, edit2
If answerall =
{
TrayTip, Error!,You must have history before you can clear it!,,3
SetTimer, Removetraytip, 5000
Return
}
Answerallbackup := Answerall
Answerall =
Guicontrol, text, edithistory, %Answerall%
Return
; I wished my last calculator actually had this
^z::
Undoclearhistory:
controlgettext, temptext, edit2
If answerallbackup =
{
TrayTip, Error!,You must clear the history before you can restore it!,,3
SetTimer, Removetraytip, 5000
Return
}
Else If temptext <>
{
TrayTip, Error!,You cannot restore history after starting new calculations,,3
SetTimer, Removetraytip, 5000
Return
}
Answerall := Answerallbackup
Guicontrol, text, edithistory, %Answerall%
ControlSend Edit2, ^{End}, ahk_group calculatorgroup
Return
; While in the 'Input' box this will just bring the last calculation back to be edited
~up:: ;Brings back the last calculation
ControlGetFocus, focusvar, ahk_group calculatorgroup
If focusvar = edit3
{
Guicontrol, text, edit3, %editcalculatebackup%
controlsend edit3, ^{End}, ahk_group calculatorgroup
}
Else
Sendraw, {up}
Return
^::
ControlGetFocus, focusvar, ahk_group calculatorgroup
If focusvar = edit3
{
Sendraw, **
}
Else
Sendraw, ^
Return
rounding:
Loop,
{
Inputbox, roundingvar, Decimal Places to round, Enter the number of decimal places (between 0 and 10) to round your answers to:
If errorlevel
Break
If rounding var is not integer
{
Msgbox, Error you must enter a whole number beween 0 and 10!
Continue
}
Else If (roundingvar < 0 or roundingvar > 10)
{
Msgbox, Error you must enter a value beween 0 and 10!
Continue
}
Else
Break
}
Return
stoprounding:
roundingvar =
Return
; The superficial portion of the calculation
Calculate:
Gui, Submit, NoHide
if editcalculate =
Return
editcalculate := RegExReplace(editcalculate,"answer",answer)
editcalculate := RegExReplace(editcalculate,"pi","3.1415926535897932384626433832795")
editcalculate := RegExReplace(editcalculate,"p","3.1415926535897932384626433832795")
editcalculatebackup := editcalculate
filedelete, tempcalc.ahk
filedelete, tempanswer
fileappend,
(
#NoTrayIcon
#ErrorStdOut
answer := %editcalculate%
fileappend, `%answer`%, tempanswer ; This is the simple solution
filesetattrib, h, tempanswer
exit
), tempcalc.ahk
filesetattrib, h, tempcalc.ahk
RunWait, tempcalc.ahk
IfExist, tempanswer
{
fileread, answer, tempanswer
filedelete, tempcalc.ahk
filedelete, tempanswer
}
Else
{
filedelete, tempcalc.ahk
If answerall =
{
answerall := "ERROR"
TrayTip, Entry Error, There is an error in your calculation,,3
SetTimer, Removetraytip, 5000
}
Else
{
answerall := answerall . "`nERROR"
TrayTip, Entry Error, There is an error in your calculation,,3
SetTimer, Removetraytip, 5000
}
Guicontrol, text, edithistory, %Answerall%
ControlSend Edit2, ^{End}, ahk_group calculatorgroup
Return
}
If answer is not number
{
If answerall =
{
answerall := "ERROR"
TrayTip, Entry Error, There is an error in your calculation,,3
SetTimer, Removetraytip, 5000
}
Else
{
answerall := answerall . "`nERROR"
TrayTip, Entry Error, There is an error in your calculation,,3
SetTimer, Removetraytip, 5000
}
}
Else
{
answerround := answer
Loop,
{
stringright, rightvar, answerround, 1
If roundingvar <>
{
answerround := Round(answerround,roundingvar)
Break
}
Else If instr(answerround,".") = 0
Break
Else If rightvar = .
{
Stringtrimright, answerround, answerround, 1
Continue
}
Else If rightvar = 0
{
Stringtrimright, answerround, answerround, 1
Continue
}
Else
Break
}
If answerall =
{
answerall := editcalculatebackup . " =`n " . answerround
Guicontrol, text, editcalculate,
}
Else
{
answerall := answerall . "`n" . editcalculatebackup . " =`n " . answerround
Guicontrol, text, editcalculate,
}
}
Guicontrol, text, edithistory, %Answerall%
ControlSend Edit2, ^{End}, ahk_group calculatorgroup
Return
removetooltip:
settimer, removetooltip, off
tooltip
return
removetraytip:
settimer, removetraytip, off
traytip
return
guiclose:
exitapp
helpmenuabout:
MsgBox, 0, My Calculator, Version 1.04.02`n`nBuilt 01.12.08`n`nby Mike Marrs
Return
helpmenushortcuts:
Gui, 2:Font, s16 Bold, Arial
Gui, 2:Add, Text, +xm w900 Center,Shortcuts
Gui, 2:Font, s8 Norm, Arial
Gui, 2:Add, Text, +xm +ys+20, Print: Ctrl + P
Gui, 2:Add, Text, +xm +ys+40, Save History: Ctrl + S
Gui, 2:Add, Text, +xm +ys+60, Save As: Ctrl + Shift + S
Gui, 2:Add, Text, +xm +ys+80, Exit: Alt + F4
Gui, 2:Add, Text, +xm +ys+100,
Gui, 2:Add, Text, +xm +ys+120, Copy History: Ctrl + C
Gui, 2:Add, Text, +xm +ys+140, Clear History: Ctrl + Backspace
Gui, 2:Add, Text, +xm +ys+160, Undo Clear History: Ctrl + Z
Gui, 2:Font, s16 Bold, Arial
Gui, 2:Add, Text, +xm w900 center,Functionality
Gui, 2:Font, s8 Bold, Arial
Gui, 2:Add, Text, +xm +ys+210 w900 center,Rounding:
Gui, 2:Font, s8 Norm, Arial
Gui, 2:Add, Text, +xm +ys+240 w900, Set Decimal Places: Use this option to automatically round answers to a set number of digits. After enabling the Set Decimal Places option, all significant digits are actually maintained throughout all calculations. To view these digits select Stop Rounding from the options menu then add '0' to your answer.
Gui, 2:Font, s8 Bold, Arial
Gui, 2:Add, Text, +xm +ys+280 w900 center, General Math
Gui, 2:Font, s8 Norm, Arial
Gui, 2:Add, Text, +xm +ys+295 w900, Note: Basic Operators: Add: +, Subtract: -, Multiply: *, Divide: /, Exponent **`n`nAbs(Number): Returns the absolute value of Number. The return value is the same type as Number (integer or floating point).`n`nCeil(Number): Returns Number rounded up to the nearest integer (without any .00 suffix). For example, Ceil(1.2) is 2 and Ceil(-1.2) is -1.Exp(N): Returns e (which is approximately 2.71828182845905) raised to the Nth power. N may be negative and may contain a decimal point. To raise numbers other than e to a power, use the ** operator.`n`nFloor(Number): Returns Number rounded down to the nearest integer (without any .00 suffix). For example, Floor(1.2) is 1 and Floor(-1.2) is -2.`n`nLog(Number): Returns the logarithm (base 10) of Number. The result is formatted as floating point. If Number is negative, an empty string is returned.`n`nLn(Number): Returns the natural logarithm (base e) of Number. The result is formatted as floating point. If Number is negative, an empty string is returned.`n`nMod(Dividend, Divisor): Modulo. Returns the remainder when Dividend is divided by Divisor. The sign of the result is always the same as the sign of the first parameter. For example, both mod(5, 3)and mod(5, -3) yield 2, but mod(-5, 3) and mod(-5, -3) yield -2. If either input is a floating point number, the result is also a floating point number. For example, mod(5.0, 3) is 2.0 and mod(5, 3.5) is 1.5. If the second parameter is zero, the function yields a blank result (empty string).`n`nRound(Number [, N]): If N is omitted or 0, Number is rounded to the nearest integer. If N is positive number, Number is rounded to N decimal places. If N is negative, Number is rounded by N digits to the leftof the decimal point. For example, Round(345, -1) is 350 and Round (345, -2) is 300. Unlike Transform Round, the result has no .000 suffix whenever N is omitted or less than 1. In v1.0.44.01+, a value of N greater than zero displays exactly N decimal places rather than obeying SetFormat. To avoid this, perform another math operation on Round()'s return value; for example: Round(3.333, 1)+0.`n`nSqrt(Number): Returns the square root of Number. The result is formatted as floating point. If Number is negative, the function yields a blank result (empty string).
Gui, 2:Font, s8 Bold, Arial
Gui, 2:Add, Text, +xm Section w900 center, Trigonometry
Gui, 2:Font, s8 Norm, Arial
Gui, 2:Add, Text, +xm +ys+15 w900, Sin(Number) | Cos(Number) | Tan(Number) : Returns the trigonometric sine|cosine|tangent of Number. Number must be expressed in radians.`n`nASin(Number): Returns the arcsine (the number whose sine is Number) in radians. If Number is less than -1 or greater than 1, the function yields a blank result (empty string).`n`nACos(Number): Returns the arccosine (the number whose cosine is Number) in radians. If Number is less than -1 or greater than 1, the function yields a blank result (empty string).`n`nATan(Number): Returns the arctangent (the number whose tangent is Number) in radians.`n`nNote: To convert a radians value to degrees, multiply it by 180/pi (approximately 57.29578). To convert a degrees value to radians, multiply it by pi/180 (approximately 0.01745329252). The value of pi (approximately 3.141592653589793) is 4 times the arctangent of 1.`n
Gui, 2:Font, s8 Bold, Arial
Gui, 2:Add, Text, +xm w900 center, Press 'Esc' to close this window
Gui, 2:Color, White
Gui, 2:Show, , Help File
;Gui, 2:+LastFound +0x200000 +Resize +0x2000000
;Winset, Style, +0x200000, Help File
;OnMessage(0x115, "OnScroll") ; WM_VSCROLL
;OnMessage(0x114, "OnScroll") ; WM_HSCROLL
;Gui, 2:; WS_VSCROLL | WS_HSCROLL
;Gui, 2:+Resize
Return
2GuiEscape:
Gui, 1:-Disabled
Gui Destroy
Return
Guisize:
settitlematchmode, 3
;Guicontrol, Move, edithistory, w100 h100
Anchor("editdescription", "w")
Anchor("edithistory", "wh")
Anchor("editcalculate", "yw")
Anchor("history", "yw")
Anchor("input", "yw")
controlgetpos, , yvar,,,edit2,Mike's Calculator
controlmove, static2,, yvar - 20,,,Mike's Calculator
Return
Anchor(i, a = "", r = false) { ; Thanks to Titan and all who contributed to the anchor function!
static c, cs = 12, cx = 255, cl = 0, g, gs = 8, z = 0, k = 0xffff, gx = 1
If z = 0
VarSetCapacity(g, gs * 99, 0), VarSetCapacity(c, cs * cx, 0), z := true
If a =
{
StringLeft, gn, i, 2
If gn contains :
{
StringTrimRight, gn, gn, 1
t = 2
}
StringTrimLeft, i, i, t ? t : 3
If gn is not digit
gn := gx
}
Else gn := A_Gui
If i is not xdigit
{
GuiControlGet, t, Hwnd, %i%
If ErrorLevel = 0
i := t
Else ControlGet, i, Hwnd, , %i%
}
gb := (gn - 1) * gs
Loop, %cx%
If (NumGet(c, cb := cs * (A_Index - 1)) == i) {
If a =
{
cf = 1
Break
}
Else gx := A_Gui
d := NumGet(g, gb), gw := A_GuiWidth - (d >> 16 & k), gh := A_GuiHeight - (d & k), as := 1
, dx := NumGet(c, cb + 4, "Short"), dy := NumGet(c, cb + 6, "Short")
, dw := NumGet(c, cb + 8, "Short"), dh := NumGet(c, cb + 10, "Short")
Loop, Parse, a, xywh
If A_Index > 1
av := SubStr(a, as, 1), as += 1 + StrLen(A_LoopField)
, d%av% += (InStr("yh", av) ? gh : gw) * (A_LoopField + 0 ? A_LoopField : 1)
DllCall("SetWindowPos", "UInt", i, "Int", 0, "Int", dx, "Int", dy, "Int", dw, "Int", dh, "Int", 4)
If r != 0
DllCall("RedrawWindow", "UInt", i, "UInt", 0, "UInt", 0, "UInt", 0x0101) ; RDW_UPDATENOW | RDW_INVALIDATE
Return
}
If cf != 1
cb := cl, cl += cs
If (!NumGet(g, gb)) {
Gui, +LastFound
WinGetPos, , , , gh
VarSetCapacity(pwi, 68, 0), DllCall("GetWindowInfo", "UInt", WinExist(), "UInt", &pwi)
, NumPut(((bx := NumGet(pwi, 48)) << 16 | by := gh - A_GuiHeight - NumGet(pwi, 52)), g, gb + 4)
, NumPut(A_GuiWidth << 16 | A_GuiHeight, g, gb)
}
Else d := NumGet(g, gb + 4), bx := d >> 16, by := d & k
ControlGetPos, dx, dy, dw, dh, , ahk_id %i%
If cf = 1
{
Gui, +LastFound
WinGetPos, , , gw, gh
d := NumGet(g, gb), dw -= gw - bx * 2 - (d >> 16), dh -= gh - by - bx - (d & k)
}
NumPut(i, c, cb), NumPut(dx - bx, c, cb + 4, "Short"), NumPut(dy - by, c, cb + 6, "Short")
, NumPut(dw, c, cb + 8, "Short"), NumPut(dh, c, cb + 10, "Short")
Return, true
}
Print( edit ){ ;Thanks to Fry for this and for majkinetor for surprising him with a better version!
FileAppend %edit%, Calculations.txt
Run, notepad /p calculations.txt
Sleep, 1500
FileDelete, calculations.txt
}
|
_________________ My perfect script:
Gui, Font, s14 cTan norm, Arial
Gui, add, UpDown, vMyUpDown
Gui, Show, Autosize, Arial
If Arial not contains % large * 2
Gui, Destroy |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4710 Location: Boulder, CO
|
Posted: Tue Apr 29, 2008 12:38 am Post subject: |
|
|
The main point of the thread was to run the calculator on machines w/o AHK. The last version is only 40 lines, and uses no temporary files. If you need a more complete solution, look here. It uses Lexikos low level AHK functions for dynamically execute AHK code. It also runs without temp files and on machines, where AHK is not installed.
If you use temp files, 10 lines are enough for a simple calculator.
Still, your version has a nice GUI, and menus. Well done! |
|
| Back to top |
|
 |
wep
Joined: 01 Jul 2008 Posts: 2
|
Posted: Wed Jul 09, 2008 6:19 pm Post subject: Re: Simple script for evaluating arithmetic expressions |
|
|
| Laszlo wrote: | | It can be used to build a calculator ... |
So I used it. Thanks.
Try my WinMouseTipCalculator for arithmetic calculations.
| Code: |
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;-= WinKey Enhancement Project =-;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;wep.dcmembers.com;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;; WinMouseTipCalc ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;Do input arithmetic expression with +,-,* and / math signs holding <Win>-key;;;
;;; <Win>+<NumPad numbers> inputs digits ;;;
;;; <Win+<Backspace> clears last digit in the input ;;;
;;; <Win>+<NumpadEnter> gives result ;;;
;;; <Win>+<Enter> also copies result to the clipboard ;;;
;;; <Win+<Esc> clear expression (input) ;;;
;;; <Win+<Ins> inserts result to active window into the text cursor ;;;
;;; <Win>+<=> copies selected expression and gives result instead of it ;;;
;;; <Win>+<End> copies selected expression then inserts full result equation ;;;
;;; <Win>+<Up> & <Win>+<Down> set roundoff for the result ;;;
;;; <Win>+<PageUp> add "$"-sign at the start position of result ;;;
;;; <Win>+<PageDown> add "%"-sign at the end position of result ;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
TRAYMENU:
Menu,Tray,NoStandard
Menu,Tray,DeleteAll
Menu,Tray,Add,E&xit,EXIT
A=
p=6
SetFormat, Float, 0.64
Gosub, TIP
#PgUp::
A:="$" . A
ToolTip, %A%
return
#PgDn::
A:=A . "%"
ToolTip, %A%
return
#1::
p=1
Gosub, TIP
return
#2::
p=2
Gosub, TIP
return
#3::
p=3
Gosub, TIP
return
#4::
p=4
Gosub, TIP
return
#5::
p=5
Gosub, TIP
return
#6::
p=6
Gosub, TIP
return
#7::
p=7
Gosub, TIP
return
#8::
p=8
Gosub, TIP
return
#9::
p=9
Gosub, TIP
return
#0::
p=0
Gosub, TIP
return
#Numpad0::
A=%A%0
ToolTip, %A%
return
#Numpad1::
A=%A%1
ToolTip, %A%
return
#Numpad2::
A=%A%2
ToolTip, %A%
return
#Numpad3::
A=%A%3
ToolTip, %A%
return
#Numpad4::
A=%A%4
ToolTip, %A%
return
#Numpad5::
A=%A%5
ToolTip, %A%
return
#Numpad6::
A=%A%6
ToolTip, %A%
return
#Numpad7::
A=%A%7
ToolTip, %A%
return
#Numpad8::
A=%A%8
ToolTip, %A%
return
#Numpad9::
A=%A%9
ToolTip, %A%
return
#BackSpace::
A:= SubStr(A, 1 , (StrLen(A)-1))
ToolTip, %A%
return
#NumpadDot::
A=%A%.
ToolTip, %A%
return
#NumpadDiv::
A=%A%/
ToolTip, %A%
return
#NumpadMult::
A=%A%*
ToolTip, %A%
return
#NumpadAdd::
A=%A%+
ToolTip, %A%
return
#NumpadSub::
A=%A%-
ToolTip, %A%
return
#NumpadEnter::
if SubStr(A, 1, 1)="-" OR SubStr(A, 1, 1)="+"
A=0%A%
A:= Eval(A)
A:= A=Round(A, 0) ? Round(A, 0) : Round(A, p)
ToolTip, %A%
Return
#Enter::
if SubStr(A, 1, 1)="-" OR SubStr(A, 1, 1)="+"
A=0%A%
A:= Eval(A)
A:= A=Round(A, 0) ? Round(A, 0) : Round(A, p)
clipboard:=A
clipboard = %clipboard%
ToolTip, %A%
Return
#Esc::
A=
ToolTip, %A%
return
#Ins::
result:= A_PriorHotkey = "#Ins" ? "=" A : A
result = %result%
SendRaw, %result%
if (A_PriorHotkey = "#Ins")
Send {Enter}
if SubStr(A, 1, 1)="-" OR SubStr(A, 1, 1)="+"
A=0%A%
A:= Eval(A)
A:= A=Round(A, 0) ? Round(A, 0) : Round(A, p)
ToolTip, %A%
Return
#End::
Send ^{Ins}
clipboard = %clipboard%
A:=clipboard
if SubStr(A, 1, 1)="-" OR SubStr(A, 1, 1)="+"
A=0%A%
A:= Eval(A)
A:= A=Round(A, 0) ? Round(A, 0) : Round(A, p)
ToolTip, %A%
SendRaw, %clipboard%=%A%
Return
#=::
Send ^{Ins}
clipboard = %clipboard%
A:=clipboard
if SubStr(A, 1, 1)="-" OR SubStr(A, 1, 1)="+"
A=0%A%
A:= Eval(A)
A:= A=Round(A, 0) ? Round(A, 0) : Round(A, p)
ToolTip, %A%
Return
#Down::
if (p>=1)
{
p-=1
}
Gosub, TIP
Return
#Up::
if (p<=63)
{
p+=1
}
Gosub, TIP
Return
;;;;;;;;;; script posted on the Autohotkey forum by Laszlo ;;;;;;;;;;
Eval(x)
{
StringGetPos i, x, +, R
StringGetPos j, x, -, R
If (i > j)
Return Left(x,i)+Right(x,i)
If (j > i)
Return Left(x,j)-Right(x,j)
StringGetPos i, x, *, R
StringGetPos j, x, /, R
If (i > j)
Return Left(x,i)*Right(x,i)
If (j > i)
Return Left(x,j)/Right(x,j)
Return x
}
Left(x,i)
{
StringLeft x, x, i
Return Eval(x)
}
Right(x,i)
{
StringTrimLeft x, x, i+1
Return Eval(x)
}
;;;;;;;;;;;;;;;;;;;;;;;;;end of Laszlo's code ;;;;;;;;;;;;;;;;;;;;;;;;
EXIT:
ExitApp
TIP:
TrayTip , WinMouseTipCalc, Result rounded to %p% decimal places, 2
Menu,Tray,Tip,WinMouseTipCalc`nResult rounded to %p% decimal places.
Return |
_________________ -= WinKey Enhancement Project (WEP) =- |
|
| Back to top |
|
 |
HotKeyIt
Joined: 18 Jun 2008 Posts: 4653 Location: AHK Forum
|
Posted: Sat Sep 06, 2008 12:54 pm Post subject: |
|
|
| Many thanks for this wonderful function Laszo. It is very useful. |
|
| Back to top |
|
 |
Laszlo
Joined: 14 Feb 2005 Posts: 4710 Location: Boulder, CO
|
Posted: Sat Sep 06, 2008 2:49 pm Post subject: |
|
|
| I am glad you found it useful. You could simplify the handling of unary + and a little more. Give it a try! It is a good exercise... |
|
| Back to top |
|
 |
HotKeyIt
Joined: 18 Jun 2008 Posts: 4653 Location: AHK Forum
|
Posted: Sun Sep 07, 2008 12:18 am Post subject: |
|
|
I use it as a quick calculator in my script, works perfect.
It is exactly what I am been looking for, especially brackets "(2+2)*2" are very useful for more complex calculation.
Very good job! |
|
| Back to top |
|
 |
|
|
You can post new topics in this forum You can reply to topics in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|