for bug?
[1/23] from: rotenca:telvia:it at: 16-Jun-2002 20:41
In a console
for x #"^(00)" #"^(ff)" 1 [print to integer! x]
-> endless loop
A bug or something i do not understand?
---
Ciao
Romano
[2/23] from: joel:neely:fedex at: 16-Jun-2002 16:42
Hi, Romano,
It has to do with (non-intuitive IMHO) handling of arithmetic
on character values...
Romano Paolo Tenca wrote:
> In a console
>
> for x #"^(00)" #"^(ff)" 1 [print to integer! x]
>
> -> endless loop
>
No matter how many times you add 1 to a character value, it
will never be greater than #"^(ff)" (believe it or not!)
>> foo: #"^(ff)"
== #"ÿ"
>> foo + 1
== #"^@"
>> to-integer foo + 1
== 0
You might have been expecting that
>> (to-integer foo) + 1
== 256
would cause the loop to exit once the counter had exceeded
the stated upper bound, but...
>> to-char (to-integer foo) + 1
** Math Error: Math or number overflow
** Where: to-char
** Near: to char! :value
On the other hand,
for x to-integer #"^(00)" to-integer #"^(ff)" 1 [print x]
works just fine, and you can use the phrase
to-char x
inside the body of the FOR if you really wanted to do something
with all possible character values.
-jn-
--
; Joel Neely joeldotneelyatfedexdotcom
REBOL [] do [ do func [s] [ foreach [a b] s [prin b] ] sort/skip
do function [s] [t] [ t: "" foreach [a b] s [repend t [b a]] t ] {
| e s m!zauafBpcvekexEohthjJakwLrngohOqrlryRnsctdtiub} 2 ]
[3/23] from: g:santilli:tiscalinet:it at: 17-Jun-2002 0:44
Hi Romano,
On Sunday, June 16, 2002, 8:41:22 PM, you wrote:
RPT> A bug or something i do not understand?
>> #"^(ff)" + 1
== #"^@"
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r
[4/23] from: rotenca:telvia:it at: 17-Jun-2002 8:11
Hi Joel and Gabriele,
thanks for your answers.
My point of view is that if 'for accepts unsigned integer, it must know how to
handle them.
In my expression i have asked to stop at 255 not at something > 255. I think
that 'for should be an until loop:
until [
...
i >= 255
]
not a while loop:
while [i > 255][
...
]
else 'for couldn't handle unsigned value in the right mode and it should not
accept values it does not know how to handle.
But perhaps others languages have this limitation in their for loop with
unsigned values. Joel do you confirm this?
---
Ciao
Romano
[5/23] from: joel:neely:fedex at: 17-Jun-2002 7:44
Hi, Romano,
Romano Paolo Tenca wrote:
> My point of view is that if 'for accepts unsigned integer,
> it must know how to handle them.
<<quoted lines omitted: 6>>
> not a while loop:
> while [i > 255][
i <= 255 ;; just a typo
> ...
> ]
>
> else 'for couldn't handle unsigned value in the right mode
> and it should not accept values it does not know how to handle.
>
The problem with post-condition tests is their inability to
do nothing gracefully
. In the case
>> for i 3 2 1 [print i]
== none
which can be understood as
print each number i in the range [3 <= i <= 2] stepping by 1
nothing should print, because the range is empty.
> But perhaps others languages have this limitation in their for
> loop with unsigned values. Joel do you confirm this?
>
The issue is not unsigned values, but rather what happens at the
edge of a finite domain (and, with programming, all elementary
domains are finite... ;-)
Consider the following:
>> for i 2147483640 2147483647 1 [print i]
2147483640
2147483641
2147483642
2147483643
2147483644
2147483645
2147483646
2147483647
** Math Error: Math or number overflow
** Where: for
** Near: start: start + bump
versus
>> a: #"^(fa)"
== #"ú"
>> loop 6 [print mold a: a + 1]
#"û"
#"ü"
#"ý"
#"þ"
#"ÿ"
#"^@"
versus
>> a: 255.255.255.250
== 255.255.255.250
>> loop 6 [print a: a + 1]
255.255.255.251
255.255.255.252
255.255.255.253
255.255.255.254
255.255.255.255
255.255.255.255
So, REBOL handles hitting the limit of a domain in at least three
distinct ways, depending on type:
1) throwing an error integer!
2) wrapping within domain char!
3) "sticking" at the limit tuple!
Anyone know of any others?
IMHO any effort to redefine the behavior of FOR should address
the following issues:
- REBOL's use of strongly-typed values (e.g. (#"^(ff)" + 1)
evaluates to char! rather than widening to integral 256)
- the ability to do nothing gracefully
- the handling of limit values
- minimizing overhead (maximizing performance)
I don't have a good answer at this point, but we are talking
about a limited number of special cases where this happens
(max values for the types {number series money time date char}).
-jn-
--
; Joel Neely joeldotneelyatfedexdotcom
REBOL [] do [ do func [s] [ foreach [a b] s [prin b] ] sort/skip
do function [s] [t] [ t: "" foreach [a b] s [repend t [b a]] t ] {
| e s m!zauafBpcvekexEohthjJakwLrngohOqrlryRnsctdtiub} 2 ]
[6/23] from: joel:neely:fedex at: 17-Jun-2002 8:49
Hi, again, Romano and list,
Joel Neely wrote:
> Romano Paolo Tenca wrote:
> >
<<quoted lines omitted: 11>>
> print each number i in the range [3 <= i <= 2] stepping by 1
> nothing should print, because the range is empty.
...
> IMHO any effort to redefine the behavior of FOR should address
> the following issues:
>
...
> - minimizing overhead (maximizing performance)
>
It is interesting that replacing
while [op end start] [
start: start + bump
]
with
if op end start [
until [
start: (old: start) + bump
]
]
would actually appear to improve performance, as well as addressing
Romano's issue with #"^(ff)" as an upper loop bound.
-jn-
[7/23] from: rotenca:telvia:it at: 17-Jun-2002 16:19
Hi Joel,
> 1) throwing an error integer!
> 2) wrapping within domain char!
> 3) "sticking" at the limit tuple!
>
> Anyone know of any others?
I have found a sort of signed integer which wraps (but in a strange mode):
x: to time! 2147483646 loop 5 [print x: x + 1]
596523:14:07
--596523:-14:-08 ; ?
-596523:14:07
-596523:14:06
-596523:14:05
---
Ciao
Romano
[8/23] from: rotenca:telvia:it at: 17-Jun-2002 16:47
Hi Joel,
> The problem with post-condition tests is their inability to
> "do nothing gracefully". In the case
<<quoted lines omitted: 3>>
> print each number i in the range [3 <= i <= 2] stepping by 1
> nothing should print, because the range is empty.
It seems to me that the solution is a pre-conditon test and a post-condition
test with something like:
myfor: func ['word start end bump body /local i do-body][
do-body: func reduce [[throw] word] body
i: start
while [i <= end] [
do-body i
if i >= end [break]
i: i + bump
]
]
This slows code a little, i admit.
> Consider the following:
> >> for i 2147483640 2147483647 1 [print i]
<<quoted lines omitted: 9>>
> ** Where: for
> ** Near: start: start + bump
I think that an overflow error! is the right thing to do also with unsigned
byte (char). Because this is exactly what is happening with a char in 'for: it
can't add 1 to 255 without overflow.
I agree: the problem is also how Rebol handles limit values. Orthogonality is
low.
---
Ciao
Romano
[9/23] from: rotenca:telvia:it at: 17-Jun-2002 17:26
To end:
another signed integer which wraps:
x: 2147483646x2147483646 loop 5 [print x: x + 1]
2147483647x2147483647
-2147483648x-2147483648
-2147483647x-2147483647
Joel, i do not understand your for code, is missing something?
if op end start [
until [
start: (old: start) + bump
]
]
---
Ciao
Romano
[10/23] from: joel:neely:fedex at: 17-Jun-2002 11:36
Hi, Romano,
On Monday, June 17, 2002, at 10:26 AM, Romano Paolo Tenca wrote:
> Joel, i do not understand your for code, is missing something?
>
> if op end start [
> until [
> start: (old: start) + bump
> ]
> ]
>
What's missing is the working part of the loop body. I stripped the loop
down to just the "counter" management to see what would happen to the
overhead timing in going to post-test.
I think that a single range test wrapped around the post-test loop is
much
faster than putting another upper-limit test inside a pre-test loop.
-jn-
[11/23] from: joel:neely:fedex at: 17-Jun-2002 12:36
Just a bit more detail... (I'm multitasking furiously this week ;-)
On Monday, June 17, 2002, at 11:36 AM, Joel Neely wrote:
> Hi, Romano,
> On Monday, June 17, 2002, at 10:26 AM, Romano Paolo Tenca wrote:
<<quoted lines omitted: 19>>
> [rebol-request--rebol--com] with "unsubscribe" in the subject, without the
> quotes.
Using the following dinky timing function:
race: func [end [number!] /local op start bump old t0 t1 t2][
op: :greater-or-equal?
bump: 1
start: 1
t0: now/time/precise
while [op end start] [start: start + bump]
t1: now/time/precise - t0
start: 1
t0: now/time/precise
until [
start: (old: start) + bump
op old end
]
t2: now/time/precise - t0
print [t1 t2]
]
which implements the pre- and post-test loops with no actual processing
inside the body, I get
>> race 5000000
0:00:30.222434 0:00:25.854029
which shows that we could pick up about an 11% performance improvement by
having UNTIL rather than WHILE as the working part of FOR as Romano has
suggested. (Notice that I didn't bother to wrap UNTIL in the IF pre-test
since that's a one-shot cost.)
-jn-
[12/23] from: joel:neely:fedex at: 17-Jun-2002 13:51
Hi, again,
On Monday, June 17, 2002, at 09:47 AM, Romano Paolo Tenca wrote:
> It seems to me that the solution is a pre-conditon test and a
> post-condition
<<quoted lines omitted: 7>>
> Orthogonality is
> low.
For a peek at a different (very clean) strategy to handling loops, I
might
suggest a peek at the "iterator" concept in Python 2.2 described at
http://www.amk.ca/python/2.2/
In brief, when you write something resembling (I'll use REBOL-ish
notation
rather than trying to explain Python syntax):
foreachin gleep bletch [...]
the variable GLEEP would iterate across all values offered by the object
BLETCH.
The mechanism, however, is seriously cool and scalable. The object
BLETCH merely has to meet two requirements:
- there must be a /NEXT refinement which is invoked for every pass to
obtain
the next element to use,
- invoking BLETCH/NEXT must result in a StopIteration exception when
there is
no next element.
Since FOREACHIN is simply looking for the StopIteration exception as the
signal
for "there are no more values", an object can do whatever makes sense to
offer
up the next value (or signal completion). This allows the programmer to
create
new objects and still use them with the standard iterative loop
mechanism with
no extra overhead.
Since RANGE (remember that I'm still using REBOL notation) returns a
range
object which already has the required behaviors, and "file" objects also
know
how to behave, one uses
foreachin foo range 1 100 [...]
or
foreachin line %glumpf.data [...]
to do just what you think.
Anyway, the idea of having a standard interface that allows extensions
(or
type-specific scenarios, such as we've been discussing with char!) to
work
consistently with looping seems quite nice.
-jn-
[13/23] from: rotenca:telvia:it at: 17-Jun-2002 22:47
Hi Joel, some notes about this thread (also to clear my looping mind :-):
1) it is strange, but your simulation code is more slow on my system (W98 -
Celeron 333 view 1.2.1.3.1 and beta 1.2.5.3.1) than the standard simulated
'for
>>race 500000
0:00:03.52 0:00:04.01
2) neither your code can check this case:
for i #"^(00)" #"^(01)" 256 []
the code should do an additional test of this type (with positive bump):
if old => old + bump [break]
3) the right solution should be a consistent math overflow error with all
scalar datatype! and not a
pseudo-random [error wrap stop bug]
like it is in the actual implementation (bug is for the time! datatype!) :-)
4) I always think that
for i #"^(00)" #"^(ff)" 1 []
should stop at #"^(ff)", with or without math overflow and with or without
wrap, so 'for should check the end condition at the end of the loop and before
adding the bump value.
5) a while or until loop is the best mode to do what 'for should do, so one
can directly control what happens (and a rebol for loop is always slower than
a rebol while/until loop)
---
Ciao
Romano
[14/23] from: g:santilli:tiscalinet:it at: 17-Jun-2002 23:49
Hi Joel,
On Monday, June 17, 2002, 8:51:19 PM, you wrote:
JN> - there must be a /NEXT refinement which is invoked for every pass to
JN> obtain
JN> the next element to use,
JN> - invoking BLETCH/NEXT must result in a StopIteration exception when
JN> there is
JN> no next element.
Hmm, should be trivial to do in REBOL. I'll do that later, it will
be fun. :)
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r
[15/23] from: joel:neely:fedex at: 18-Jun-2002 7:28
Hi, Romano,
Romano Paolo Tenca wrote:
> 1) it is strange, but your simulation code is more slow on my
> system (W98 - Celeron 333 view 1.2.1.3.1 and beta 1.2.5.3.1)
> than the standard simulated 'for
>
> >>race 500000
>
> 0:00:03.52 0:00:04.01
>
May I suggest
- increasing the argument at least one order of magnitude
- running multiple times
I've seen situations where some transient condition could easily
throw a half-second glitch into a small benchmark. The first
run I made of (an earlier version of) RACE the result favored
the WHILE version over the UNTIL version, but over a large number
of subsequent runs with larger loop counts the UNTIL version was
the consistent winner.
> 2) neither your code can check this case:
>
> for i #"^(00)" #"^(01)" 256 []
>
You're right. Ooops.
> 3) the right solution should be a consistent math overflow error
> with all scalar datatype! and not a
<<quoted lines omitted: 4>>
> for i #"^(00)" #"^(ff)" 1 []
> should stop at #"^(ff)", with or without math overflow and with
I assume you mean "after" instead of "at", that is the #"^(ff)"
should be processed but should be the last value to be processed.
> or without wrap, so 'for should check the end condition at the
> end of the loop and before adding the bump value.
>
I'm beginning to think that the optimal solution to all of the
above would be something like the following:
1) perform type consistency checks and throw an error if bounds
and increment are not suitable
2) calculate the number of values that actually satisfy both the
bounds/increment constraints and the domain constraints of
the bounds types
3) if the number of such values is zero, the range is empty, so
do nothing gracefully and exit
4) if the number of such value is non-zero, set CURRENT to the
lower bound, then...
5) use LOOP (controlled by the number of values calculated in
step 2) to perform the body and then increment CURRENT by the
supplied "bump" argument.
This strategy would push all of the boundary issues into step 2,
eliminating the attempted evaluation of an out-of-bounds value
within the loop, no matter what the types of the data, nor the
handling of edge effects by REBOL.
The added overhead would go into loop setup rather than loop body
and the iteration would actually be performed by LOOP, so for
sufficiently large iteration counts, there should be a net gain
of performance.
-jn-
--
; Joel Neely joeldotneelyatfedexdotcom
REBOL [] do [ do func [s] [ foreach [a b] s [prin b] ] sort/skip
do function [s] [t] [ t: "" foreach [a b] s [repend t [b a]] t ] {
| e s m!zauafBpcvekexEohthjJakwLrngohOqrlryRnsctdtiub} 2 ]
[16/23] from: lmecir:mbox:vol:cz at: 18-Jun-2002 18:22
I think, that FOR contains quite a few other bugs too and its speed is poor.
My observations are:
too aggressive CATCH attribute handling and incorrect series handling
-L
[17/23] from: g:santilli:tiscalinet:it at: 18-Jun-2002 19:37
Hi Joel,
On Monday, June 17, 2002, 8:51:19 PM, you wrote:
JN> foreachin gleep bletch [...]
My QAD solution:
foreachin: func ['word object body /local result] [
if none? object [return none]
body: func reduce [word] body
if not all [in object 'next in object 'current] [make error! "Invalid object"]
until [
set/any 'result body object/current
object/next
]
get/any 'result
]
range: func [start end' bump'] [
if end' - start / bump' < 1 [return none]
context [
current: start
end: end'
bump: bump'
op?: either positive? bump [:greater?] [:lesser?]
next: does [
current: current + bump
op? current end
]
]
]
>> foreachin i range 1 10 1 [print i]
1
2
3
4
5
6
7
8
9
10
>> foreachin i range 10 1 -1 [print i]
10
9
8
7
6
5
4
3
2
1
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r
[18/23] from: g:santilli:tiscalinet:it at: 18-Jun-2002 18:33
Hi Joel,
On Tuesday, June 18, 2002, 2:28:42 PM, you wrote:
JN> 1) perform type consistency checks and throw an error if bounds
JN> and increment are not suitable
JN> 2) calculate the number of values that actually satisfy both the
JN> bounds/increment constraints and the domain constraints of
JN> the bounds types
JN> 3) if the number of such values is zero, the range is empty, so
JN> do nothing gracefully and exit
JN> 4) if the number of such value is non-zero, set CURRENT to the
JN> lower bound, then...
JN> 5) use LOOP (controlled by the number of values calculated in
JN> step 2) to perform the body and then increment CURRENT by the
JN> supplied "bump" argument.
Interesting idea... something like:
for: func [
"Repeats a block over a range of values."
[catch throw]
'word [word!] "Variable to hold current value"
start [number! series! money! time! date! char!] "Starting value"
end [number! series! money! time! date! char!] "Ending value"
bump [number! money! time! char!] "Amount to skip each time"
body [block!] "Block to evaluate"
/local result do-body times
][
if (type? start) <> (type? end) [
throw make error! reduce ['script 'expect-arg 'for 'end type? start]
]
do-body: func reduce [[throw] word] body
op: :greater-or-equal?
either series? start [
if not same? head start head end [
throw make error! reduce ['script 'invalid-arg end]
]
times: 1 + to-integer divide subtract index? end index? start bump
loop times [
set/any 'result do-body start
start: skip start bump
]
] [
times: 1 + to-integer divide subtract end start bump
loop times [
set/any 'result do-body start
start: start + bump
]
]
get/any 'result
]
Do you see any problems with it?
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r
[19/23] from: joel:neely:fedex at: 18-Jun-2002 23:12
Hi, Gabriele,
Gabriele Santilli wrote:
> Hi Joel,
>
> On Monday, June 17, 2002, 8:51:19 PM, you wrote:
>
> JN> foreachin gleep bletch [...]
>
> My QAD solution:
>
> foreachin: func ['word object body /local result] [
> if none? object [return none]
...
until [
set/any 'result body object/current
object/next
]
get/any 'result
> ]
>
> range: func [start end' bump'] [
> if end' - start / bump' < 1 [return none]
> context [
...
> ]
> ]
>
That's a nice first cut, but it assumes that the object passed
to FOREACHIN will be able to deliver at least one value (since
the UNTIL loop doesn't check for failure until after trying to
evaluate the body on CURRENT.
I realize that you handled that for RANGE objects, but the
thing that's nice about the iterator-driven loop in Python is
that ANY object (including one with mutable state/content) can
expose the correct interface to allow FOREACHIN to operate on
it (including the "do nothing gracefully" case).
It's too late for me to play any more with this tonight, but
there are two approaches that immediately come to mind around
this issue:
1) Inside FOREACHIN simply repeatedly apply the body to /NEXT
until /NEXT throws an error. If the error contains a
"Stop Iteration" message, simply return RESULT's value as
the value of FOREACHIN; if the error is any other kind,
then pass it on.
2) Require the object to have two methods /MORE? and /NEXT
where /MORE? indicates whether it is possible to call /NEXT
without failure, and /NEXT returns the next unused value
from the iterator.
Sketching out an example for (2), we could then imagine
foreachin temp series-iterator some-series [...]
where (DANGER, WILL ROBINSON: UNTESTED CODE AHEAD!)
series-iterator: func [s [series!]] [
make object! [
ser: s
more?: func [] [empty? ser]
next: func [/local result] [
result: first ser
ser: next ser
result
]
]
]
as an example of something that could do nothing gracefully.
-jn-
--
; Joel Neely joeldotneelyatfedexdotcom
REBOL [] do [ do func [s] [ foreach [a b] s [prin b] ] sort/skip
do function [s] [t] [ t: "" foreach [a b] s [repend t [b a]] t ] {
| e s m!zauafBpcvekexEohthjJakwLrngohOqrlryRnsctdtiub} 2 ]
[20/23] from: joel:neely:fedex at: 18-Jun-2002 22:49
Hi, Gabriele,
Gabriele Santilli wrote:
> Interesting idea... something like:
>
> for: func [
...
> ][
...
> ]
>
> Do you see any problems with it?
>
There's good news and bad news:
1) A QAD test indicates a big performance win. After renaming
your posted version to NEWFOR, I ran the following (wrapped
for the email):
t0: now/time/precise
for i 1 10000000 1 []
t1: now/time/precise - t0
and got
== 0:01:14.557616
than ran:
t0: now/time/precise
newfor i 1 10000000 1 []
t1: now/time/precise - t0
and got
== 0:00:59.648256
which shows about a 20% reduction in run time.
2) This does, indeed, solve Romano's problem with using FOR to
iterate through char! values, as shown by:
n: 0
newfor i #"^(00)" #"^(ff)" 51 [
n: n + 1
print [n tab to-integer i]
if n > 10 [break]
]
which gives:
1 0
2 51
3 102
4 153
5 204
6 255
== none
versus:
n: 0
for i #"^(00)" #"^(ff)" 51 [
n: n + 1
print [n tab to-integer i]
if n > 10 [break]
]
which exhibits Romano's Syndrome:
1 0
2 51
3 102
4 153
5 204
6 255
7 50
8 101
9 152
10 203
11 254
== none
(Of course the business with N was to compensate for my slow
reaction time on the "Escape" key! ;-)
3) I believe that (with a bit more work) NEWFOR could be extended
to handle tuple! ranges as well. Being able to iterate thru
a collection of IP addresses or skip through color space seems
to be useful.
On the other hand...
1) Integer ranges wider than the maximum integral value break
the computation of iteration count; with the existing FOR:
for i -2147483647 1147483647 1000000000 [print i]
we get behavior as expected:
-2147483647
-1147483647
-147483647
852516353
while with the new version:
newfor i -2147483647 1147483647 1000000000 [print i]
we get a new breakage mode:
** Math Error: Math or number overflow
** Where: newfor
** Near: times: 1 + to-integer divide
I had planned on adding a later note that the iteration
count computation would need to be performed in decimal!
(with suitable protection against round-off error
contaminating the iteration count), due to just this issue,
but I had a class that kept me to busy to remember that
follow-up.
2) There's a bit more work needed in loop unrolling to prevent
edge-of-domain failure:
>> newfor i 2147483637 2147483647 2 [print i]
2147483637
2147483639
2147483641
2147483643
2147483645
2147483647
** Math Error: Math or number overflow
** Where: newfor
** Near: start: start + bump
something along the lines of replacing
times: 1 + to-integer divide subtract end start bump
loop times [
set/any 'result do-body start
start: start + bump
]
with
if 0 < times: i + to-integer (end - start) / bump [
set/any 'result do-body start
loop times - 1 [
start: start + bump
set/any 'result do-body start
]
]
seemed to do the trick:
>> newfor i 2147483637 2147483647 2 [print i]
2147483637
2147483639
2147483641
2147483643
2147483645
2147483647
3) The "bit more work" to address tuple! values would have to
deal with calculating the "width" of a range of tuple values,
and the peculiar behavior of tuple arithmetic (perhaps to
correct it, at least for the purpose of NEWFOR!)
>> baseIP: 255.0.0.0
== 255.0.0.0
>> loop 20 [print baseIP: baseIP + 0.10.20.30]
255.10.20.30
255.20.40.60
255.30.60.90
255.40.80.120
255.50.100.150
255.60.120.180
255.70.140.210
255.80.160.240
255.90.180.255
255.100.200.255
255.110.220.255
255.120.240.255
255.130.255.255
255.140.255.255
255.150.255.255
255.160.255.255
255.170.255.255
255.180.255.255
255.190.255.255
255.200.255.255
However, I think that's a very manageable task.
Thanks for the amazingly quick post!
-jn-
--
; Joel Neely joeldotneelyatfedexdotcom
REBOL [] do [ do func [s] [ foreach [a b] s [prin b] ] sort/skip
do function [s] [t] [ t: "" foreach [a b] s [repend t [b a]] t ] {
| e s m!zauafBpcvekexEohthjJakwLrngohOqrlryRnsctdtiub} 2 ]
[21/23] from: g:santilli:tiscalinet:it at: 19-Jun-2002 12:34
Hi Joel,
On Wednesday, June 19, 2002, 5:49:56 AM, you wrote:
JN> 1) Integer ranges wider than the maximum integral value break
JN> the computation of iteration count; with the existing FOR:
LOOP only accepts integers... OTOH we could nest two LOOPs to have
64bit wide integer ranges. :)
JN> 2) There's a bit more work needed in loop unrolling to prevent
JN> edge-of-domain failure:
Maybe we could add just some error handling...
JN> 3) The "bit more work" to address tuple! values would have to
JN> deal with calculating the "width" of a range of tuple values,
JN> and the peculiar behavior of tuple arithmetic (perhaps to
JN> correct it, at least for the purpose of NEWFOR!)
I'll leave that to the reader as a useful exercise. ;-)
JN> Thanks for the amazingly quick post!
It was easy to do... :)
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r
[22/23] from: g:santilli:tiscalinet:it at: 19-Jun-2002 12:38
Hi Joel,
On Wednesday, June 19, 2002, 6:12:17 AM, you wrote:
JN> That's a nice first cut, but it assumes that the object passed
JN> to FOREACHIN will be able to deliver at least one value (since
JN> the UNTIL loop doesn't check for failure until after trying to
JN> evaluate the body on CURRENT.
Indeed. My first version was using THROW on /NEXT, but I realized
it was probably uselessly complicated, as the issue with "no
iteration at all" can be dealt differently.
JN> 2) Require the object to have two methods /MORE? and /NEXT
JN> where /MORE? indicates whether it is possible to call /NEXT
JN> without failure, and /NEXT returns the next unused value
JN> from the iterator.
I have a third: let the first /NEXT be no-op, and return
immediately true if there's nothing to do. Anyway, your seems the
simplest.
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amigan -- AGI L'Aquila -- REB: http://web.tiscali.it/rebol/index.r
[23/23] from: joel:neely:fedex at: 19-Jun-2002 10:49
Hi, Gabriele,
I had the compression ratio set too high... Sorry!
On Wednesday, June 19, 2002, at 05:34 AM, Gabriele Santilli wrote:
> Hi Joel,
>
> On Wednesday, June 19, 2002, 5:49:56 AM, you wrote:
>
> JN> 1) Integer ranges wider than the maximum integral value break
> JN> the computation of iteration count; with the existing FOR:
>
> LOOP only accepts integers... OTOH we could nest two LOOPs to have
> 64bit wide integer ranges. :)
What I was thinking about was a range with widely-spaced endpoints (wider
than maxint), but also with a large step value, so that the actual number
of loop cycles would be integral, but the intermediate calculation would
break, as in
newfor i -2147483647 1147483647 1000000000 [print i]
** Math Error: Math or number overflow
** Where: newfor
** Near: times: 1 + to-integer divide
Given the desire to get the performance and behavioral improvements, I've
only been able to come up with a "mixed" strategy (something like FOR
already
does for series vs. range iterations) as follows:
- if the number of values in the range is within maxint, then set up for
using LOOP to manage the work,
- if the number of values in range exceeds maxint, but there are no
boundary
problems to address, use a simple WHILE (similar to current FOR),
- if the number of values in range exceeds maxint, and there *are* some
boundary problems to address, use a WHILE with additional error
handling
for bailout.
I'll play "reader" when I get the chance. ;-)
-jn-
Notes
- Quoted lines have been omitted from some messages.
View the message alone to see the lines that have been omitted