Sky Slate Blueberry Blackcurrant Watermelon Strawberry Orange Banana Apple Emerald Chocolate

# Monster: evaluate math expressions in strings

87 replies to this topic
• Moderators
• 4713 posts
• Last active: Mar 31 2012 03:17 AM
• Joined: 14 Feb 2005
If you want to evaluate a string, representing an arithmetic expression, you can use the Eval() function. Its parameter can be a literal string or a variable, containing a string, or even an AHK expression, resulting in a string of an arithmetic expression:
```b := "a"

a := "1+2"

MsgBox % Eval(%b%)```
The parameter of the Eval() function can contain other Eval() calls, so the recursion you are asking for is there. It just does not seem to be a good idea to generally change the meaning of %var% to Eval(%var%). It is an interesting idea you could gain some convenience with, but we loose consistency and possibilities.

• Members
• 774 posts
• Last active: Jan 04 2014 10:44 PM
• Joined: 24 Nov 2007
I have to read an arithmetic expression from Steam's skin definition file, replace some variables (which my function already does), and then evaluate the expression.

I was trying to start the daunting task of creating something like an Eval function for my SteamWin needs, when I found this.

Edit:

I initially posted to ask if I could use your functions from Monster in my script, but when looking further into them, I realized they are more generalized than I need. So as a result, I'm just going to use them as a reference in creating a lightweight eval function for simple math.

Thanks so much for this amazing script. I've learned a lot just from looking at it.

• Moderators
• 4713 posts
• Last active: Mar 31 2012 03:17 AM
• Joined: 14 Feb 2005
Here you find a much simpler version, which might be sufficient for your task. The following script is further simplified:
```MsgBox % Eval("-2+(-1+2)*3")

Eval(x) {   ; Evaluate arithmetic expression with numbers, + - / * ( )

Return Eval#(RegExReplace(x,"-","#")) ; # = subtraction, to distinguish from sign

}

Eval#(x) {  ; Evaluate expression with numbers, + #(subtract) / * ( ). Recurse into (..)

Return RegExMatch(x,"(.*)\(([^\(\)]+)\)(.*)",y) ? Eval#(y1 . [email protected](y2) . y3) : [email protected](x)

}

[email protected](x) {  ; Evaluate expression with numbers, + #(subtract) / *

RegExMatch(x,"(.*)(\+|#)(.*)",y)    ; last + or -

IfEqual y2,+, Return [email protected](y1) + [email protected](y3)

IfEqual y2,#, Return [email protected](y1) - [email protected](y3)

RegExMatch(x,"(.*)(\*|/)(.*)",y)    ; last * or /

IfEqual y2,*, Return [email protected](y1) * [email protected](y3)

IfEqual y2,/, Return [email protected](y1) / [email protected](y3)

Return x ? x : 0                    ; empty expression: 0, number: unchanged

}```

• Members
• 774 posts
• Last active: Jan 04 2014 10:44 PM
• Joined: 24 Nov 2007
Wow! I just finished writing a 51-line script to evaluate simple math expressions with parenthesis, and I feel completely and utterly humbled by the version you just posted. For some reason I didn't find the other script you linked to in my previous search, but I'm very glad for the new version you just posted above

It looks streamlined and lightweight, and it's perfect for my needs.

Thanks a million Laszlo!

• Members
• 40 posts
• Last active: Jan 12 2011 03:28 PM
• Joined: 17 May 2008
I chopped out the existing hotkeys, and am using the Eval() etc functions as a library. I then set up a hotkey for Cntl-C in my auto-start script, so that if hit twice quickly will Eval() the ClipBoard.

```#include MathMONSTER (Core) by Laszlo.ahk

\$^c::
if gvCtrlCTicks
{
if (( A_TickCount - gvCtrlCTicks ) < 501 )
{
MonsterClip := ClipBoard
if ( SubStr( MonsterClip, 0, 1) = "=" )
{
MonsterEval := Eval( SubStr(MonsterClip, 1, -1) )
a := MonsterClip . MonsterEval
}
else
{
MonsterEval := Eval( MonsterClip )
a := MonsterEval
}
ClipBoard := a
caretx := A_CaretX
carety := A_CaretY
if ( carety > 150 )
carety -= 25
else
carety += 20
ToolTip, %a%,caretx,carety,2
SetTimer, RemoveToolTipMonster, 1100
}
else
{
gvCtrlCTicks := A_TickCount
Send ^c
}
}
else
{
gvCtrlCTicks := A_TickCount
Send ^c
}
Return

RemoveToolTipMonster:
SetTimer, RemoveToolTipMonster, Off
ToolTip,,,,2
return
```

