A faster modulus operation

Hello.

Here are two scripts with timings, one with the regular modulus function, and one with the rev function. The result may surprise you! :slight_smile:

Slow version:

set t0 to (current date)
repeat with i from 1 to 1000
	set a to ((random number) * 100 * 360) mod 360
end repeat
set t1 to (current date) - t0

Fast version:

set t0 to (current date)
repeat with i from 1 to 1000
	set a to rev((random number) * 100 * 360)
end repeat
set t1 to (current date) - t0

on rev(x)
	return x - ((x div 360.0) * 360.0)
end rev

Hi.

If you put the ā€˜random numberā€™ call outside the repeats and do enough iterations to be measurable at the resolution of ā€˜current dateā€™ ā€ say 2,500,000 ā€ the result may surprise you! :wink:

Hello.

Well. I modified the code, and generated the data into a list, and now the results are pointing towards the mod operator as the best way to take the modulus, or reduce a number.

Script Debugger returned this as the result of the code below.

script o
	property l : {}
end script
repeat with i from 1 to 6000
	set end of o's l to (random number) * 100 * 360
end repeat

set t0 to (current date)
repeat with i from 1 to 6000
	set a to (item i of o's l) mod 360
end repeat
set t1 to (current date) - t0

For the one with the rev function, this was returned:

And here is the code.

script o
	property l : {}
end script
repeat with i from 1 to 6000
	set end of o's l to (random number) * 100 * 360
end repeat

set t0 to (current date)
repeat with i from 1 to 6000
	set a to rev(item i of o's l)
end repeat
set t1 to (current date) - t0

on rev(x)
	return x - ((x div 360.0) * 360.0)
end rev

The former reports from Script Debugger was something like this for the modulus:

And something like this for the one with the rev function.

But the times obtained by the date function in seconds reported grossly 50% less time for the last one, than for the former. (Both with the random number directly in the calls.)

Iā€™ll have to do some more measures, when it comes to osaxen calls with the modulus, and the rev() handler, but that the modulus handler is unsurpassed, when it comes to just processing a list of numbers, (which is something I canā€™t recall ever have done).

I may not like it, but it is most probable, that Script Debugger has the correct timing, I just donā€™t understand the disagreement with Script Debugger and the result of the date handler. It may very well be that I just started the script at odd places towards a second though.

Here is a last version, with the rev function inlined, which is a realistic thing to do, when you try to optimize the modulus function anyway. :slight_smile:

script o
	property l : {}
end script
repeat with i from 1 to 6000
	set end of o's l to (random number) * 100 * 360
end repeat

set t0 to (current date)
repeat with i from 1 to 6000
	set a to (item i of o's l) - (((item i of o's l) div 360.0) * 360.0)
end repeat
set t1 to (current date) - t0

Thatā€™s weird, in script editor there is no difference in time on my machine :expressionless:

I am not any wiser either, for all I know, I have posted an exact copy of the internals of the modulus operator, but where there is only one argument to interpret. The other thing is, that mayge when calling a Scripting addtions function in the call, makes for some more overhead, than calling it within the argument of a handler.

Those speculations are nothing to base optimizing to the bone on. :expressionless:

Actually, the pick of the random number handler, was a a good one, as it is transcedent, just like the cos and sin functions, that will go there in my real calls. As it is, I think the mod handler that I have, is as good as the rev handler, apart from one tiny detail, which is that there is only one argument to parse (the x variable). The other thing making it viable somewhere, is that Iā€™ll ā€œnormalizeā€ negative results at places, by adding the base, so Iā€™ll use a handler any way.

In the mean time, Iā€™ll try to figure out some conclusive tests. By the way, all results reported in previous posts, where from the second run, so it was all cached under equal terms.