AppleScript Speed Stunner: Round vs. Mod & Div

I was working on a routine the other day and, quite by accident discovered that the round() function is extremely slow. How slow? Compared to a routine that uses DIV and MOD functions, round() is significantly slower.

Here’s my Timing Test script, fitted with two different ways to round the results of a division to the nearest integer:

set theDivisor to 256
set theLoopCount to 20
set {theDividendStart, theDividendStop} to {120, 130}
 --bracket values around tipping points to show equivalent results

set t1 to the ticks
repeat theLoopCount times
    set resA to {}
    repeat with theDividend from theDividendStart to theDividendStop
        set theQuotient to round (theDividend / theDivisor)
        copy {theDividend, theQuotient} to end of resA
    end repeat
end repeat

set t2 to the ticks
repeat theLoopCount times
    set resB to {}
    repeat with theDividend from theDividendStart to theDividendStop
        if ((theDividend mod theDivisor) > (theDivisor div 2)) then
            set extra to 1
        else
            set extra to 0
        end if
        set theQuotient to (theDividend div theDivisor) + extra
        copy {theDividend, theQuotient} to end of resB
    end repeat
end repeat
set t3 to (the ticks) - t2

set {LoopA, LoopB} to {(t2 - t1) / theLoopCount, t3 / theLoopCount}
get {LoopA, LoopB, LoopA / LoopB, resA, resB}

On my old G4/733, round() is about 30 times slower.

There is even more of a disparity when you add “Rounding up|down” to the mix. The code for rounding up:

set theDivisor to 256
set theLoopCount to 100
set {TheDividendStart, theDividendStop} to {250, 260}

set t1 to the ticks
repeat theLoopCount times
    set resA to {}
    repeat with theDividend from TheDividendStart to theDividendStop
        set theQuotient to round (theDividend / theDivisor) rounding up
        copy {theDividend, theQuotient} to end of resA
    end repeat
end repeat
set t2 to the ticks

repeat theLoopCount times
    set resB to {}
    repeat with theDividend from TheDividendStart to theDividendStop
        if ((theDividend mod theDivisor) = 0) then
            set extra to 0
        else
            set extra to 1
        end if
        set theQuotient to (theDividend div theDivisor) + extra
        copy {theDividend, theQuotient} to end of resB
    end repeat
end repeat
set t3 to (the ticks) - t2

set {LoopA, LoopB} to {(t2 - t1) / theLoopCount, t3 / theLoopCount}
get {LoopA, LoopB, LoopA / LoopB, resA, resB}

And rounding down is even simpler:

set theDivisor to 256
set theLoopCount to 100
set {TheDividendStart, theDividendStop} to {250, 260}

set t1 to the ticks
repeat theLoopCount times
    set resA to {}
    repeat with theDividend from TheDividendStart to theDividendStop
        set theQuotient to round (theDividend / theDivisor) rounding down
        copy {theDividend, theQuotient} to end of resA
    end repeat
end repeat

set t2 to the ticks
repeat theLoopCount times
    set resB to {}
    repeat with theDividend from TheDividendStart to theDividendStop
        set theQuotient to (theDividend div theDivisor)
        copy {theDividend, theQuotient} to end of resB
    end repeat
end repeat
set t3 to (the ticks) - t2

set {LoopA, LoopB} to {(t2 - t1) / theLoopCount, t3 / theLoopCount}
get {LoopA, LoopB, LoopA / LoopB, resA, resB}

In these tests, Round() rounding up|down runs about 50 times slower than the same function written with DIV and MOD.

At this point I am curious about two things. First: is round() any faster on Intel? Second: what sort of timings would you get for equivalent routines written in C (or its variants)?

Apr 18, 2009 1:00 PM

google_pluslinkedingoogle_pluslinkedinby feather

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.