Thanks Laszlo for this great script!

Edit: I made a tweak in the Monster core, so instead of using "x" as a var prefix internally, it now uses "mmx":
```If RegExMatch(x, "(\S*?)\s*:=\s*(.*)", y) {
y := "x" . y1                    ; user vars internally start with x to avoid name conflicts
Return %y% := Eval1(y2)
}

x := RegExReplace(x,"([a-z_A-Z]\w*)([^\w'»’]|\$)","%x\$1%\$2") ; VAR -> %xVAR%
```
is now
```If RegExMatch(x, "(\S*?)\s*:=\s*(.*)", y) {
y := "mmx" . y1                    ; user vars internally start with x to avoid name conflicts
Return %y% := Eval1(y2)
}

x := RegExReplace(x,"([a-z_A-Z]\w*)([^\w'»’]|\$)","%mmx\$1%\$2") ; VAR -> %xVAR%
```
Enjoy,
Shawn

• Members
• 256 posts
• Last active: Oct 13 2009 01:27 PM
• Joined: 20 Aug 2008
Seriously, Laszlo, you should try getting into Assembly, this stuff you do with AHK only already is amazing.
-Chavez.

• Members
• 40 posts
• Last active: Jan 12 2011 03:28 PM
• Joined: 17 May 2008

Seriously, Laszlo, you should try getting into Assembly, this stuff you do with AHK only already is amazing.

He already has He's got more than a few posts of binary ASM code to use in-line in AHK scripts to speed up various operations.

• Members
• 49 posts
• Last active: Mar 12 2010 07:29 PM
• Joined: 07 Mar 2009
Need help! I noticed that Sin(), Tan() and other trigonometry functions, is used with radians. How can I make it usable with degrees? This what i found in ahk help file:
`Note: 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.`

• Moderators
• 4713 posts
• Last active: Mar 31 2012 03:17 AM
• Joined: 14 Feb 2005
```deg := 57.295779513082321

MsgBox % sin(30/deg)   ; sine of 30 degrees

MsgBox % deg*asin(0.5) ; arc sine of 0.5 in degrees```
In Monster you can use 180/pi in place of deg, that is:
```sin(30/180*pi)

180/pi*asin(0.5)```

• Members
• 49 posts
• Last active: Mar 12 2010 07:29 PM
• Joined: 07 Mar 2009
Thanks

• Members
• 1 posts
• Last active: Apr 23 2010 05:52 AM
• Joined: 23 Apr 2010

Monster: evaluate math expressions in strings w/o external programs

<!-- m -->http://rosettacode.o... ... AutoHotkey<!-- m -->

Thanks.

• Moderators
• 4713 posts
• Last active: Mar 31 2012 03:17 AM
• Joined: 14 Feb 2005
I have no objection, but Monster does not qualify:

an abstract-syntax tree (AST) for the expression must be created from parsing the input

.

• Spam Officer
• 2186 posts
• Last active: Nov 07 2015 08:15 AM
• Joined: 27 Feb 2009
Thanks Laszlo, very handy.
I was using the built-in constants and realized that you're using 1 gallon = 4.54609 liter (Imperial) rather than 3.785411784 liter (US)... :wink:

Marine Corps Gen. Joseph Dunford told senators at his Joint Chiefs of Staff confirmation hearing : “If you want to talk about a nation that could pose an existential threat to the United States, I'd have to point to Russia. And if you look at their behavior, it's nothing short of alarming.”

• Moderators
• 4713 posts
• Last active: Mar 31 2012 03:17 AM
• Joined: 14 Feb 2005

you're using 1 gallon = 4.54609 liter (Imperial) rather than 3.785411784 liter (US)

Thanks. I changed the first post to US gallon.

• Spam Officer
• 2186 posts
• Last active: Nov 07 2015 08:15 AM
• Joined: 27 Feb 2009
Why would this not give the correct result?:
`MsgBox % Eval("\$16 5.85")`

It gives me 5.8499999999999996. Other examples show similar error.

:?:

Marine Corps Gen. Joseph Dunford told senators at his Joint Chiefs of Staff confirmation hearing : “If you want to talk about a nation that could pose an existential threat to the United States, I'd have to point to Russia. And if you look at their behavior, it's nothing short of alarming.”