In this environment we measure efficiency in number of consumed Service Units. I'll convert the current dateTime to milliseconds to illustrate the bug:
0 100 100 100 100 100 1000⊥⎕TS ⍝ this statement consumes around 150 SUs
0 100 100 100 100 100 1000.0⊥⎕TS ⍝ this statement consumes around 5 SUs
What's going on here? Well, by attaching .0
to any of the terms in the left argument, we're telling the interpreter to go into float mode. Without it, it first tries to handle the operation with integers, notices that it isn't working and then retries in float mode.
The same trick can be used on the right argument, or by adding 0.0
, or by multiplying by 1.0
.
Out of curiousity I tried the same in Dyalog APL v15:
Hardly any difference there...
P.S: it is certainly ok to share knowledge by answering your own question - but to do that, you should also post the answer as "Answer" and not as part of the question. By doing so, you will be able to accept your own answer (after waiting a day or so) which will then close the question.
I imagine the following is happening: (one man's guess)
0 100 100 100 100 100 1000 is a 16 bit integer vector in Dyalog, probably 32 in APL2
⊥ would normally return the wider of the left or right argument types
⎕TS is also an integer vector, 16 or 32 bit integer
The answer is 2.017011212181701E16, approx. 20170112122036000 clearly a 64 bit (or greater) floating point number.
APL2 is betting that this decode operation will succeed using integer arithmetic. It first attempts to compute the decode using integer arithmetic, but then the operation fails on account of arithmetic overflow. APL2 then tries again using floating point. The increase in the timing includes trapping the overflow, cleanup, and doing it again.
Changing the left argument to 0 100 100 100 100 100 1000.0 causes decode to use 64 bit floating point arithmetic without first attempting integer arithmetic.
Dyalog possibly does not bother with this and does the decode in floating point.
Interestingly, on Dyalog, ⎕DR 0 100 100 100 100 100 1000 ⊥ 1 is 645, 64 bit floating point
+/ and +\ and others may have similar problems with overflow.
⎕DR +/21/100000000 is 323, 32 bit integer
⎕DR +/22/100000000 is 645, 64 bit float
It would be instructive to try these examples using GNU APL which uses 64 bit integers.