Loops/Wrong ranges: Difference between revisions
m (→{{header|REXX}}: added zkl header) |
(→{{header|zkl}}: added zode) |
||
Line 423: | Line 423: | ||
=={{header|zkl}}== |
=={{header|zkl}}== |
||
<lang zkl>// zero increment (ie infnite loop) throws an error |
|||
<lang zkl></lang> |
|||
// if stop is "*", the loop is has no end (ie infinite) |
|||
<lang zkl></lang> |
|||
// stop is included unless step steps skips it |
|||
// if start > stop is a dead loop |
|||
// ranges ([a..b,c]) are lazy lists |
|||
fcn looper([(start,stop,increment)]){ |
|||
print(" %3s %3s\t%2d --> ".fmt(start,stop,increment)); |
|||
if(increment!=0){ foreach n in ([start..stop,increment]){ print(n," ") } } |
|||
println(); |
|||
} |
|||
println("start stop increment"); |
|||
T( T(-2,2,1),T(-2,2,0),T(-2,2,-1),T(-2,2,10),T( 2,-2,1), |
|||
T( 2,2,1),T( 2,2,-1),T( 2,2,0),T( 0,0,0), |
|||
T(0.0, (0.0).pi, 0.7853981633974483), T("a","e",1), T("e","a",1) ) |
|||
.apply2(looper);</lang> |
|||
{{out}} |
{{out}} |
||
<pre> |
<pre> |
||
start stop increment |
|||
-2 2 1 --> -2 -1 0 1 2 |
|||
-2 2 0 --> |
|||
-2 2 -1 --> |
|||
-2 2 10 --> -2 |
|||
2 -2 1 --> |
|||
2 2 1 --> 2 |
|||
2 2 -1 --> 2 |
|||
2 2 0 --> |
|||
0 0 0 --> |
|||
0 3.14159 0 --> 0 0.785398 1.5708 2.35619 3.14159 |
|||
a e 1 --> a b c d e |
|||
e a 1 --> |
|||
</pre> |
</pre> |
Revision as of 17:33, 16 September 2018
Some languages have syntax or function(s) to generate a range of numeric values from a start value, a stop value, and an increment.
The purpose of this task is to select the range syntax/function that would generate at least two increasing numbers when given a stop value more than the start value and a positive increment of less than half the difference. You are than to use that same syntax/function but with different parameters; and show, here, what would happen.
Use these values if possible:
start stop increment Comment -2 2 1 Normal -2 2 0 Zero increment -2 2 -1 Increments away from stop value -2 2 10 First increment is beyond stop value 2 -2 1 Start more than stop: positive increment 2 2 1 Start equal stop: positive increment 2 2 -1 Start equal stop: negative increment 2 2 0 Start equal stop: zero increment 0 0 0 Start equal stop equal zero: zero increment
Go
Go has only one loop, a 'for' statement, which supports four different syntactical forms commonly found in other C-family languages:
1. A C-like 'for' loop with initialization, condition and increment sections.
2. The 'while' loop functionality (condition only)
3. Infinite loop, equivalent to for(;;) (all sections omitted)
4. Looping over a range of values, similar to foreach etc. (using 'range' keyword).
It appears that either #1 or #4 fits the requirements of this task so I've written a function which generates the appropriate sequence using #1 (limited to a maximum of 10 elements as some sequences will be infinite). I've then applied #4 to the resulting sequence. All sequences include the stop value if it's actually reached. <lang go>package main
import "fmt"
type S struct {
start, stop, incr int comment string
}
var examples = []S{
{-2, 2, 1, "Normal"}, {-2, 2, 0, "Zero increment"}, {-2, 2, -1, "Increments away from stop value"}, {-2, 2, 10, "First increment is beyond stop value"}, {2, -2, 1, "Start more than stop: positive increment"}, {2, 2, 1, "Start equal stop: positive increment"}, {2, 2, -1, "Start equal stop: negative increment"}, {2, 2, 0, "Start equal stop: zero increment"}, {0, 0, 0, "Start equal stop equal zero: zero increment"},
}
func sequence(s S, limit int) []int {
var seq []int for i, c := s.start, 0; i <= s.stop && c < limit; i, c = i+s.incr, c+1 { seq = append(seq, i) } return seq
}
func main() {
const limit = 10 for _, ex := range examples { fmt.Println(ex.comment) fmt.Printf("Range(%d, %d, %d) -> ", ex.start, ex.stop, ex.incr) fmt.Println(sequence(ex, limit)) fmt.Println() }
}</lang>
- Output:
Normal Range(-2, 2, 1) -> [-2 -1 0 1 2] Zero increment Range(-2, 2, 0) -> [-2 -2 -2 -2 -2 -2 -2 -2 -2 -2] Increments away from stop value Range(-2, 2, -1) -> [-2 -3 -4 -5 -6 -7 -8 -9 -10 -11] First increment is beyond stop value Range(-2, 2, 10) -> [-2] Start more than stop: positive increment Range(2, -2, 1) -> [] Start equal stop: positive increment Range(2, 2, 1) -> [2] Start equal stop: negative increment Range(2, 2, -1) -> [2 1 0 -1 -2 -3 -4 -5 -6 -7] Start equal stop: zero increment Range(2, 2, 0) -> [2 2 2 2 2 2 2 2 2 2] Start equal stop equal zero: zero increment Range(0, 0, 0) -> [0 0 0 0 0 0 0 0 0 0]
Kotlin
Although Kotlin's 'for' statement can deal with a range of integers, the increment must be positive and so it cannot be used for this task. We therefore use instead a 'while' statement to generate the same sequence as a C language 'for' statement would (limited to a maximum of 10 elements as some sequences will be infinite) and wrap it in a function. <lang scala>// Version 1.2.70
class Example(val start: Int, val stop: Int, val incr: Int, val comment: String)
var examples = listOf(
Example(-2, 2, 1, "Normal"), Example(-2, 2, 0, "Zero increment"), Example(-2, 2, -1, "Increments away from stop value"), Example(-2, 2, 10, "First increment is beyond stop value"), Example(2, -2, 1, "Start more than stop: positive increment"), Example(2, 2, 1, "Start equal stop: positive increment"), Example(2, 2, -1, "Start equal stop: negative increment"), Example(2, 2, 0, "Start equal stop: zero increment"), Example(0, 0, 0, "Start equal stop equal zero: zero increment")
)
fun sequence(ex: Example, limit: Int) =
if (ex.incr == 0) { List(limit) { ex.start } } else { val res = mutableListOf<Int>() var c = 0 var i = ex.start while (i <= ex.stop && c < limit) { res.add(i) i += ex.incr c++ } res }
fun main(args: Array<String>) {
for (ex in examples) { println(ex.comment) System.out.printf("Range(%d, %d, %d) -> ", ex.start, ex.stop, ex.incr) println(sequence(ex, 10)) println() }
}</lang>
- Output:
Normal Range(-2, 2, 1) -> [-2, -1, 0, 1, 2] Zero increment Range(-2, 2, 0) -> [-2, -2, -2, -2, -2, -2, -2, -2, -2, -2] Increments away from stop value Range(-2, 2, -1) -> [-2, -3, -4, -5, -6, -7, -8, -9, -10, -11] First increment is beyond stop value Range(-2, 2, 10) -> [-2] Start more than stop: positive increment Range(2, -2, 1) -> [] Start equal stop: positive increment Range(2, 2, 1) -> [2] Start equal stop: negative increment Range(2, 2, -1) -> [2, 1, 0, -1, -2, -3, -4, -5, -6, -7] Start equal stop: zero increment Range(2, 2, 0) -> [2, 2, 2, 2, 2, 2, 2, 2, 2, 2] Start equal stop equal zero: zero increment Range(0, 0, 0) -> [0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Perl 6
It would be odd to call ANY of these sequences "wrong" in Perl 6. Perl 6 specifically has built in capability of working with infinite sequences. Just because a sequence is infinite, doesn't mean you can't define it, work with it or use values from it. Sure, if you try to reify the whole thing you may be waiting a while, but there is nothing preventing you from using a portion of it.
Perl 6 sequence definitions specifically allow "ending points" that may never occur in the sequence. Since that is the case, you don't even really need to specify a stop value. You can just say stop at "whatever". Whatever is spelled "*" in Perl 6.
There is additional syntax you can add to stop at the nearest value, last value previous or first value successor to the "stop value" (Note I didn't say less than or greater than the stop value since the sequence can be ascending, descending or non-monotonic).
Also note: The iterator function for the sequence is literally a function. It is any expression that produces a value. These sequences all use simple arithmatic increments but that is not a limitation of the sequence operator.
<lang perl6># Given sequence definitions
- start stop inc. Comment
for -2, 2, 1, # Normal
-2, 2, 0, # Zero increment -2, 2, -1, # Increments away from stop value -2, 2, 10, # First increment is beyond stop value 2, -2, 1, # Start more than stop: positive increment 2, 2, 1, # Start equal stop: positive increment 2, 2, 0, # Start equal stop: zero increment 0, 0, 0, # Start equal stop equal zero: zero increment
- Additional "problematic" sequences
1, Inf, 3, # Endpoint literally at infinity 0, π, τ/8, # Floating point numbers 1.4, *, -7.1 # Whatever
-> $start, $stop, $inc { my $seq = flat ($start, *+$inc … $stop); printf "Start: %3s, Stop: %3s, Increment: %3s | ", $start, $stop.Str, $inc; # only show up to the first 15 elements of possibly infinite sequences put $seq[^15].grep: +*.so
}
- For that matter the start and end values don't need to be numeric either. Both
- or either can be a function, list, or other object. Really anything that a
- "successor" function can be defined for and produces a value.
- Start with a list, iterate by multiplying the previous 3 terms together
- and end with a term defined by a function.
put 1, -.5, 2.sqrt, * * * * * … *.abs < 1e-2;
- Start with an array, iterate by rotating, end when 0 is in the last place.
say [0,1,2,3,4,5], *.rotate(-1) … !*.tail;
- Iterate through strings.
put 'a' … 'h';</lang>
- Output:
Start: -2, Stop: 2, Increment: 1 | -2 -1 1 2 Start: -2, Stop: 2, Increment: 0 | -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 -2 Start: -2, Stop: 2, Increment: -1 | -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 Start: -2, Stop: 2, Increment: 10 | -2 8 18 28 38 48 58 68 78 88 98 108 118 128 138 Start: 2, Stop: -2, Increment: 1 | 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 Start: 2, Stop: 2, Increment: 1 | 2 Start: 2, Stop: 2, Increment: 0 | 2 Start: 0, Stop: 0, Increment: 0 | Start: 1, Stop: Inf, Increment: 3 | 1 4 7 10 13 16 19 22 25 28 31 34 37 40 43 Start: 1, Stop: 2, Increment: 0 | 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 Start: 0, Stop: 3.141592653589793, Increment: 0.7853981633974483 | 0.7853981633974483 1.5707963267948966 2.356194490192345 3.141592653589793 Start: 1.4, Stop: *, Increment: -7.1 | 1.4 -5.7 -12.8 -19.9 -27 -34.1 -41.2 -48.3 -55.4 -62.5 -69.6 -76.7 -83.8 -90.9 -98 1 -0.5 1.4142135623730951 -0.7071067811865476 0.5000000000000001 -0.5000000000000002 0.176776695296637 -0.04419417382415928 0.0039062500000000095 ([0 1 2 3 4 5] [5 0 1 2 3 4] [4 5 0 1 2 3] [3 4 5 0 1 2] [2 3 4 5 0 1] [1 2 3 4 5 0]) a b c d e f g h
Python
Python has the range function. <lang python>import re from itertools import islice # To limit execution if it would generate huge values
- list(islice('ABCDEFG', 2)) --> ['A', 'B']
- list(islice('ABCDEFG', 4)) --> ['A', 'B', 'C', 'D']
data =
start stop increment Comment
-2 2 1 Normal
-2 2 0 Zero increment
-2 2 -1 Increments away from stop value
-2 2 10 First increment is beyond stop value
2 -2 1 Start more than stop: positive increment
2 2 1 Start equal stop: positive increment
2 2 -1 Start equal stop: negative increment
2 2 0 Start equal stop: zero increment
0 0 0 Start equal stop equal zero: zero increment
table = [re.split(r'\s\s+', line.strip()) for line in data.strip().split('\n')]
- %%
for _start, _stop, _increment, comment in table[1:]:
start, stop, increment = [int(x) for x in (_start, _stop, _increment)] print(f'{comment.upper()}:\n range({start}, {stop}, {increment})') error, values = None, None try: values = list(islice(range(start, stop, increment), 999)) except ValueError as e: error = e print(' !!ERROR!!', e) if values is not None: if len(values) < 22: print(' =', values) else: print(' =', str(values[:22])[:-1], '...')
</lang>
- Output:
NORMAL: range(-2, 2, 1) = [-2, -1, 0, 1] ZERO INCREMENT: range(-2, 2, 0) !!ERROR!! range() arg 3 must not be zero INCREMENTS AWAY FROM STOP VALUE: range(-2, 2, -1) = [] FIRST INCREMENT IS BEYOND STOP VALUE: range(-2, 2, 10) = [-2] START MORE THAN STOP: POSITIVE INCREMENT: range(2, -2, 1) = [] START EQUAL STOP: POSITIVE INCREMENT: range(2, 2, 1) = [] START EQUAL STOP: NEGATIVE INCREMENT: range(2, 2, -1) = [] START EQUAL STOP: ZERO INCREMENT: range(2, 2, 0) !!ERROR!! range() arg 3 must not be zero START EQUAL STOP EQUAL ZERO: ZERO INCREMENT: range(0, 0, 0) !!ERROR!! range() arg 3 must not be zero
REXX
Note that a do loop with zero by value, or a do loop that goes in the "wrong" direction is not considered an error in REXX as there are other methods of limiting the range (or stopping condition) within the loop body. A special check was made in this REXX version to check for a runaway (race) condition. <lang rexx>/*REXX program demonstrates several versions of DO loops with "unusual" interations. */ @.=; @.1= ' -2 2 1 ' /*"normal". */
@.2= ' -2 2 0 ' /*"normal", zero increment.*/ @.3= ' -2 2 -1 ' /*increases away from stop, neg increment.*/ @.4= ' -2 2 10 ' /*1st increment > stop, positive increment.*/ @.5= ' 2 -2 1 ' /*start > stop, positive increment.*/ @.6= ' 2 2 1 ' /*start equals stop, positive increment.*/ @.7= ' 2 2 -1 ' /*start equals stop, negative increment.*/ @.8= ' 2 2 0 ' /*start equals stop, zero increment.*/ @.9= ' 0 0 0 ' /*start equals stop, zero increment.*/
zLim= 10 /*a limit to check for runaway (race) loop.*/
/*a zero increment is not an error in REXX.*/ do k=1 while @.k\== /*perform a DO loop with several ranges. */ parse var @.k x y z . /*obtain the three values for a DO loop. */ say say center('start of performing DO loop number ' k " with range: " x y z, 79, '═') zz= 0 do j=x to y by z until zz>=zLim /* ◄─── perform the DO loop.*/ say ' j ───►' right(j, max(3, length(j) ) ) /*right justify J for alignment*/ if z==0 then zz= zz + 1 /*if zero inc, count happenings*/ end /*j*/
if zz>=zLim then say 'the DO loop for the ' k " entry was terminated (runaway)." say center(' end of performing DO loop number ' k " with range: " x y z, 79, '─') say end /*k*/ /*stick a fork in it, we're all done. */</lang>
- output:
══════════start of performing DO loop number 1 with range: -2 2 1═══════════ j ───► -2 j ───► -1 j ───► 0 j ───► 1 j ───► 2 ────────── end of performing DO loop number 1 with range: -2 2 1─────────── ══════════start of performing DO loop number 2 with range: -2 2 0═══════════ j ───► -2 j ───► -2 j ───► -2 j ───► -2 j ───► -2 j ───► -2 j ───► -2 j ───► -2 j ───► -2 j ───► -2 the DO loop for the 2 entry was terminated (runaway). ────────── end of performing DO loop number 2 with range: -2 2 0─────────── ══════════start of performing DO loop number 3 with range: -2 2 -1══════════ ────────── end of performing DO loop number 3 with range: -2 2 -1────────── ══════════start of performing DO loop number 4 with range: -2 2 10══════════ j ───► -2 ────────── end of performing DO loop number 4 with range: -2 2 10────────── ══════════start of performing DO loop number 5 with range: 2 -2 1═══════════ ────────── end of performing DO loop number 5 with range: 2 -2 1─────────── ═══════════start of performing DO loop number 6 with range: 2 2 1═══════════ j ───► 2 ─────────── end of performing DO loop number 6 with range: 2 2 1─────────── ══════════start of performing DO loop number 7 with range: 2 2 -1═══════════ j ───► 2 ────────── end of performing DO loop number 7 with range: 2 2 -1─────────── ═══════════start of performing DO loop number 8 with range: 2 2 0═══════════ j ───► 2 j ───► 2 j ───► 2 j ───► 2 j ───► 2 j ───► 2 j ───► 2 j ───► 2 j ───► 2 j ───► 2 the DO loop for the 8 entry was terminated (runaway). ─────────── end of performing DO loop number 8 with range: 2 2 0─────────── ═══════════start of performing DO loop number 9 with range: 0 0 0═══════════ j ───► 0 j ───► 0 j ───► 0 j ───► 0 j ───► 0 j ───► 0 j ───► 0 j ───► 0 j ───► 0 j ───► 0 the DO loop for the 9 entry was terminated (runaway). ─────────── end of performing DO loop number 9 with range: 0 0 0───────────
zkl
<lang zkl>// zero increment (ie infnite loop) throws an error // if stop is "*", the loop is has no end (ie infinite) // stop is included unless step steps skips it // if start > stop is a dead loop // ranges ([a..b,c]) are lazy lists fcn looper([(start,stop,increment)]){
print(" %3s %3s\t%2d --> ".fmt(start,stop,increment)); if(increment!=0){ foreach n in ([start..stop,increment]){ print(n," ") } } println();
} println("start stop increment"); T( T(-2,2,1),T(-2,2,0),T(-2,2,-1),T(-2,2,10),T( 2,-2,1),
T( 2,2,1),T( 2,2,-1),T( 2,2,0),T( 0,0,0), T(0.0, (0.0).pi, 0.7853981633974483), T("a","e",1), T("e","a",1) )
.apply2(looper);</lang>
- Output:
start stop increment -2 2 1 --> -2 -1 0 1 2 -2 2 0 --> -2 2 -1 --> -2 2 10 --> -2 2 -2 1 --> 2 2 1 --> 2 2 2 -1 --> 2 2 2 0 --> 0 0 0 --> 0 3.14159 0 --> 0 0.785398 1.5708 2.35619 3.14159 a e 1 --> a b c d e e a 1 -->