Loops/With multiple ranges: Difference between revisions
Thundergnat (talk | contribs) m →{{header|Perl 6}}: a little exposition |
Thundergnat (talk | contribs) m →{{header|Perl 6}}: clarification |
||
Line 396: | Line 396: | ||
=={{header|Perl 6}}== |
=={{header|Perl 6}}== |
||
This task is really conflating things, (at least in Perl 6). Sequences and loops are two different concepts and may be considered / implemented separately from each other. |
This task is really conflating two separate things, (at least in Perl 6). Sequences and loops are two different concepts and may be considered / implemented separately from each other. |
||
Yes, you can generate a sequence with a loop, and a loop can use a sequence for an iteration value, but the two are somewhat orthogonal and don't necessarily overlap. |
Yes, you can generate a sequence with a loop, and a loop can use a sequence for an iteration value, but the two are somewhat orthogonal and don't necessarily overlap. |
Revision as of 16:49, 17 September 2018
Some languages allow multiple loop ranges, such as the PL/I example (snippet) below.
<lang pli> /* all variables are DECLARED as integers. */
prod= 1; /*start with a product of unity. */ sum= 0; /* " " " sum " zero. */ x= +5; y= -5; z= -2; one= 1; three= 3; seven= 7; /*(below) ** is exponentiation: 4**3=64 */ do j= -three to 3**3 by three , -seven to +seven by x , 555 to 550 - y , 22 to -28 by -three , 1927 to 1939 , x to y by z , 11**x to 11**x + one; /* ABS(n) = absolute value*/ sum= sum + abs(j); /*add absolute value of J.*/ if abs(prod)<2**27 & j¬=0 then prod=prod*j; /*PROD is small enough & J*/ end; /*not 0, then multiply it.*/ /*SUM and PROD are used for verification of J incrementation.*/ display (' sum= ' || sum); /*display strings to term.*/ display ('prod= ' || prod); /* " " " " */</lang>
- Task
Simulate/translate the above PL/I program snippet as best as possible in your language, with particular emphasis on the do loop construct.
The do index must be incremented/decremented in the same order shown.
If feasible, add commas to the two output numbers (being displayed).
Show all output here. <lang> A simple PL/I DO loop (incrementing or decrementing) has the construct of:
DO variable = start_expression {TO ending_expression] {BY increment_expression} ; ---or--- DO variable = start_expression {BY increment_expression} {TO ending_expression] ;
where it is understood that all expressions will have a value. The variable is normally a scaler variable, but need not be (but for this task, all variables and expressions are declared to be scaler integers). If the BY expression is omitted, a BY value of unity is used. All expressions are evaluated before the DO loop is executed, and those values are used throughout the DO loop execution (even though, for instance, the value of Z may be changed within the DO loop. This isn't the case here for this task.
A multiple-range DO loop can be constructed by using a comma (,) to separate additional ranges (the use of multiple TO and/or BY keywords). This is the construct used in this task. There are other forms of DO loops in PL/I involving the WHILE clause, but those won't be needed here. DO loops without a TO clause might need a WHILE clause or some other means of exiting the loop (such as LEAVE, RETURN, SIGNAL, GOTO, or STOP), or some other (possible error) condition that causes transfer of control outside the DO loop. Also, in PL/I, the check if the DO loop index value is outside the range is made at the "head" (start) of the DO loop, so it's possible that the DO loop isn't executed, but that isn't the case for any of the ranges used in this task.
In the example above, the clause: x to y by z will cause the variable J to have to following values (in this order): 5 3 1 -1 -3 -5
In the example above, the clause: -seven to +seven by x will cause the variable J to have to following values (in this order): -7 -2 3 </lang>
- Related tasks
- Loop over multiple arrays simultaneously
- Loops/Break
- Loops/Continue
- Loops/Do-while
- Loops/Downward for
- Loops/For
- Loops/For with a specified step
- Loops/Foreach
- Loops/Increment loop index within loop body
- Loops/Infinite
- Loops/N plus one half
- Loops/Nested
- Loops/While
- Loops/with multiple ranges
- Loops/Wrong ranges
ALGOL W
As with most of the other languages, Algol W doesn't support multiple loop ranges, so a sequence pf loops is used instead. <lang algolw>begin
% translation of task PL/1 code, with minimal changes, semicolons required by % % PL/1 but redundant in Algol W retained ( technically they introduce empty % % statements after the "if" in the loop body and before the final "end" ) % % Note that in Algol W, the loop counter is a local variable to the loop and % % the value of j is not available outside the loops % procedure loopBody ( integer value j ); %(below) ** is exponentiation: 4**3=64 % begin sum := sum + abs(j); %add absolute value of J.% if abs(prod)<2**27 and j not = 0 then prod := prod*j; %PROD is small enough & J% % ABS(n) = absolute value% end; %not 0, then multiply it.% %SUM and PROD are used for verification of J incrementation.% integer prod, sum, x, y, z, one, three, seven; prod := 1; %start with a product of unity. % sum := 0; % " " " sum " zero. % x := +5; y := -5; z := -2; one := 1; three := 3; seven := 7; for j := -three step three until round( 3**3 ) do loopBody( j ); for j := -seven step x until +seven do loopBody( j ); for j := 555 until 550 - y do loopBody( j ); for j := 22 step -three until -28 do loopBody( j ); for j := 1927 until 1939 do loopBody( j ); for j := x step z until y do loopBody( j ); for j := round( 11**x ) until round( 11**x ) + one do loopBody( j ); write(s_w := 0, " sum= ", sum); %display strings to term.% write(s_w := 0, "prod= ", prod); % " " " " %
end.</lang>
- Output:
sum= 348173 prod= -793618560
C
<lang c>#include <stdio.h>
- include <stdlib.h>
- include <locale.h>
long prod = 1L, sum = 0L;
void process(int j) {
sum += abs(j); if (labs(prod) < (1 << 27) && j) prod *= j;
}
long ipow(int n, uint e) {
long pr = n; int i; if (e == 0) return 1L; for (i = 2; i <= e; ++i) pr *= n; return pr;
}
int main() {
int j; const int x = 5, y = -5, z = -2; const int one = 1, three = 3, seven = 7; long p = ipow(11, x); for (j = -three; j <= ipow(3, 3); j += three) process(j); for (j = -seven; j <= seven; j += x) process(j); for (j = 555; j <= 550 - y; ++j) process(j); for (j = 22; j >= -28; j -= three) process(j); for (j = 1927; j <= 1939; ++j) process(j); for (j = x; j >= y; j -= -z) process(j); for (j = p; j <= p + one; ++j) process(j); setlocale(LC_NUMERIC, ""); printf("sum = % 'ld\n", sum); printf("prod = % 'ld\n", prod); return 0;
}</lang>
- Output:
sum = 348,173 prod = -793,618,560
Factor
Factor doesn't have any special support for this sort of thing, but we can store iterable range
objects in a collection and loop over them.
<lang factor>USING: formatting kernel locals math math.functions math.ranges
sequences sequences.generalizations tools.memory.private ;
[let ! Allow lexical variables.
1 :> prod! ! Start with a product of unity. 0 :> sum! ! " " " sum " zero. 5 :> x -5 :> y -2 :> z 1 :> one 3 :> three 7 :> seven
three neg 3 3 ^ three <range> ! Create array seven neg seven x <range> ! of 7 ranges. 555 550 y - [a,b] 22 -28 three neg <range> 1927 1939 [a,b] x y z <range> 11 x ^ 11 x ^ 1 + [a,b] 7 narray
[ [ :> j j abs sum + sum! prod abs 2 27 ^ < j zero? not and [ prod j * prod! ] when ] each ! Loop over range. ] each ! Loop over array of ranges. ! SUM and PROD are used for verification of J incrementation. sum prod [ commas ] bi@ " sum= %s\nprod= %s\n" printf
]</lang>
- Output:
sum= 348,173 prod= -793,618,560
Go
Nothing fancy from Go here (is there ever?), just a series of individual for loops. <lang go>package main
import "fmt"
func pow(n int, e uint) int {
if e == 0 { return 1 } prod := n for i := uint(2); i <= e; i++ { prod *= n } return prod
}
func abs(n int) int {
if n >= 0 { return n } return -n
}
func commatize(n int) string {
s := fmt.Sprintf("%d", n) if n < 0 { s = s[1:] } le := len(s) for i := le - 3; i >= 1; i -= 3 { s = s[0:i] + "," + s[i:] } if n >= 0 { return " " + s } return "-" + s
}
func main() {
prod := 1 sum := 0 const ( x = 5 y = -5 z = -2 one = 1 three = 3 seven = 7 ) p := pow(11, x) var j int
process := func() { sum += abs(j) if abs(prod) < (1<<27) && j != 0 { prod *= j } }
for j = -three; j <= pow(3, 3); j += three { process() } for j = -seven; j <= seven; j += x { process() } for j = 555; j <= 550-y; j++ { process() } for j = 22; j >= -28; j -= three { process() } for j = 1927; j <= 1939; j++ { process() } for j = x; j >= y; j -= -z { process() } for j = p; j <= p+one; j++ { process() } fmt.Println("sum = ", commatize(sum)) fmt.Println("prod = ", commatize(prod))
}</lang>
- Output:
sum = 348,173 prod = -793,618,560
Kotlin
Nothing special here, just a series of individual for loops. <lang scala>// Version 1.2.70
import kotlin.math.abs
infix fun Int.pow(e: Int): Int {
if (e == 0) return 1 var prod = this for (i in 2..e) { prod *= this } return prod
}
fun main(args: Array<String>) {
var prod = 1 var sum = 0 val x = 5 val y = -5 val z = -2 val one = 1 val three = 3 val seven = 7 val p = 11 pow x fun process(j: Int) { sum += abs(j) if (abs(prod) < (1 shl 27) && j != 0) prod *= j }
for (j in -three..(3 pow 3) step three) process(j) for (j in -seven..seven step x) process(j) for (j in 555..550-y) process(j) for (j in 22 downTo -28 step three) process(j) for (j in 1927..1939) process(j) for (j in x downTo y step -z) process(j) for (j in p..p + one) process(j) System.out.printf("sum = % ,d\n", sum) System.out.printf("prod = % ,d\n", prod)
}</lang>
- Output:
sum = 348,173 prod = -793,618,560
Perl
<lang perl>use constant one => 1; use constant three => 3; use constant seven => 7; use constant x => 5; use constant yy => -5; # 'y' conflicts with use as equivalent to 'tr' operator (a carry-over from 'sed') use constant z => -2;
my $prod = 1;
sub from_to_by {
my($begin,$end,$skip) = @_; my $n = 0; grep{ !($n++ % abs $skip) } $begin <= $end ? $begin..$end : reverse $end..$begin;
}
sub commatize {
(my $s = reverse shift) =~ s/(.{3})/$1,/g; $s =~ s/,(-?)$/$1/; $s = reverse $s;
}
for my $j (
from_to_by(-three,3**3,three), from_to_by(-seven,seven,x), 555 .. 550 - yy, from_to_by(22,-28,-three), 1927 .. 1939, from_to_by(x,yy,z), 11**x .. 11**x+one, ) { $sum += abs($j); $prod *= $j if $j and abs($prod) < 2**27;
}
printf "%-8s %12s\n", 'Sum:', commatize $sum; printf "%-8s %12s\n", 'Product:', commatize $prod;</lang>
- Output:
Sum: 348,173 Product: -793,618,560
Perl 6
This task is really conflating two separate things, (at least in Perl 6). Sequences and loops are two different concepts and may be considered / implemented separately from each other.
Yes, you can generate a sequence with a loop, and a loop can use a sequence for an iteration value, but the two are somewhat orthogonal and don't necessarily overlap.
Sequences are first class objects in Perl 6. You can (and typically do) generate a sequence using the (appropriately enough) sequence operator and can assign it to a variable and/or pass it as a parameter; the entire sequence, not just it's individual values. It may be used in a looping construct, but it is not necessary to do so.
Various looping constructs often do use sequences as their iterator but not exclusively, possibly not even in the majority.
Displaying the j sequence as well since it isn't very large.
<lang perl6>sub comma { ($^i < 0 ?? '-' !! ) ~ $i.abs.flip.comb(3).join(',').flip }
my \x = 5; my \y = -5; my \z = -2; my \one = 1; my \three = 3; my \seven = 7;
my $j = flat
( -three, *+three … 3³ ), ( -seven, *+x …^ * > seven ), ( 555 .. 550 - y ), ( 22, *-three …^ * < -28 ), ( 1927 .. 1939 ), ( x, *+z …^ * < y ), ( 11**x .. 11**x + one );
put 'j sequence: ', $j; put ' Sum: ', comma [+] $j».abs; put ' Product: ', comma ([\*] $j.grep: so +*).first: *.abs > 2²⁷;
- Or, an alternate method for generating the 'j' sequence, employing user-defined
- operators to preserve the 'X to Y by Z' layout of the example code.
- Note that these operators will only work for monotonic sequences.
sub infix:<to> { $^a ... $^b } sub infix:<by> { $^a[0, $^b.abs ... *] }
$j = cache flat
-three to 3**3 by three , -seven to seven by x , 555 to (550 - y) , 22 to -28 by -three , 1927 to 1939 by one , x to y by z , 11**x to (11**x + one) ;
put "\nLiteral minded variant:"; put ' Sum: ', comma [+] $j».abs; put ' Product: ', comma ([\*] $j.grep: so +*).first: *.abs > 2²⁷;</lang>
- Output:
j sequence: -3 0 3 6 9 12 15 18 21 24 27 -7 -2 3 555 22 19 16 13 10 7 4 1 -2 -5 -8 -11 -14 -17 -20 -23 -26 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 5 3 1 -1 -3 -5 161051 161052 Sum: 348,173 Product: -793,618,560 Literal minded variant: Sum: 348,173 Product: -793,618,560
REXX
Programming note: the (sympathetic) trailing semicolons (;) after each REXX statement are optional, they are only there to mimic what the PL/I language requires after each statement.
The technique used by this REXX version is to "break up" the various do iterating clauses (ranges) into separate do loops, and have them invoke a subroutine to perform the actual computations. <lang rexx>/*REXX program emulates a multiple─range DO loop (all variables can be any numbers). */
prod= 1; sum= 0; x= +5; y= -5; z= -2; one= 1;
three= 3; seven= 7;
do j= -three to 3**3 by three ; call meat; end; do j= -seven to seven by x ; call meat; end; do j= 555 to 550 - y ; call meat; end; do j= 22 to -28 by -three ; call meat; end; do j= 1927 to 1939 ; call meat; end; do j= x to y by z ; call meat; end; do j= 11**x to 11**x + one ; call meat; end;
say ' sum= ' || commas( sum); /*display SUM with commas. */ say 'prod= ' || commas(prod); /* " PROD " " */ exit; /*stick a fork in it, we're done.*/ /*──────────────────────────────────────────────────────────────────────────────────────*/ commas: procedure; parse arg _; n= _'.9'; #= 123456789; b= verify(n, #, "M")
e= verify(n, #'0', , verify(n, #"0.", 'M') ) - 4 do j=e to b by -3; _= insert(',', _, j); end; return _
/*──────────────────────────────────────────────────────────────────────────────────────*/ meat: sum= sum + abs(j);
if abs(prod)<2**27 & j\==0 then prod= prod * j; return;</lang>
- output when using the same variable values:
sum= 348,173 prod= -793,618,560
zkl
<lang zkl>prod,sum := 1,0; /* start with a product of unity, sum of 0 */ x,y,z := 5, -5, -2; one,three,seven := 1,3,7; foreach j in (Walker.chain([-three..(3).pow(3),three], // do these sequentially
[-seven..seven,x], [555..550 - y], [22..-28,-three], #[start..last,step] [1927..1939], [x..y,z], [(11).pow(x)..(11).pow(x) + one])){ sum+=j.abs(); /* add absolute value of J */ if(prod.abs()<(2).pow(27) and j!=0) prod*=j; /* PROD is small enough & J */
} /* SUM and PROD are used for verification of J incrementation */ println("sum = %,d\nprod = %,d".fmt(sum,prod));</lang>
- Output:
sum = 348,173 prod = -793,618,560