In many of my macros I need to generate a random number. The two builtin functions RAND(X) and RANDOM(X) let you get a random number from ZERO to Positive X. I generally need a number from -X to +X. So I have found four different ways to solve this, but they are all ugly. Very ugly. There's no need to explain them here. A neat solution would be if Keyboard Maestro supported this directly. (Or better, if it allowed us to declare functions.) In my view, the simplest solution is to extend the RANDOM function to support two parameters: RANDOM(Low,High) which would return a random number from Low to High. In that case I could call it like this: RANDOM(-X,X). Or if the language doesn't allow this then a new function could solve it like this: RANDOMXY(X,Y). Naturally the language doesn't get changed just because I ask, but I think this would be an exceptionally simple enhancement to implement. An alternative solution is to create the function RANDOMSIGN() which returns either 1 or -1. If a parameter was passed to RANDOMSIGN like this, RANDOMSIGN(X), it could return a random number from -X to +X. This method has the advantage of not having to repeat X, which is often a long expression.
What methods are you using at the moment ? You mentioned four that are very ugly.
What I would do is:
RANDOM(2*X) - X
Word of advise - when asking for a feature, never explain how it is “exceptionally simple” to implement - pretty much everything is much more complicated than you would think.
Sorry Peter. Hope I'm not on your bad side. You are my hero. Great product.
Not at all, it's just friendly (unsolicited) advise. Actually, it is probably a very good rule in general: If you are asking for something, don't attempt to understate the required effort of the person you are asking it of, basically the difference between:
I know this is asking a lot, but could you do XYZ?
as opposed to:
Could you do XYZ, it wont take you much effort?
The former is almost always a better approach since it better honours to work of the provider.
If X is a long expression, as I indicated it "often" is, then that idea doesn't work well because I have to repeat the long expression and edit two expressions each time I edit it. But thanks.
Yes. You are right. I bungled that. I'm normally a pretty nice guy but on that point I wasn't.
No problem at all. I took no offence, and in this case it is pretty close to accurate, although there is always some level of question when you have varying numbers of parameters.
No promises, but it is on the todo list.
Just for the curious, here's one of my methods. It might prove to be helpful to people:
In the above example if I replace "100" by some long expression I don't have to edit the expression twice, unlike the method shown by CJK.
Thanks Peter. Hey, I just did a search of my macros and I have 179 different macros that contain the string "RANDOM(" and 128 macros that contain "RAND(". Many macros contain multiple calls so I would estimate I call one of these two functions about 1000 times. Off the top of my head I would guess about half of them include arithmetic to return a negative value. So I would save a lot of work if you are able to implement something to help me out.
You could store the long expression in a variable with a short name.
OK, this solution isn't so ugly, as you put it. I think it's fine, although that's less important than what you think since you're the one dealing with it.
Hmm, I could store the expression in a variable? Cool idea. Thanks. Interesting. I'll consider it. But that means I have to add over 500 actions to my programs, which by my definition, is ugly.
Nobody mentioned that with the idea I proposed, the chance of getting a zero is double the chance of any other number. So if you need perfect random, it's a bad idea. But for many applications, like mine, that's fine.
Very curious: what are these macros doing ? You don't have to answer, of course, I'm just being nosey.
Absolutely – I personally never respond to the (startlingly numerous) requests that take that form
(when things are so simple and effortless, it really seems an awful pity to deprive the OP of the pleasure of doing it themselves ...)
You asked me why I use RAND functions.
I use $9 servos to build things and I control the servos with a variety of inputs and one of those inputs is random data. Of course the random data is based on real world measurements which is why I pass expressions to the RAND functions. If you dig into my older posts I think I probably mentioned this once before.
As to what I'm building, I'll keep that to myself for the moment. But it's not Skynet, as my coworkers have often accused me of building. If you aren't sure what I'm talking about, or if you just want a laugh, go to youtube and search for the video "Terminator 3 Skynet Takes Over". I think people like Elon Musk are talking a lot about this as a real world threat. Don't worry about helping me: all I build is toys, not robots to take over the world.
With all of Keyboard Maestro's triggers I find it a good language to interface with the real world. It has several triggers based on the clock, and a couple based on USB devices, a MIDI trigger, a folder trigger, etc. (I haven't used the gesture trigger yet although that deals with hardware too.) Some of these I use extensively to get data from the outside world. I would like to see more features in KM that interface with the outside world. Like maybe Homekit triggers. Or audio (volume) or video (motion) triggers. Or triggers that integrate with SiriKit. But these are features that I won't say "will be exceptionally simple enhancements."
From -30 to 30 in a shell script.
seq -30 30 | shuf -n 1
shuf is a GNU Utility that must be installed by the user.
I expect there're buku functions available in Perl or Python.
You should be able to create a sub-macro as sophisticated as you like and call it at need.
That's a creative idea and I appreciate it. I enjoy script ideas. Just for fun I googled how to use the shell to generate random numbers. Lots of ways to do that. In fact using a macro was one of the four methods I rejected, and the reason I rejected it would be that I would have to create a macro call roughly 500 times, with approximately the same number of new variables (since many of my macros can run concurrently, I can't use the same variable for any of them.)
I'm not really satisfied with 500 new actions and 500 new variables.
In case you are interested, you can eliminate the GNU requirement in a variety of ways, perhaps like this:
Here's another solution like yours which has a certain elegance and cleanliness:
seq -100 100 | sort -R | head -n 1
There are other solutions using shell but some of them use the same formatting characters as this website uses to format text so I can't show them here.
Ah, I'm happy to see
RANDOM has the syntax for negative numbers. I didn't find it in my rather cursory look on the exchange sites.
That's nice, although like
shuf it requires the user to install a later version of
sort (at least on my macOS 10.12.6 system).
On my system
sort doesn't have the
Remember that the Execute a Macro action can take a parameter.