Multiplication or powers

Hi,

What is better (faster), multiplication with the asterisk, or raising to a power. For instance:

set n to 7
3 * 3 * 3 * 3 * 3 * 3 * 3
-- or
3 ^ n

Edited: the reason why I ask this is that I don’t think it’s measurable. I was hoping that someone might already know by theory. I’ll try it. Maybe run it 100,000 times.
p.s. I should use 3^7

Thanks,
kel

Hi,

Nevermind, I tested it and the powers lost:

--
delay 1run script (do shell script "python -c 'import time; print time.time()'") --dummy
set t1 to run script (do shell script "python -c 'import time; print time.time()'")
set t2 to run script (do shell script "python -c 'import time; print time.time()'")
set time_calib to t2 - t1
set t1 to run script (do shell script "python -c 'import time; print time.time()'")
--
repeat 10000 times
	3 * 3 * 3 * 3 * 3 * 3 * 3
end repeat
--
set t2 to run script (do shell script "python -c 'import time; print time.time()'")
set time_diff1 to t2 - t1 - time_calib
--
delay 1
--
run script (do shell script "python -c 'import time; print time.time()'") --dummy
set t1 to run script (do shell script "python -c 'import time; print time.time()'")
set t2 to run script (do shell script "python -c 'import time; print time.time()'")
set time_calib to t2 - t1
set t1 to run script (do shell script "python -c 'import time; print time.time()'")
--
repeat 10000 times
	3 ^ 7
end repeat
--
set t2 to run script (do shell script "python -c 'import time; print time.time()'")
set time_diff2 to t2 - t1 - time_calib

{time_diff1, time_diff2}

Edited: disregard this. I put the delay in the wrong place.:expressionless:

Edited: now you can’t tell the difference. Fixed the script.

Thanks anyway,
kel

That is really interesting to know.

I would have imagined that the multiplication be faster.

I have just discovered, that in order to truncate number properly, and correctly with AppleScript,
you really have to be careful, as the snippet below shows: Normally, as integer, will round up, but if you already have truncated an intermediary result with div, and are sure that you want it to the closes whole number afterwards, then you are safe with a coersion to “as integer”, but if you truncate it again with a div 1, then you may end up with a number one short.

Try this:

set x to 4.34
set h to (100 * (x - (x div 1))) as integer
# This is the interesting one!
set i to (100 * (x - (x div 1))) div 1
# Delivers wrong result in this case, and you can never know...
set j to (100 * (x - (x div 1)))

By the way, the primitive operations are done with 15.6 digits of precision… (15).
Handlers coming for Osax’s operates with 12 digits of precision.

Here are my tests…


set t1 to current date

repeat 10000000 times
	set i to 3 ^ 7
end repeat


set t2 to current date
set tdiff1 to t2 - t1

set t1 to current date

repeat 10000000 times
	set i to 3 * 3 * 3 * 3 * 3 * 3 * 3
end repeat

set t2 to current date
set tdiff2 to t2 - t1

get tdiff1 & ", " & tdiff2


results (2 runs) :

Powers / Multiplication:
1 - ( 67 / 66 ) seconds
2 - ( 69 / 65 ) seconds


set t1 to current date

repeat 5000000 times
	set i to 3 ^ 14
end repeat


set t2 to current date
set tdiff1 to t2 - t1

set t1 to current date

repeat 5000000 times
	set i to 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3 * 3
end repeat

set t2 to current date
set tdiff2 to t2 - t1

get tdiff1 & ", " & tdiff2

results (2 runs) :

Powers / Multiplication:
1 - ( 31 / 54 ) seconds
2 - ( 31 / 55 ) seconds

===

It seems then that it is more of a parsing issue?
Anyway, there are my tests.

===
PPC G4 800Mhz Dual
Applescript 1.10.7
OS-X Tiger

‘as integer’ rounds to the nearest integer, with .5 rounding to the nearest even integer.

Back on topic, my own timings for 10,000,000 iterations each of method, using the LapTime OSAX::

3 ^ 7: 8.755 seconds
3 * 3 * 3 * 3 * 3 * 3 * 3: 10.449 seconds

The first result varies by up to a tenth of a second and the seoond by up to half a second. This is in line with what I’d expect with one mathematical operation pitched against six.

The picture’s slightly skewed by the fact that the 3 and the 7 are integers. They’re automatically coerced to reals for the “power” operation, which is a real one. The row of seven 3s is multiplied throughout as integer operations. If all the numbers are changed to reals, the power operation is slightly faster, but the mutliplications take about twice as long!

3.0 ^ 7.0: 7.051 seconds
3.0 * 3.0 * 3.0 * 3.0 * 3.0 * 3.0 * 3.0: 20.464 seconds

I haven’t tested it all this time round, but logic would suggest that the higher the power, the greater the advantage to the power operator, especially with reals.

Hello.

It is nice to have the power versus multiplication operations sorted out! I (It didn’t work quite as I thought it would, because I believed that mulitplication of reals to be faster than the power of operation).

Staying a wee bit aside the main topic:

The only fix I see for truncating reals into integers correctly (positive), is to add 0.000000000001 to it, before getting the integer par, that is such a tiny fraction, that I think it shouldn’t hurt the overall accuracy of any calculations in AppleScript, but on the other hand, remove some rounding errors due to the fact that the numbers are binary.

set x to 4.34
set i to ((100 * (x - (x div 1))) + 1.0E-12) div 1

If by “truncate” you mean “return the first two decimal places of a real number as an integer”, it would be better to do the truncation outside the range in which the internal rounding inaccuracy occurs:

set x to 4.34
x * 1000 mod 1000 div 10

Hello.

