Given a double number D on the stack, what's a reasonable way of looping D times? I recently needed to do this to support file reading on a 16-bit Forth.
Clearly you can just make a loop by counting down:
begin
<something>
-1. d+ 2dup d0=
until
2drop
But there is a more elegant arrangement using a nested pair of DO..LOOPs.
The inspiration is this ancient Z80 technique of using two 8-bit loops to form a 16-bit counter: http://map.grauw.nl/articles/fast_loops.php
The Forth equivalent looks quite
: prep over 0<> - ;
...
prep 0 do
0 do
<whatever>
loop 0
loop drop
prep adjusts the loop counter, incrementing the high count only if the low count is nonzero.
So for example a loop count of $123456 would be represented on the stack as:
$3456 $12
prep adjusts the high count to $13:
$3456 $13
So the outer DO..LOOP executes $13 times. The first inner do executes $3456 times. The subsequent iterations are all performing:
0 0 DO .. LOOP
and hence execute $10000 times.
This works well, but there does not seem to be an easy way of computing the double counter value.
There is a small further optimization possible. Instead of adjusting the outer loop counter, prep can compute compute a DO..LOOP starting value of either 0 or -1:
: prep over 0<> ;
...
prep do
0 do
<whatever>
loop 0
loop drop