That is a good one, for that particular case. I was thinking more of a general solution, like the INT function in various basic dialects, but adjusting for the conversion between binary storage/decimal representation, in AppleScript, in that it adjusts for internal rounding problems.

set x to 4.34
set y to INT((100 * (x - (INT(x)))))
to INT(x)
	if x < 0 then
		return ((x - 1.0E-12) div 1)
	else if x ≠ 0 then
		return ((x + 1.0E-12) div 1)
	else
		return 0
	end if
end INT

Edit

Using a handler, is no better than doing the math straight away as Nigel does, but if you factor out the math, for formulas to become more readable anyway, then this is slightly cheaper. And given the quality of my typist, this approach is a safer one, with regards to neglects, etc, than writing the incantation, inline in the formula, where you’d have to use Nigel’s approach anyway, if you don’t know the quantity to be negative or positive up front. :wink:

The inaccuracy’s introduced when the fractional part is snipped directly from the given real, before INT() gets a look-in. It happens even with the less clumsy ‘x mod 1’.

set x to 4.34
{x - x div 1 = 0.34, x mod 1 = 0.34}
--> {false, false}

Knowing this, it’s better to have the fractional-part-snipping process avoid the inaccuracy than to add unnecessary garbage (which won’t work if the inaccuracy goes the other way) to INT(), which is of course not needed in AppleScript anyway.

set x to 4.34
set y to INT(x * 1000 mod 1000 / 10)

to INT(x)
	return x div 1
end INT

I agree whole heartedly, I think think however, the best solution will depend upon the way the expressions originated in the first hand: Now that I know this, I can take precautions, and write the formula, so it should work properly from the start; taking inaccuracies into account up front. On the other hand: If I have a piece of Pascal or Basic code that uses the INT function in the middle of some expression (or a C cast to integer), then I think at least I will be much better with using an INT handler, than starting to rewrite the expression. Because there may be unforeseen consequences, and I should save a lot of time, by not having to sort any of the consequences out, but just use the INT handler blindly. :slight_smile:

EDIT

The fraction handler, that returns the decimal part of a floating point value is a much simpler:
Her you don’t have to consider the intrinisic inaccuracies, if you do, then you’ll end up with an even more inaccurate result.

to FRAC(x)
	if x < 0 or x > 0 then
		return x mod 1
	else
		return 0
	end if
end FRAC

Hello.

Here is a power handler, I have written using the exp and ln verbs of Satimage.Osax, I haven’t the imagination at the moment, as to how to compare it to the built in ^ operator, nor test if for speed, but I am sure it is slower, in all respects, but maybe more accurate.

to pow(base, exponent)
	return (exp (exponent * (ln base)))
end pow

I haven’t found any edge - case where it differs, but the operation, is much more heavy than using the ^ operator, so this was an exercise only.

Please learn not to hijack threads or wander off-topic. You’ve been told enough times.

I moved it.

I just felt that the subjects were reasonable interconnected. No harm intended. :slight_smile:

Hi,

Interesting comparisons. I didn’t that there would be differences in accuracy for real numbers also.

And, thanks for the different testings on speed.

I’ll check these out. I just woke up. Need my coffee. :slight_smile:

Thanks a lot,
kel

Hello.

This is a technique that is named Horners Rule, that proves for efficent multiplication of powers. When plugging in a value into a formula that consists of powers, the most efficient way may be to do like below, in order to minimize the number of multiplications.

(5 + 2x + 3x^3 + 4X^4 )

set a to 5 + x * (2 + x * (3 + 4 * x))

A further descriptions of Horners Rule/Method, can be found here.

Hi McUsr,

Interesting stuff. I think I’ve seen that formula at this site before. The link to the Horner’s rule was blank so I made this from the algorithm:

-- ax^n where a=1, x=3, n=7
set a to 1
set x to 3
set n to 7
set r to a -- the result
repeat while n > 0
	set r to r * x
	set n to n - 1
end repeat
{r, 3 ^ 7}

No error checking. I guess you just need to expand n times (degree of the polynomial).

On the other hand, I think that for powers greater than 2, it’s better to use the power operator. I need to reread what everyone posted again.

Edited: changed the repeat loop to account for n<0.

Thanks a lot,
kel

Hello.

Kell, now what you have written is supposedly what is going on behind the scenes, in applescript, we can write the polynomial fully out, in one go, which I think you can’t at all times. That is at least how I relearned it from a book, as I also thought that your variant of it, is the way to do it, but heck, you can just have the coeffecients for the terms in the code, as variables, and if necessary calculate them up front.

(I timed the scheme I posted above, and it seemed faster than multiplying all of the terms out, for 1000 iterations, for figures over 1000, then spelling out the expression “normally” seemed faster.

I don’t see me iterate more than say 100 times, so for me Horners rule is good.

I also agree about the powers of, when the exponents are real, which they often are!

I think you can or should be able to optimize such a calculation a little bit further, by factoring the power function (^) into exp and ln statements, so that you only raise the logarithm by the exponent in the final step, for the last result.

It should save some, if it is needed.

Edit

It is really odd that the link doesn’t work, because it works from Google, without being cached, it is the page from rosettacode.org.

Hi McUsr,

I know it’s the long way to do it, but I just wanted to see how your scheme was derived.

BTW, did you know that the full moon is coming up on the 19th? :slight_smile:

Later,
kel

Hello.

That is the way you would do it, if you got your polynomial from a string or so, and didn’t know the polynomial up front.

When it comes to the second part of my post above, describing a scheme for replacing the internal power operator with external exp and ln verbs, well that will probably work better , in languages, that doesn’t have the event model, like Applescript, because here the overhead of sending an event for calling exp or ln, will matter much.

Nice to know about the full moon, pretty big already, I use “Stellarium” at times. :slight_smile: